diff --git a/includes/update.inc b/includes/update.inc index 1eb7a1d..2d7b6df 100644 --- a/includes/update.inc +++ b/includes/update.inc @@ -748,6 +748,9 @@ function update_fix_d7_requirements() { // Rename action description to label. db_change_field('actions', 'description', 'label', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0')); + // Include updates of new core modules. + update_fix_new_modules(); + variable_set('update_d7_requirements', TRUE); } @@ -755,6 +758,130 @@ function update_fix_d7_requirements() { } /** + * Prepares system records of new core modules to include their updates. + * + * Only updates of installed modules are ran. New modules in Drupal core do not + * participate in the upgrade and update path, since they are yet unknown to the + * system. + * + * Module updates to execute are only evaluated *once* before the update batch + * is executed. This one-time evaluation also includes the calculation of update + * dependencies. To include updates from new core modules in a major version + * upgrade, their schema_version needs to be changed from SCHEMA_UNINSTALLED to + * 0. + * + * @see update_get_update_list() + * + * Without adjusting schema_version, only module updates that other modules + * depend on would be executed. + * + * Not all modules are required. New modules that are optional should not be + * installed or enabled. Only if another module depends on them. + * + * All new core modules must have a MODULE_schema_7000() implementation of + * hook_schema(), which specifies the initial database schema at the time of + * upgrading. Later updates that are changing the schema still need to be + * executed. + * + * @see update_module_enable() + */ +function update_fix_new_modules() { + // Updates of required modules MUST be executed. + $required_modules = array( + 'field', + 'field_sql_storage', + 'text', + ); + $optional_modules = array( + 'dashboard', + 'field_ui', // system_update_7020() + 'image', + 'list', // system_update_7027() + 'number', // system_update_7027() + 'overlay', + 'rdf', + 'shortcut', + 'toolbar', + ); + // If Taxonomy was installed, new Options module is required. + $query = db_query_range('SELECT 1 FROM {system} WHERE type = :type AND name = :name AND schema_version > :version', 0, 1, array( + ':type' => 'module', + ':name' => 'taxonomy', + ':version' => SCHEMA_UNINSTALLED, + )); + if ($query->fetchField()) { + $required_modules[] = 'options'; // system_update_7027() + } + else { + $optional_modules[] = 'options'; + } + + $schema = array(); + // Collect tables in initial and current schema definitions of new modules. + foreach (array_merge($required_modules, $optional_modules) as $module) { + $function = $module . '_schema_7000'; + if (function_exists($function)) { + $schema += $function(); + } + $function = $module . '_schema'; + if (function_exists($function)) { + $schema += $function(); + } + } + // Rename tables in new schema definitions that already exist. + foreach ($schema as $table => $spec) { + if (db_table_exists($table)) { + db_rename_table($table, '__d6' . $table); + } + } + + // Required modules WILL be installed and MUST be prepared for updates. + // Change their schema_version to 0. + db_update('system') + ->condition('type', 'module') + ->condition('name', $required_modules, 'IN') + ->fields(array('schema_version' => 0)) + ->execute(); + + // Updates of new optional modules .... this is WHACK! + // - if the module (name) previously existed, it needs to changed to uninstalled, so the new optional module is not included in the upgrade. + // - if the module is going to be enabled in a update of another module, it has to be changed to 0. Otherwise, the module's updates wouldn't be included, dependencies not calculated. + // - not only core modules can depend on other core modules that are optional; updates of contributed modules can depend on optional (new) core modules as well. + // + // In fact, the only proper way to solve this is to use update_module_enable() in module updates to enable modules, and to HALT THE BATCH and restart it with the new and current set of enabled modules. + db_update('system') + ->condition('type', 'module') + ->condition('name', $optional_modules, 'IN') + ->fields(array('schema_version' => SCHEMA_UNINSTALLED)) + ->execute(); +} + +function update_module_enable(array $modules) { + foreach ($modules as $module) { + // Check for initial schema and install it. + $function = $module . '_schema_7000'; + if (function_exists($function)) { + $schema = $function(); + foreach ($schema as $table => $spec) { + db_create_table($table, $spec); + } + } + // Change the schema version from SCHEMA_UNINSTALLED to 0, so any module + // updates since the module's inception are executed in a core upgrade. + db_update('system') + ->condition('type', 'module') + ->condition('name', $module) + ->fields(array('schema_version' => 0)) + ->execute(); + + // @todo Manually clear statics and caches... don't invoke hooks... + + module_invoke($module, 'install'); + module_invoke($module, 'enable'); + } +} + +/** * Register the currently installed profile in the system table. * * Install profiles are now treated as modules by Drupal, and have an upgrade diff --git a/modules/field/field.install b/modules/field/field.install index d56eb90..b9e6a5b 100644 --- a/modules/field/field.install +++ b/modules/field/field.install @@ -168,6 +168,168 @@ function field_schema() { } /** + * Implements hook_schema() for update_fix_new_modules(). + */ +function field_schema_7000() { + // Static (meta) tables. + $schema['field_config'] = array( + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'The primary identifier for a field', + ), + 'field_name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'description' => 'The name of this field. Non-deleted field names are unique, but multiple deleted fields can have the same name.', + ), + 'type' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'description' => 'The type of this field.', + ), + 'module' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The module that implements the field type.', + ), + 'active' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Boolean indicating whether the module that implements the field type is enabled.', + ), + 'storage_type' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'description' => 'The storage backend for the field.', + ), + 'storage_module' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The module that implements the storage backend.', + ), + 'storage_active' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Boolean indicating whether the module that implements the storage backend is enabled.', + ), + 'locked' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + 'description' => '@TODO', + ), + 'data' => array( + 'type' => 'blob', + 'size' => 'big', + 'not null' => TRUE, + 'serialize' => TRUE, + 'description' => 'Serialized data containing the field properties that do not warrant a dedicated column.', + ), + 'cardinality' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + 'translatable' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + 'deleted' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('id'), + 'indexes' => array( + 'field_name' => array('field_name'), + // Used by field_read_fields(). + 'active' => array('active'), + 'storage_active' => array('storage_active'), + 'deleted' => array('deleted'), + // Used by field_modules_disabled(). + 'module' => array('module'), + 'storage_module' => array('storage_module'), + // Used by field_associate_fields(). + 'type' => array('type'), + 'storage_type' => array('storage_type'), + ), + ); + $schema['field_config_instance'] = array( + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'The primary identifier for a field instance', + ), + 'field_id' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'The identifier of the field attached by this instance', + ), + 'field_name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '' + ), + 'entity_type' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '' + ), + 'bundle' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'default' => '' + ), + 'data' => array( + 'type' => 'blob', + 'size' => 'big', + 'not null' => TRUE, + 'serialize' => TRUE, + ), + 'deleted' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('id'), + 'indexes' => array( + // Used by field_delete_instance(). + 'field_name_bundle' => array('field_name', 'entity_type', 'bundle'), + // Used by field_read_instances(). + 'deleted' => array('deleted'), + ), + ); + $schema['cache_field'] = drupal_get_schema_unprocessed('system', 'cache'); + + return $schema; +} + +/** * Utility function: create a field by writing directly to the database. * * This function can be used for databases whose schema is at field module diff --git a/modules/system/system.install b/modules/system/system.install index e55c7cf..c5420a6 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -2071,10 +2071,12 @@ function system_update_7018() { /** * Enable field and field_ui modules. + * + * @see update_fix_new_modules() */ function system_update_7020() { $module_list = array('field_sql_storage', 'field', 'field_ui'); - module_enable($module_list, FALSE); + update_module_enable($module_list); } /** @@ -2089,10 +2091,12 @@ function system_update_7021() { /** * Enable field type modules. + * + * @see update_fix_new_modules() */ function system_update_7027() { $module_list = array('text', 'number', 'list', 'options'); - module_enable($module_list, FALSE); + update_module_enable($module_list); } /**