Merge commit '347145b4f1c40409c68af0ad61be15ee5f9d04f2' into al-os
This commit is contained in:
commit
31819a5ee6
|
@ -30,6 +30,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace realm;
|
using namespace realm;
|
||||||
|
using namespace realm::_impl;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Write a byte to a pipe to notify anyone waiting for data on the pipe
|
// Write a byte to a pipe to notify anyone waiting for data on the pipe
|
|
@ -26,6 +26,7 @@
|
||||||
namespace realm {
|
namespace realm {
|
||||||
class Realm;
|
class Realm;
|
||||||
|
|
||||||
|
namespace _impl {
|
||||||
class ExternalCommitHelper {
|
class ExternalCommitHelper {
|
||||||
public:
|
public:
|
||||||
ExternalCommitHelper(Realm* realm);
|
ExternalCommitHelper(Realm* realm);
|
||||||
|
@ -87,6 +88,7 @@ private:
|
||||||
FdHolder m_shutdown_write_fd;
|
FdHolder m_shutdown_write_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace _impl
|
||||||
} // namespace realm
|
} // namespace realm
|
||||||
|
|
||||||
#endif /* REALM_EXTERNAL_COMMIT_HELPER_HPP */
|
#endif /* REALM_EXTERNAL_COMMIT_HELPER_HPP */
|
|
@ -316,6 +316,7 @@ public:
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
|
namespace _impl {
|
||||||
namespace transaction {
|
namespace transaction {
|
||||||
void advance(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) {
|
void advance(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) {
|
||||||
TransactLogHandler(delegate, sg, [&](auto&&... args) {
|
TransactLogHandler(delegate, sg, [&](auto&&... args) {
|
||||||
|
@ -344,4 +345,5 @@ void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace transaction
|
} // namespace transaction
|
||||||
|
} // namespace _impl
|
||||||
} // namespace realm
|
} // namespace realm
|
|
@ -24,6 +24,7 @@ class RealmDelegate;
|
||||||
class SharedGroup;
|
class SharedGroup;
|
||||||
class ClientHistory;
|
class ClientHistory;
|
||||||
|
|
||||||
|
namespace _impl {
|
||||||
namespace transaction {
|
namespace transaction {
|
||||||
// Advance the read transaction version, with change notifications sent to delegate
|
// Advance the read transaction version, with change notifications sent to delegate
|
||||||
// Must not be called from within a write transaction.
|
// Must not be called from within a write transaction.
|
||||||
|
@ -41,6 +42,7 @@ void commit(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate);
|
||||||
// for reverting to the old values sent to delegate
|
// for reverting to the old values sent to delegate
|
||||||
void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate);
|
void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate);
|
||||||
} // namespace transaction
|
} // namespace transaction
|
||||||
|
} // namespace _impl
|
||||||
} // namespace realm
|
} // namespace realm
|
||||||
|
|
||||||
#endif /* REALM_TRANSACT_LOG_HANDLER_HPP */
|
#endif /* REALM_TRANSACT_LOG_HANDLER_HPP */
|
|
@ -149,6 +149,13 @@ static inline bool property_has_changed(Property const& p1, Property const& p2)
|
||||||
|| p1.is_nullable != p2.is_nullable;
|
|| p1.is_nullable != p2.is_nullable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool property_can_be_migrated_to_nullable(const Property& old_property, const Property& new_property) {
|
||||||
|
return old_property.type == new_property.type
|
||||||
|
&& !old_property.is_nullable
|
||||||
|
&& new_property.is_nullable
|
||||||
|
&& new_property.name == old_property.name;
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectStore::verify_schema(Schema const& actual_schema, Schema& target_schema, bool allow_missing_tables) {
|
void ObjectStore::verify_schema(Schema const& actual_schema, Schema& target_schema, bool allow_missing_tables) {
|
||||||
std::vector<ObjectSchemaValidationException> errors;
|
std::vector<ObjectSchemaValidationException> errors;
|
||||||
for (auto &object_schema : target_schema) {
|
for (auto &object_schema : target_schema) {
|
||||||
|
@ -205,6 +212,45 @@ std::vector<ObjectSchemaValidationException> ObjectStore::verify_object_schema(O
|
||||||
return exceptions;
|
return exceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void copy_property_values(const Property& old_property, const Property& new_property, Table& table,
|
||||||
|
T (Table::*getter)(std::size_t, std::size_t) const noexcept,
|
||||||
|
void (Table::*setter)(std::size_t, std::size_t, T)) {
|
||||||
|
size_t old_column = old_property.table_column, new_column = new_property.table_column;
|
||||||
|
size_t count = table.size();
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
(table.*setter)(new_column, i, (table.*getter)(old_column, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_property_values(const Property& source, const Property& destination, Table& table) {
|
||||||
|
switch (destination.type) {
|
||||||
|
case PropertyTypeInt:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_int, &Table::set_int);
|
||||||
|
break;
|
||||||
|
case PropertyTypeBool:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_bool, &Table::set_bool);
|
||||||
|
break;
|
||||||
|
case PropertyTypeFloat:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_float, &Table::set_float);
|
||||||
|
break;
|
||||||
|
case PropertyTypeDouble:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_double, &Table::set_double);
|
||||||
|
break;
|
||||||
|
case PropertyTypeString:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_string, &Table::set_string);
|
||||||
|
break;
|
||||||
|
case PropertyTypeData:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_binary, &Table::set_binary);
|
||||||
|
break;
|
||||||
|
case PropertyTypeDate:
|
||||||
|
copy_property_values(source, destination, table, &Table::get_datetime, &Table::set_datetime);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// set references to tables on targetSchema and create/update any missing or out-of-date tables
|
// set references to tables on targetSchema and create/update any missing or out-of-date tables
|
||||||
// if update existing is true, updates existing tables, otherwise validates existing tables
|
// if update existing is true, updates existing tables, otherwise validates existing tables
|
||||||
// NOTE: must be called from within write transaction
|
// NOTE: must be called from within write transaction
|
||||||
|
@ -230,13 +276,40 @@ bool ObjectStore::create_tables(Group *group, Schema &target_schema, bool update
|
||||||
ObjectSchema current_schema(group, target_object_schema->name);
|
ObjectSchema current_schema(group, target_object_schema->name);
|
||||||
std::vector<Property> &target_props = target_object_schema->properties;
|
std::vector<Property> &target_props = target_object_schema->properties;
|
||||||
|
|
||||||
|
// handle columns changing from required to optional
|
||||||
|
for (auto& current_prop : current_schema.properties) {
|
||||||
|
auto target_prop = target_object_schema->property_for_name(current_prop.name);
|
||||||
|
if (!target_prop || !property_can_be_migrated_to_nullable(current_prop, *target_prop))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
target_prop->table_column = current_prop.table_column;
|
||||||
|
current_prop.table_column = current_prop.table_column + 1;
|
||||||
|
|
||||||
|
table->insert_column(target_prop->table_column, DataType(target_prop->type), target_prop->name, target_prop->is_nullable);
|
||||||
|
copy_property_values(current_prop, *target_prop, *table);
|
||||||
|
table->remove_column(current_prop.table_column);
|
||||||
|
|
||||||
|
current_prop.table_column = target_prop->table_column;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inserted_placeholder_column = false;
|
||||||
|
|
||||||
// remove extra columns
|
// remove extra columns
|
||||||
size_t deleted = 0;
|
size_t deleted = 0;
|
||||||
for (auto& current_prop : current_schema.properties) {
|
for (auto& current_prop : current_schema.properties) {
|
||||||
current_prop.table_column -= deleted;
|
current_prop.table_column -= deleted;
|
||||||
|
|
||||||
auto target_prop = target_object_schema->property_for_name(current_prop.name);
|
auto target_prop = target_object_schema->property_for_name(current_prop.name);
|
||||||
if (!target_prop || property_has_changed(current_prop, *target_prop)) {
|
if (!target_prop || (property_has_changed(current_prop, *target_prop)
|
||||||
|
&& !property_can_be_migrated_to_nullable(current_prop, *target_prop))) {
|
||||||
|
if (deleted == current_schema.properties.size() - 1) {
|
||||||
|
// We're about to remove the last column from the table. Insert a placeholder column to preserve
|
||||||
|
// the number of rows in the table for the addition of new columns below.
|
||||||
|
table->add_column(type_Bool, "placeholder");
|
||||||
|
inserted_placeholder_column = true;
|
||||||
|
}
|
||||||
|
|
||||||
table->remove_column(current_prop.table_column);
|
table->remove_column(current_prop.table_column);
|
||||||
++deleted;
|
++deleted;
|
||||||
current_prop.table_column = npos;
|
current_prop.table_column = npos;
|
||||||
|
@ -273,6 +346,15 @@ bool ObjectStore::create_tables(Group *group, Schema &target_schema, bool update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inserted_placeholder_column) {
|
||||||
|
// We inserted a placeholder due to removing all columns from the table. Remove it, and update the indices
|
||||||
|
// of any columns that we inserted after it.
|
||||||
|
table->remove_column(0);
|
||||||
|
for (auto& target_prop : target_props) {
|
||||||
|
target_prop.table_column--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update table metadata
|
// update table metadata
|
||||||
if (target_object_schema->primary_key.length()) {
|
if (target_object_schema->primary_key.length()) {
|
||||||
// if there is a primary key set, check if it is the same as the old key
|
// if there is a primary key set, check if it is the same as the old key
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
using namespace realm;
|
using namespace realm;
|
||||||
|
using namespace realm::_impl;
|
||||||
|
|
||||||
RealmCache Realm::s_global_cache;
|
RealmCache Realm::s_global_cache;
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,16 @@
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
class ClientHistory;
|
class ClientHistory;
|
||||||
class ExternalCommitHelper;
|
|
||||||
class Realm;
|
class Realm;
|
||||||
class RealmCache;
|
class RealmCache;
|
||||||
class RealmDelegate;
|
class RealmDelegate;
|
||||||
typedef std::shared_ptr<Realm> SharedRealm;
|
typedef std::shared_ptr<Realm> SharedRealm;
|
||||||
typedef std::weak_ptr<Realm> WeakRealm;
|
typedef std::weak_ptr<Realm> WeakRealm;
|
||||||
|
|
||||||
|
namespace _impl {
|
||||||
|
class ExternalCommitHelper;
|
||||||
|
}
|
||||||
|
|
||||||
class Realm : public std::enable_shared_from_this<Realm>
|
class Realm : public std::enable_shared_from_this<Realm>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -115,7 +118,7 @@ namespace realm {
|
||||||
|
|
||||||
Group *m_group = nullptr;
|
Group *m_group = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<ExternalCommitHelper> m_notifier;
|
std::shared_ptr<_impl::ExternalCommitHelper> m_notifier;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<RealmDelegate> m_delegate;
|
std::unique_ptr<RealmDelegate> m_delegate;
|
||||||
|
|
Loading…
Reference in New Issue