Example #1
0
void ObjectStore::create_metadata_tables(Group *group) {
    TableRef table = group->get_or_add_table(c_primaryKeyTableName);
    if (table->get_column_count() == 0) {
        table->add_column(type_String, c_primaryKeyObjectClassColumnName);
        table->add_column(type_String, c_primaryKeyPropertyNameColumnName);
    }

    table = group->get_or_add_table(c_metadataTableName);
    if (table->get_column_count() == 0) {
        table->add_column(type_Int, c_versionColumnName);

        // set initial version
        table->add_empty_row();
        table->set_int(c_versionColumnIndex, c_zeroRowIndex, ObjectStore::NotVersioned);
    }
}
Example #2
0
// 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
// NOTE: must be called from within write transaction
bool ObjectStore::create_tables(Group *group, ObjectStore::Schema &target_schema, bool update_existing) {
    bool changed = false;

    // first pass to create missing tables
    vector<ObjectSchema *> to_update;
    for (auto& object_schema : target_schema) {
        bool created = false;
        ObjectStore::table_for_object_type_create_if_needed(group, object_schema.name, created);

        // we will modify tables for any new objectSchema (table was created) or for all if update_existing is true
        if (update_existing || created) {
            to_update.push_back(&object_schema);
            changed = true;
        }
    }

    // second pass adds/removes columns for out of date tables
    for (auto& target_object_schema : to_update) {
        TableRef table = table_for_object_type(group, target_object_schema->name);
        ObjectSchema current_schema(group, target_object_schema->name);
        vector<Property> &target_props = target_object_schema->properties;

        // add missing columns
        for (auto& target_prop : target_props) {
            auto current_prop = current_schema.property_for_name(target_prop.name);

            // add any new properties (new name or different type)
            if (!current_prop || property_has_changed(*current_prop, target_prop)) {
                switch (target_prop.type) {
                        // for objects and arrays, we have to specify target table
                    case PropertyTypeObject:
                    case PropertyTypeArray: {
                        TableRef link_table = ObjectStore::table_for_object_type(group, target_prop.object_type);
                        target_prop.table_column = table->add_column_link(DataType(target_prop.type), target_prop.name, *link_table);
                        break;
                    }
                    default:
                        target_prop.table_column = table->add_column(DataType(target_prop.type), target_prop.name);
                        break;
                }
                changed = true;
            }
        }

        // remove extra columns
        sort(begin(current_schema.properties), end(current_schema.properties), [](Property &i, Property &j) {
            return j.table_column < i.table_column;
        });
        for (auto& current_prop : current_schema.properties) {
            auto target_prop = target_object_schema->property_for_name(current_prop.name);
            if (!target_prop || property_has_changed(current_prop, *target_prop)) {
                table->remove_column(current_prop.table_column);
                changed = true;
            }
        }

        // update table metadata
        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 (current_schema.primary_key != target_object_schema->primary_key) {
                set_primary_key_for_object(group, target_object_schema->name, target_object_schema->primary_key);
                changed = true;
            }
        }
        else if (current_schema.primary_key.length()) {
            // there is no primary key, so if there was one nil out
            set_primary_key_for_object(group, target_object_schema->name, "");
            changed = true;
        }
    }
    return changed;
}
Example #3
0
// 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
// NOTE: must be called from within write transaction
std::vector<std::pair<std::string, Property>> ObjectStore::create_tables(Group *group, Schema &target_schema, bool update_existing) {
    // properties to delete
    std::vector<std::pair<std::string,Property>> to_delete;

    // first pass to create missing tables
    std::vector<ObjectSchema *> to_update;
    for (auto& object_schema : target_schema) {
        bool created = false;
        ObjectStore::table_for_object_type_create_if_needed(group, object_schema.name, created);

        // we will modify tables for any new objectSchema (table was created) or for all if update_existing is true
        if (update_existing || created) {
            to_update.push_back(&object_schema);
        }
    }

    // second pass adds/removes columns for out of date tables
    for (auto& target_object_schema : to_update) {
        TableRef table = table_for_object_type(group, target_object_schema->name);
        ObjectSchema current_schema(group, target_object_schema->name);
        std::vector<Property> &target_props = target_object_schema->persisted_properties;

        // handle columns changing from required to optional
        for (auto& current_prop : current_schema.persisted_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;
        }

        bool inserted_placeholder_column = false;

        // remove extra columns
        size_t deleted = 0;
        for (auto& current_prop : current_schema.persisted_properties) {
            current_prop.table_column -= deleted;

            auto target_prop = target_object_schema->property_for_name(current_prop.name);
            // mark object name & property pairs for deletion
            if (!target_prop) {
                to_delete.push_back(std::make_pair(current_schema.name, current_prop));
            }
            else if ((property_has_changed(current_prop, *target_prop) &&
                      !property_can_be_migrated_to_nullable(current_prop, *target_prop))) {
                if (deleted == current_schema.persisted_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);
                ++deleted;
                current_prop.table_column = npos;
            }
        }

        // add missing columns
        for (auto& target_prop : target_props) {
            auto current_prop = current_schema.property_for_name(target_prop.name);

            // add any new properties (no old column or old column was removed due to not matching)
            if (!current_prop || current_prop->table_column == npos) {
                switch (target_prop.type) {
                        // for objects and arrays, we have to specify target table
                    case PropertyType::Object:
                    case PropertyType::Array: {
                        TableRef link_table = ObjectStore::table_for_object_type(group, target_prop.object_type);
                        REALM_ASSERT(link_table);
                        target_prop.table_column = table->add_column_link(DataType(target_prop.type), target_prop.name, *link_table);
                        break;
                    }
                    default:
                        target_prop.table_column = table->add_column(DataType(target_prop.type),
                                                                     target_prop.name,
                                                                     target_prop.is_nullable);
                        break;
                }
            }
            else {
                target_prop.table_column = current_prop->table_column;
            }
        }

        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
        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 (current_schema.primary_key != target_object_schema->primary_key) {
                set_primary_key_for_object(group, target_object_schema->name, target_object_schema->primary_key);
            }
        }
        else if (current_schema.primary_key.length()) {
            // there is no primary key, so if there was one nil out
            set_primary_key_for_object(group, target_object_schema->name, "");
        }
    }
    return to_delete;
}
        table->add_column(type_Binary, "data");
        table->add_column(type_Timestamp, "date");

        table->add_column_link(type_Link, "object", *target);
        table->add_column_link(type_LinkList, "array", *target);

        table->add_column(type_Int, "int?", true);
        table->add_column(type_Bool, "bool?", true);
        table->add_column(type_Float, "float?", true);
        table->add_column(type_Double, "double?", true);
        table->add_column(type_String, "string?", true);
        table->add_column(type_Binary, "data?", true);
        table->add_column(type_Timestamp, "date?", true);

        table->add_column(type_Table, "subtable 1");
        size_t col = table->add_column(type_Table, "subtable 2");
        table->get_subdescriptor(col)->add_column(type_Int, "value");

        auto add_list = [](TableRef table, DataType type, StringData name, bool nullable) {
            size_t col = table->add_column(type_Table, name);
            table->get_subdescriptor(col)->add_column(type, ObjectStore::ArrayColumnName, nullptr, nullable);
        };

        add_list(table, type_Int, "int array", false);
        add_list(table, type_Bool, "bool array", false);
        add_list(table, type_Float, "float array", false);
        add_list(table, type_Double, "double array", false);
        add_list(table, type_String, "string array", false);
        add_list(table, type_Binary, "data array", false);
        add_list(table, type_Timestamp, "date array", false);
        add_list(table, type_Int, "int? array", true);