diff --git a/core/includes/update.inc b/core/includes/update.inc index f956605..c628d3f 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -100,34 +100,31 @@ function update_settings_file_requirements() { } /** - * Checks whether the minimum system schema version has been satisfied. - * - * Upgrading from a 7.x site database should block the update process. - * Ensure that the site is running Drupal 8 before proceeding. Not that this - * has to happen AFTER the database bootstraps because of - * drupal_get_installed_schema_version(). + * Returns whether the minimum schema requirement has been satisfied. * * @return array * A requirements info array. */ -function update_migrate_requirements() { +function update_system_schema_requirements() { $requirements = array(); - try { - $system_schema = drupal_get_installed_schema_version('system'); - } - catch (\Exception $e) { - $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField(); + + $system_schema = drupal_get_installed_schema_version('system'); + + $requirements['minimum schema']['title'] = 'Minimum schema version'; + if ($system_schema >= \Drupal::CORE_MINIMUM_SCHEMA_VERSION) { + $requirements['minimum schema'] += array( + 'value' => 'The installed schema version meets the minimum.', + 'description' => 'Schema version: ' . $system_schema, + ); } - if ($system_schema < \Drupal::CORE_MINIMUM_SCHEMA_VERSION) { - $requirements = array( - 'drupal 7 version' => array( - 'title' => 'Drupal 7 version', - 'value' => 'Your site database is from a Drupal 7 or earlier site.', - 'severity' => REQUIREMENT_ERROR, - 'description' => 'Migrate your Drupal 7 installation to a Drupal 8 installation using the Migrate module. Updating directly from Drupal 7 to Drupal 8 is not supported.', - ), + else { + $requirements['minimum schema'] += array( + 'value' => 'The installed schema version does not meet the minimum.', + 'severity' => REQUIREMENT_ERROR, + 'description' => 'Your system schema version is ' . $system_schema . '. Updating directly from a schema version prior to 8000 is not supported. You must migrate your site to Drupal 8 first.', ); } + return $requirements; } @@ -140,15 +137,10 @@ function update_migrate_requirements() { * FALSE. */ function update_check_requirements($skip_warnings = FALSE) { - // Upgrading from a 7.x site database should block the update process. - $requirements = update_migrate_requirements(); - // If the user is not upgrading for a system schema prior to 8.x, gather - // any additional extra requirements. - if (empty($requirements)) { - // Check requirements of all loaded modules. - $requirements = \Drupal::moduleHandler()->invokeAll('requirements', array('update')); - $requirements += update_settings_file_requirements(); - } + // Check requirements of all loaded modules. + $requirements = \Drupal::moduleHandler()->invokeAll('requirements', array('update')); + $requirements += update_system_schema_requirements(); + $requirements += update_settings_file_requirements(); $severity = drupal_requirements_severity($requirements); // If there are errors, always display them. If there are only warnings, skip @@ -189,6 +181,25 @@ function update_prepare_d8_bootstrap() { // Bootstrap to configuration. drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); + // Bootstrap the database. + require_once __DIR__ . '/database.inc'; + + // Updating from a site schema version prior to 8000 should block the update + // process. Ensure that the site is not attempting to update a database + // created in a previous version of Drupal. + try { + $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField(); + } + catch (\Exception $e) { + // The schema_version does not exist in the system table, so continue + // for the moment assuming that this is a Drupal 8 database schema. Another + // check will be made later to verify this is the case. + } + if (isset($system_schema) && $system_schema < \Drupal::CORE_MINIMUM_SCHEMA_VERSION) { + print 'Your system schema version is ' . $system_schema . '. Updating directly from a schema version prior to 8000 is not supported. You must migrate your site to Drupal 8 first.'; + exit; + } + // During the bootstrap to DRUPAL_BOOTSTRAP_PAGE_CACHE, code will try to read // the cache but the cache tables are not compatible yet. Use the Null backend // by default to avoid exceptions. @@ -213,9 +224,6 @@ function update_prepare_d8_bootstrap() { $kernel = new DrupalKernel('update', drupal_classloader(), FALSE); $kernel->boot(); - // Bootstrap the database. - require_once __DIR__ . '/database.inc'; - // module.inc is not yet loaded but there are calls to module_config_sort() // below. require_once __DIR__ . '/module.inc'; diff --git a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php index 4158cea..ef2f136 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php @@ -41,6 +41,28 @@ function setUp() { } /** + * Tests that updates from schema versions prior to 8000 are prevented. + */ + function testInvalidMigration() { + // Mock a D7 system table so that the schema value of the system module + // can be retrieved. + db_create_table('system', $this->getSystemSchema()); + // Assert that the table exists. + $this->assertTrue(db_table_exists('system'), 'The table exists.'); + // Insert a value for the system module. + db_insert('system') + ->fields(array( + 'name' => 'system', + 'schema_version' => 7000, + )) + ->execute(); + $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(':system' => 'system'))->fetchField(); + $this->drupalGet($this->update_url, array('external' => TRUE)); + $text = 'Your system schema version is ' . $system_schema . '. Updating directly from a schema version prior to 8000 is not supported. You must migrate your site to Drupal 8 first.'; + $this->assertRaw($text, 'Updates from schema versions prior to 8000 are prevented.'); + } + + /** * Tests access to the update script. */ function testUpdateAccess() { @@ -218,4 +240,78 @@ function testSuccessfulUpdateFunctionality() { $this->clickLink('Administration pages'); $this->assertResponse(200); } + + /** + * Returns the Drupal 7 system table schema. + */ + public function getSystemSchema() { + return array( + 'description' => "A list of all modules, themes, and theme engines that are or have been installed in Drupal's file system.", + 'fields' => array( + 'filename' => array( + 'description' => 'The path of the primary file for this item, relative to the Drupal root; e.g. modules/node/node.module.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'name' => array( + 'description' => 'The name of the item; e.g. node.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'type' => array( + 'description' => 'The type of the item, either module, theme, or theme_engine.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + 'default' => '', + ), + 'owner' => array( + 'description' => "A theme's 'parent' . Can be either a theme or an engine.", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'status' => array( + 'description' => 'Boolean indicating whether or not this item is enabled.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'bootstrap' => array( + 'description' => "Boolean indicating whether this module is loaded during Drupal's early bootstrapping phase (e.g. even before the page cache is consulted).", + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'schema_version' => array( + 'description' => "The module's database schema version number. -1 if the module is not installed (its tables do not exist); 0 or the largest N of the module's hook_update_N() function that has either been run or existed when the module was first installed.", + 'type' => 'int', + 'not null' => TRUE, + 'default' => -1, + 'size' => 'small', + ), + 'weight' => array( + 'description' => "The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name.", + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'info' => array( + 'description' => "A serialized array containing information from the module's .info file; keys can include name, description, package, version, core, dependencies, and php.", + 'type' => 'blob', + 'not null' => FALSE, + ), + ), + 'primary key' => array('filename'), + 'indexes' => array( + 'system_list' => array('status', 'bootstrap', 'type', 'weight', 'name'), + 'type_name' => array('type', 'name'), + ), + ); + } }