cms/drupal/includes/update.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * Drupal database update API.
       
     6  *
       
     7  * This file contains functions to perform database updates for a Drupal
       
     8  * installation. It is included and used extensively by update.php.
       
     9  */
       
    10 
       
    11 /**
       
    12  * Minimum schema version of Drupal 6 required for upgrade to Drupal 7.
       
    13  *
       
    14  * Upgrades from Drupal 6 to Drupal 7 require that Drupal 6 be running
       
    15  * the most recent version, or the upgrade could fail. We can't easily
       
    16  * check the Drupal 6 version once the update process has begun, so instead
       
    17  * we check the schema version of system.module in the system table.
       
    18  */
       
    19 define('REQUIRED_D6_SCHEMA_VERSION', '6055');
       
    20 
       
    21 /**
       
    22  * Disable any items in the {system} table that are not core compatible.
       
    23  */
       
    24 function update_fix_compatibility() {
       
    25   $incompatible = array();
       
    26   $result = db_query("SELECT name, type, status FROM {system} WHERE status = 1 AND type IN ('module','theme')");
       
    27   foreach ($result as $row) {
       
    28     if (update_check_incompatibility($row->name, $row->type)) {
       
    29       $incompatible[] = $row->name;
       
    30     }
       
    31   }
       
    32   if (!empty($incompatible)) {
       
    33     db_update('system')
       
    34       ->fields(array('status' => 0))
       
    35       ->condition('name', $incompatible, 'IN')
       
    36       ->execute();
       
    37   }
       
    38 }
       
    39 
       
    40 /**
       
    41  * Tests the compatibility of a module or theme.
       
    42  */
       
    43 function update_check_incompatibility($name, $type = 'module') {
       
    44   static $themes, $modules;
       
    45 
       
    46   // Store values of expensive functions for future use.
       
    47   if (empty($themes) || empty($modules)) {
       
    48     // We need to do a full rebuild here to make sure the database reflects any
       
    49     // code changes that were made in the filesystem before the update script
       
    50     // was initiated.
       
    51     $themes = system_rebuild_theme_data();
       
    52     $modules = system_rebuild_module_data();
       
    53   }
       
    54 
       
    55   if ($type == 'module' && isset($modules[$name])) {
       
    56     $file = $modules[$name];
       
    57   }
       
    58   elseif ($type == 'theme' && isset($themes[$name])) {
       
    59     $file = $themes[$name];
       
    60   }
       
    61   if (!isset($file)
       
    62       || !isset($file->info['core'])
       
    63       || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY
       
    64       || version_compare(phpversion(), $file->info['php']) < 0) {
       
    65     return TRUE;
       
    66   }
       
    67   return FALSE;
       
    68 }
       
    69 
       
    70 /**
       
    71  * Performs extra steps required to bootstrap when using a Drupal 6 database.
       
    72  *
       
    73  * Users who still have a Drupal 6 database (and are in the process of
       
    74  * updating to Drupal 7) need extra help before a full bootstrap can be
       
    75  * achieved. This function does the necessary preliminary work that allows
       
    76  * the bootstrap to be successful.
       
    77  *
       
    78  * No access check has been performed when this function is called, so no
       
    79  * irreversible changes to the database are made here.
       
    80  */
       
    81 function update_prepare_d7_bootstrap() {
       
    82   // Allow the bootstrap to proceed even if a Drupal 6 settings.php file is
       
    83   // still being used.
       
    84   include_once DRUPAL_ROOT . '/includes/install.inc';
       
    85   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
       
    86   global $databases, $db_url, $db_prefix, $update_rewrite_settings;
       
    87   if (empty($databases) && !empty($db_url)) {
       
    88     $databases = update_parse_db_url($db_url, $db_prefix);
       
    89     // Record the fact that the settings.php file will need to be rewritten.
       
    90     $update_rewrite_settings = TRUE;
       
    91     $settings_file = conf_path() . '/settings.php';
       
    92     $writable = drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_WRITABLE);
       
    93     $requirements = array(
       
    94       'settings file' => array(
       
    95         'title' => 'Settings file',
       
    96         'value' => $writable ? 'The settings file is writable.' : 'The settings file is not writable.',
       
    97         'severity' => $writable ? REQUIREMENT_OK : REQUIREMENT_ERROR,
       
    98         'description' => $writable ? '' : 'Drupal requires write permissions to <em>' . $settings_file . '</em> during the update process. If you are unsure how to grant file permissions, consult the <a href="http://drupal.org/server-permissions">online handbook</a>.',
       
    99       ),
       
   100     );
       
   101     update_extra_requirements($requirements);
       
   102   }
       
   103 
       
   104   // The new {blocked_ips} table is used in Drupal 7 to store a list of
       
   105   // banned IP addresses. If this table doesn't exist then we are still
       
   106   // running on a Drupal 6 database, so we suppress the unavoidable errors
       
   107   // that occur by creating a static list.
       
   108   $GLOBALS['conf']['blocked_ips'] = array();
       
   109 
       
   110   // Check that PDO is available and that the correct PDO database driver is
       
   111   // loaded. Bootstrapping to DRUPAL_BOOTSTRAP_DATABASE will result in a fatal
       
   112   // error otherwise.
       
   113   $message = '';
       
   114   $pdo_link = 'http://drupal.org/requirements/pdo';
       
   115   // Check that PDO is loaded.
       
   116   if (!extension_loaded('pdo')) {
       
   117     $message = '<h2>PDO is required!</h2><p>Drupal 7 requires PHP ' . DRUPAL_MINIMUM_PHP . ' or higher with the PHP Data Objects (PDO) extension enabled.</p>';
       
   118   }
       
   119   // The PDO::ATTR_DEFAULT_FETCH_MODE constant is not available in the PECL
       
   120   // version of PDO.
       
   121   elseif (!defined('PDO::ATTR_DEFAULT_FETCH_MODE')) {
       
   122     $message = '<h2>The wrong version of PDO is installed!</h2><p>Drupal 7 requires the PHP Data Objects (PDO) extension from PHP core to be enabled. This system has the older PECL version installed.';
       
   123     $pdo_link = 'http://drupal.org/requirements/pdo#pecl';
       
   124   }
       
   125   // Check that the correct driver is loaded for the database being updated.
       
   126   // If we have no driver information (for example, if someone tried to create
       
   127   // the Drupal 7 $databases array themselves but did not do it correctly),
       
   128   // this message will be confusing, so do not perform the check; instead, just
       
   129   // let the database connection fail in the code that follows.
       
   130   elseif (isset($databases['default']['default']['driver']) && !in_array($databases['default']['default']['driver'], PDO::getAvailableDrivers())) {
       
   131     $message = '<h2>A PDO database driver is required!</h2><p>You need to enable the PDO_' . strtoupper($databases['default']['default']['driver']) . ' database driver for PHP ' . DRUPAL_MINIMUM_PHP . ' or higher so that Drupal 7 can access the database.</p>';
       
   132   }
       
   133   if ($message) {
       
   134     print $message . '<p>See the <a href="' . $pdo_link . '">system requirements page</a> for more information.</p>';
       
   135     exit();
       
   136   }
       
   137 
       
   138   // Allow the database system to work even if the registry has not been
       
   139   // created yet.
       
   140   drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
       
   141 
       
   142   // If the site has not updated to Drupal 7 yet, check to make sure that it is
       
   143   // running an up-to-date version of Drupal 6 before proceeding. Note this has
       
   144   // to happen AFTER the database bootstraps because of
       
   145   // drupal_get_installed_schema_version().
       
   146   $system_schema = drupal_get_installed_schema_version('system');
       
   147   if ($system_schema < 7000) {
       
   148     $has_required_schema = $system_schema >= REQUIRED_D6_SCHEMA_VERSION;
       
   149     $requirements = array(
       
   150       'drupal 6 version' => array(
       
   151         'title' => 'Drupal 6 version',
       
   152         'value' => $has_required_schema ? 'You are running a current version of Drupal 6.' : 'You are not running a current version of Drupal 6',
       
   153         'severity' => $has_required_schema ? REQUIREMENT_OK : REQUIREMENT_ERROR,
       
   154         'description' => $has_required_schema ? '' : 'Please update your Drupal 6 installation to the most recent version before attempting to upgrade to Drupal 7',
       
   155       ),
       
   156     );
       
   157 
       
   158     // Make sure that the database environment is properly set up.
       
   159     try {
       
   160       db_run_tasks(db_driver());
       
   161     }
       
   162     catch (DatabaseTaskException $e) {
       
   163       $requirements['database tasks'] = array(
       
   164         'title' => 'Database environment',
       
   165         'value' => 'There is a problem with your database environment',
       
   166         'severity' => REQUIREMENT_ERROR,
       
   167         'description' => $e->getMessage(),
       
   168       );
       
   169     }
       
   170 
       
   171     update_extra_requirements($requirements);
       
   172 
       
   173     // Allow a D6 session to work, since the upgrade has not been performed yet.
       
   174     $d6_session_name = update_get_d6_session_name();
       
   175     if (!empty($_COOKIE[$d6_session_name])) {
       
   176       // Set the current sid to the one found in the D6 cookie.
       
   177       $sid = $_COOKIE[$d6_session_name];
       
   178       $_COOKIE[session_name()] = $sid;
       
   179       session_id($sid);
       
   180     }
       
   181 
       
   182     // Upgrading from D6 to D7.{0,1,2,3,4,8,...} is different than upgrading
       
   183     // from D6 to D7.{5,6,7} which should be considered broken. To be able to
       
   184     // properly handle this difference in node_update_7012 we need to keep track
       
   185     // of whether a D6 > D7 upgrade or a D7 > D7 update is running.
       
   186     // Since variable_set() is not available here, the D6 status is being saved
       
   187     // in a local variable to be able to store it later.
       
   188     $update_d6 = TRUE;
       
   189   }
       
   190 
       
   191   // Create the registry tables.
       
   192   if (!db_table_exists('registry')) {
       
   193     $schema['registry'] = array(
       
   194       'fields' => array(
       
   195         'name'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       
   196         'type'   => array('type' => 'varchar', 'length' => 9, 'not null' => TRUE, 'default' => ''),
       
   197         'filename'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       
   198         'module'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       
   199         'weight'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       
   200       ),
       
   201       'primary key' => array('name', 'type'),
       
   202       'indexes' => array(
       
   203         'hook' => array('type', 'weight', 'module'),
       
   204       ),
       
   205     );
       
   206     db_create_table('registry', $schema['registry']);
       
   207   }
       
   208   if (!db_table_exists('registry_file')) {
       
   209     $schema['registry_file'] = array(
       
   210       'fields' => array(
       
   211         'filename'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE),
       
   212         'hash'   => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE),
       
   213       ),
       
   214       'primary key' => array('filename'),
       
   215     );
       
   216     db_create_table('registry_file', $schema['registry_file']);
       
   217   }
       
   218 
       
   219   // Older versions of Drupal 6 do not include the semaphore table, which is
       
   220   // required to bootstrap, so we add it now so that we can bootstrap and
       
   221   // provide a reasonable error message.
       
   222   if (!db_table_exists('semaphore')) {
       
   223     $semaphore = array(
       
   224       'description' => 'Table for holding semaphores, locks, flags, etc. that cannot be stored as Drupal variables since they must not be cached.',
       
   225       'fields' => array(
       
   226         'name' => array(
       
   227           'description' => 'Primary Key: Unique name.',
       
   228           'type' => 'varchar',
       
   229           'length' => 255,
       
   230           'not null' => TRUE,
       
   231           'default' => ''
       
   232         ),
       
   233         'value' => array(
       
   234           'description' => 'A value for the semaphore.',
       
   235           'type' => 'varchar',
       
   236           'length' => 255,
       
   237           'not null' => TRUE,
       
   238           'default' => ''
       
   239         ),
       
   240         'expire' => array(
       
   241           'description' => 'A Unix timestamp with microseconds indicating when the semaphore should expire.',
       
   242           'type' => 'float',
       
   243           'size' => 'big',
       
   244           'not null' => TRUE
       
   245         ),
       
   246       ),
       
   247       'indexes' => array(
       
   248         'value' => array('value'),
       
   249         'expire' => array('expire'),
       
   250       ),
       
   251       'primary key' => array('name'),
       
   252     );
       
   253     db_create_table('semaphore', $semaphore);
       
   254   }
       
   255 
       
   256   // The new cache_bootstrap bin is required to bootstrap to
       
   257   // DRUPAL_BOOTSTRAP_SESSION, so create it here rather than in
       
   258   // update_fix_d7_requirements().
       
   259   if (!db_table_exists('cache_bootstrap')) {
       
   260     $cache_bootstrap = array(
       
   261       'description' => 'Cache table for data required to bootstrap Drupal, may be routed to a shared memory cache.',
       
   262       'fields' => array(
       
   263         'cid' => array(
       
   264           'description' => 'Primary Key: Unique cache ID.',
       
   265           'type' => 'varchar',
       
   266           'length' => 255,
       
   267           'not null' => TRUE,
       
   268           'default' => '',
       
   269         ),
       
   270         'data' => array(
       
   271           'description' => 'A collection of data to cache.',
       
   272           'type' => 'blob',
       
   273           'not null' => FALSE,
       
   274           'size' => 'big',
       
   275         ),
       
   276         'expire' => array(
       
   277           'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
       
   278           'type' => 'int',
       
   279           'not null' => TRUE,
       
   280           'default' => 0,
       
   281         ),
       
   282         'created' => array(
       
   283           'description' => 'A Unix timestamp indicating when the cache entry was created.',
       
   284           'type' => 'int',
       
   285           'not null' => TRUE,
       
   286           'default' => 0,
       
   287         ),
       
   288         'serialized' => array(
       
   289           'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
       
   290           'type' => 'int',
       
   291           'size' => 'small',
       
   292           'not null' => TRUE,
       
   293           'default' => 0,
       
   294         ),
       
   295       ),
       
   296       'indexes' => array(
       
   297         'expire' => array('expire'),
       
   298       ),
       
   299       'primary key' => array('cid'),
       
   300     );
       
   301     db_create_table('cache_bootstrap', $cache_bootstrap);
       
   302   }
       
   303 
       
   304   // Set a valid timezone for 6 -> 7 upgrade process.
       
   305   drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
       
   306   $timezone_offset = variable_get('date_default_timezone', 0);
       
   307   if (is_numeric($timezone_offset)) {
       
   308     // Save the original offset.
       
   309     variable_set('date_temporary_timezone', $timezone_offset);
       
   310     // Set the timezone for this request only.
       
   311     $GLOBALS['conf']['date_default_timezone'] = 'UTC';
       
   312   }
       
   313 
       
   314   // This allows update functions to tell if an upgrade from D6 is running.
       
   315   if (!empty($update_d6)) {
       
   316     variable_set('update_d6', TRUE);
       
   317   }
       
   318 }
       
   319 
       
   320 /**
       
   321  * A helper function that modules can use to assist with the transformation
       
   322  * from numeric block deltas to string block deltas during the 6.x -> 7.x
       
   323  * upgrade.
       
   324  *
       
   325  * @todo This function should be removed in 8.x.
       
   326  *
       
   327  * @param $sandbox
       
   328  *   An array holding data for the batch process.
       
   329  * @param $renamed_deltas
       
   330  *   An associative array.  Keys are module names, values an associative array
       
   331  *   mapping the old block deltas to the new block deltas for the module.
       
   332  *   Example:
       
   333  *   @code
       
   334  *     $renamed_deltas = array(
       
   335  *       'mymodule' =>
       
   336  *         array(
       
   337  *           0 => 'mymodule-block-1',
       
   338  *           1 => 'mymodule-block-2',
       
   339  *         ),
       
   340  *     );
       
   341  *   @endcode
       
   342  * @param $moved_deltas
       
   343  *   An associative array. Keys are source module names, values an associative
       
   344  *   array mapping the (possibly renamed) block name to the new module name.
       
   345  *   Example:
       
   346  *   @code
       
   347  *     $moved_deltas = array(
       
   348  *       'user' =>
       
   349  *         array(
       
   350  *           'navigation' => 'system',
       
   351  *         ),
       
   352  *     );
       
   353  *   @endcode
       
   354  */
       
   355 function update_fix_d7_block_deltas(&$sandbox, $renamed_deltas, $moved_deltas) {
       
   356   // Loop through each block and make changes to the block tables.
       
   357   // Only run this the first time through the batch update.
       
   358   if (!isset($sandbox['progress'])) {
       
   359     // Determine whether to use the old or new block table names.
       
   360     $block_tables = db_table_exists('blocks') ? array('blocks', 'blocks_roles') : array('block', 'block_role');
       
   361     foreach ($block_tables as $table) {
       
   362       foreach ($renamed_deltas as $module => $deltas) {
       
   363         foreach ($deltas as $old_delta => $new_delta) {
       
   364           // Only do the update if the old block actually exists.
       
   365           $block_exists = db_query("SELECT COUNT(*) FROM {" . $table . "} WHERE module = :module AND delta = :delta", array(
       
   366               ':module' => $module,
       
   367               ':delta' => $old_delta,
       
   368             ))
       
   369             ->fetchField();
       
   370           if ($block_exists) {
       
   371             // Delete any existing blocks with the new module+delta.
       
   372             db_delete($table)
       
   373               ->condition('module', $module)
       
   374               ->condition('delta', $new_delta)
       
   375               ->execute();
       
   376             // Rename the old block to the new module+delta.
       
   377             db_update($table)
       
   378               ->fields(array('delta' => $new_delta))
       
   379               ->condition('module', $module)
       
   380               ->condition('delta', $old_delta)
       
   381               ->execute();
       
   382           }
       
   383         }
       
   384       }
       
   385       foreach ($moved_deltas as $old_module => $deltas) {
       
   386         foreach ($deltas as $delta => $new_module) {
       
   387           // Only do the update if the old block actually exists.
       
   388           $block_exists = db_query("SELECT COUNT(*) FROM {" . $table . "} WHERE module = :module AND delta = :delta", array(
       
   389               ':module' => $old_module,
       
   390               ':delta' => $delta,
       
   391             ))
       
   392             ->fetchField();
       
   393           if ($block_exists) {
       
   394             // Delete any existing blocks with the new module+delta.
       
   395             db_delete($table)
       
   396               ->condition('module', $new_module)
       
   397               ->condition('delta', $delta)
       
   398               ->execute();
       
   399             // Rename the old block to the new module+delta.
       
   400             db_update($table)
       
   401               ->fields(array('module' => $new_module))
       
   402               ->condition('module', $old_module)
       
   403               ->condition('delta', $delta)
       
   404               ->execute();
       
   405           }
       
   406         }
       
   407       }
       
   408     }
       
   409 
       
   410     // Initialize batch update information.
       
   411     $sandbox['progress'] = 0;
       
   412     $sandbox['last_user_processed'] = -1;
       
   413     $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE data LIKE :block", array(
       
   414         ':block' => '%' . db_like(serialize('block')) . '%',
       
   415       ))
       
   416       ->fetchField();
       
   417   }
       
   418   // Now do the batch update of the user-specific block visibility settings.
       
   419   $limit = 100;
       
   420   $result = db_select('users', 'u')
       
   421     ->fields('u', array('uid', 'data'))
       
   422     ->condition('uid', $sandbox['last_user_processed'], '>')
       
   423     ->condition('data', '%' . db_like(serialize('block')) . '%', 'LIKE')
       
   424     ->orderBy('uid', 'ASC')
       
   425     ->range(0, $limit)
       
   426     ->execute();
       
   427   foreach ($result as $row) {
       
   428     $data = unserialize($row->data);
       
   429     $user_needs_update = FALSE;
       
   430     foreach ($renamed_deltas as $module => $deltas) {
       
   431       foreach ($deltas as $old_delta => $new_delta) {
       
   432         if (isset($data['block'][$module][$old_delta])) {
       
   433           // Transfer the old block visibility settings to the newly-renamed
       
   434           // block, and mark this user for a database update.
       
   435           $data['block'][$module][$new_delta] = $data['block'][$module][$old_delta];
       
   436           unset($data['block'][$module][$old_delta]);
       
   437           $user_needs_update = TRUE;
       
   438         }
       
   439       }
       
   440     }
       
   441     foreach ($moved_deltas as $old_module => $deltas) {
       
   442       foreach ($deltas as $delta => $new_module) {
       
   443         if (isset($data['block'][$old_module][$delta])) {
       
   444           // Transfer the old block visibility settings to the moved
       
   445           // block, and mark this user for a database update.
       
   446           $data['block'][$new_module][$delta] = $data['block'][$old_module][$delta];
       
   447           unset($data['block'][$old_module][$delta]);
       
   448           $user_needs_update = TRUE;
       
   449         }
       
   450       }
       
   451     }
       
   452     // Update the current user.
       
   453     if ($user_needs_update) {
       
   454       db_update('users')
       
   455         ->fields(array('data' => serialize($data)))
       
   456         ->condition('uid', $row->uid)
       
   457         ->execute();
       
   458     }
       
   459     // Update our progress information for the batch update.
       
   460     $sandbox['progress']++;
       
   461     $sandbox['last_user_processed'] = $row->uid;
       
   462   }
       
   463   // Indicate our current progress to the batch update system.
       
   464   if ($sandbox['progress'] < $sandbox['max']) {
       
   465     $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
       
   466   }
       
   467 }
       
   468 
       
   469 /**
       
   470  * Perform Drupal 6.x to 7.x updates that are required for update.php
       
   471  * to function properly.
       
   472  *
       
   473  * This function runs when update.php is run the first time for 7.x,
       
   474  * even before updates are selected or performed. It is important
       
   475  * that if updates are not ultimately performed that no changes are
       
   476  * made which make it impossible to continue using the prior version.
       
   477  */
       
   478 function update_fix_d7_requirements() {
       
   479   global $conf;
       
   480 
       
   481   // Rewrite the settings.php file if necessary, see
       
   482   // update_prepare_d7_bootstrap().
       
   483   global $update_rewrite_settings, $db_url, $db_prefix;
       
   484   if (!empty($update_rewrite_settings)) {
       
   485     $databases = update_parse_db_url($db_url, $db_prefix);
       
   486     $salt = drupal_hash_base64(drupal_random_bytes(55));
       
   487     file_put_contents(conf_path() . '/settings.php', "\n" . '$databases = ' . var_export($databases, TRUE) . ";\n\$drupal_hash_salt = '$salt';", FILE_APPEND);
       
   488   }
       
   489   if (drupal_get_installed_schema_version('system') < 7000 && !variable_get('update_d7_requirements', FALSE)) {
       
   490     // Change 6.x system table field values to 7.x equivalent.
       
   491     // Change field values.
       
   492     db_change_field('system', 'schema_version', 'schema_version', array(
       
   493      'type' => 'int',
       
   494      'size' => 'small',
       
   495      'not null' => TRUE,
       
   496      'default' => -1)
       
   497     );
       
   498     db_change_field('system', 'status', 'status', array(
       
   499       'type' => 'int', 'not null' => TRUE, 'default' => 0));
       
   500     db_change_field('system', 'weight', 'weight', array(
       
   501       'type' => 'int', 'not null' => TRUE, 'default' => 0));
       
   502     db_change_field('system', 'bootstrap', 'bootstrap', array(
       
   503       'type' => 'int', 'not null' => TRUE, 'default' => 0));
       
   504     // Drop and recreate 6.x indexes.
       
   505     db_drop_index('system', 'bootstrap');
       
   506     db_add_index('system', 'bootstrap', array(
       
   507       'status', 'bootstrap', array('type', 12), 'weight', 'name'));
       
   508 
       
   509     db_drop_index('system' ,'modules');
       
   510     db_add_index('system', 'modules', array(array(
       
   511       'type', 12), 'status', 'weight', 'name'));
       
   512 
       
   513     db_drop_index('system', 'type_name');
       
   514     db_add_index('system', 'type_name', array(array('type', 12), 'name'));
       
   515     // Add 7.x indexes.
       
   516     db_add_index('system', 'system_list', array('weight', 'name'));
       
   517 
       
   518     // Add the cache_path table.
       
   519     if (db_table_exists('cache_path')) {
       
   520       db_drop_table('cache_path');
       
   521     }
       
   522     require_once('./modules/system/system.install');
       
   523     $schema['cache_path'] = system_schema_cache_7054();
       
   524     $schema['cache_path']['description'] = 'Cache table used for path alias lookups.';
       
   525     db_create_table('cache_path', $schema['cache_path']);
       
   526 
       
   527     // system_update_7042() renames columns, but these are needed to bootstrap.
       
   528     // Add empty columns for now.
       
   529     db_add_field('url_alias', 'source', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   530     db_add_field('url_alias', 'alias', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   531 
       
   532     // Add new columns to {menu_router}.
       
   533     db_add_field('menu_router', 'delivery_callback', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   534     db_add_field('menu_router', 'context', array(
       
   535       'description' => 'Only for local tasks (tabs) - the context of a local task to control its placement.',
       
   536       'type' => 'int',
       
   537       'not null' => TRUE,
       
   538       'default' => 0,
       
   539     ));
       
   540     db_drop_index('menu_router', 'tab_parent');
       
   541     db_add_index('menu_router', 'tab_parent', array(array('tab_parent', 64), 'weight', 'title'));
       
   542     db_add_field('menu_router', 'theme_callback', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   543     db_add_field('menu_router', 'theme_arguments', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   544 
       
   545     // Add the role_permission table.
       
   546     $schema['role_permission'] = array(
       
   547       'fields' => array(
       
   548         'rid' => array(
       
   549         'type' => 'int',
       
   550         'unsigned' => TRUE,
       
   551         'not null' => TRUE,
       
   552       ),
       
   553       'permission' => array(
       
   554         'type' => 'varchar',
       
   555         'length' => 128,
       
   556         'not null' => TRUE,
       
   557         'default' => '',
       
   558       ),
       
   559     ),
       
   560     'primary key' => array('rid', 'permission'),
       
   561     'indexes' => array(
       
   562       'permission' => array('permission'),
       
   563       ),
       
   564     );
       
   565     db_create_table('role_permission', $schema['role_permission']);
       
   566 
       
   567     // Drops and recreates semaphore value index.
       
   568     db_drop_index('semaphore', 'value');
       
   569     db_add_index('semaphore', 'value', array('value'));
       
   570 
       
   571     $schema['date_format_type'] = array(
       
   572       'description' => 'Stores configured date format types.',
       
   573       'fields' => array(
       
   574         'type' => array(
       
   575           'description' => 'The date format type, e.g. medium.',
       
   576           'type' => 'varchar',
       
   577           'length' => 64,
       
   578           'not null' => TRUE,
       
   579         ),
       
   580         'title' => array(
       
   581           'description' => 'The human readable name of the format type.',
       
   582           'type' => 'varchar',
       
   583           'length' => 255,
       
   584           'not null' => TRUE,
       
   585         ),
       
   586         'locked' => array(
       
   587           'description' => 'Whether or not this is a system provided format.',
       
   588           'type' => 'int',
       
   589           'size' => 'tiny',
       
   590           'default' => 0,
       
   591           'not null' => TRUE,
       
   592         ),
       
   593       ),
       
   594       'primary key' => array('type'),
       
   595     );
       
   596 
       
   597     $schema['date_formats'] = array(
       
   598       'description' => 'Stores configured date formats.',
       
   599       'fields' => array(
       
   600         'dfid' => array(
       
   601           'description' => 'The date format identifier.',
       
   602           'type' => 'serial',
       
   603           'not null' => TRUE,
       
   604           'unsigned' => TRUE,
       
   605         ),
       
   606         'format' => array(
       
   607           'description' => 'The date format string.',
       
   608           'type' => 'varchar',
       
   609           'length' => 100,
       
   610           'not null' => TRUE,
       
   611         ),
       
   612         'type' => array(
       
   613           'description' => 'The date format type, e.g. medium.',
       
   614           'type' => 'varchar',
       
   615           'length' => 64,
       
   616           'not null' => TRUE,
       
   617         ),
       
   618         'locked' => array(
       
   619           'description' => 'Whether or not this format can be modified.',
       
   620           'type' => 'int',
       
   621           'size' => 'tiny',
       
   622           'default' => 0,
       
   623           'not null' => TRUE,
       
   624         ),
       
   625       ),
       
   626       'primary key' => array('dfid'),
       
   627       'unique keys' => array('formats' => array('format', 'type')),
       
   628     );
       
   629 
       
   630     $schema['date_format_locale'] = array(
       
   631       'description' => 'Stores configured date formats for each locale.',
       
   632       'fields' => array(
       
   633         'format' => array(
       
   634           'description' => 'The date format string.',
       
   635           'type' => 'varchar',
       
   636           'length' => 100,
       
   637           'not null' => TRUE,
       
   638         ),
       
   639         'type' => array(
       
   640           'description' => 'The date format type, e.g. medium.',
       
   641           'type' => 'varchar',
       
   642           'length' => 64,
       
   643           'not null' => TRUE,
       
   644         ),
       
   645         'language' => array(
       
   646           'description' => 'A {languages}.language for this format to be used with.',
       
   647           'type' => 'varchar',
       
   648           'length' => 12,
       
   649           'not null' => TRUE,
       
   650         ),
       
   651       ),
       
   652       'primary key' => array('type', 'language'),
       
   653     );
       
   654 
       
   655     db_create_table('date_format_type', $schema['date_format_type']);
       
   656     // Sites that have the Drupal 6 Date module installed already have the
       
   657     // following tables.
       
   658     if (db_table_exists('date_formats')) {
       
   659       db_rename_table('date_formats', 'd6_date_formats');
       
   660     }
       
   661     db_create_table('date_formats', $schema['date_formats']);
       
   662     if (db_table_exists('date_format_locale')) {
       
   663       db_rename_table('date_format_locale', 'd6_date_format_locale');
       
   664     }
       
   665     db_create_table('date_format_locale', $schema['date_format_locale']);
       
   666 
       
   667     // Add the queue table.
       
   668     $schema['queue'] = array(
       
   669       'description' => 'Stores items in queues.',
       
   670       'fields' => array(
       
   671         'item_id' => array(
       
   672           'type' => 'serial',
       
   673           'unsigned' => TRUE,
       
   674           'not null' => TRUE,
       
   675           'description' => 'Primary Key: Unique item ID.',
       
   676         ),
       
   677         'name' => array(
       
   678           'type' => 'varchar',
       
   679           'length' => 255,
       
   680           'not null' => TRUE,
       
   681           'default' => '',
       
   682           'description' => 'The queue name.',
       
   683         ),
       
   684         'data' => array(
       
   685           'type' => 'blob',
       
   686           'not null' => FALSE,
       
   687           'size' => 'big',
       
   688           'serialize' => TRUE,
       
   689           'description' => 'The arbitrary data for the item.',
       
   690         ),
       
   691         'expire' => array(
       
   692           'type' => 'int',
       
   693           'not null' => TRUE,
       
   694           'default' => 0,
       
   695           'description' => 'Timestamp when the claim lease expires on the item.',
       
   696         ),
       
   697         'created' => array(
       
   698           'type' => 'int',
       
   699           'not null' => TRUE,
       
   700           'default' => 0,
       
   701           'description' => 'Timestamp when the item was created.',
       
   702         ),
       
   703       ),
       
   704       'primary key' => array('item_id'),
       
   705       'indexes' => array(
       
   706         'name_created' => array('name', 'created'),
       
   707         'expire' => array('expire'),
       
   708       ),
       
   709     );
       
   710     // Check for queue table that may remain from D5 or D6, if found
       
   711     //drop it.
       
   712     if (db_table_exists('queue')) {
       
   713       db_drop_table('queue');
       
   714     }
       
   715 
       
   716     db_create_table('queue', $schema['queue']);
       
   717 
       
   718     // Create the sequences table.
       
   719     $schema['sequences'] = array(
       
   720       'description' => 'Stores IDs.',
       
   721       'fields' => array(
       
   722         'value' => array(
       
   723           'description' => 'The value of the sequence.',
       
   724           'type' => 'serial',
       
   725           'unsigned' => TRUE,
       
   726           'not null' => TRUE,
       
   727         ),
       
   728        ),
       
   729       'primary key' => array('value'),
       
   730     );
       
   731     // Check for sequences table that may remain from D5 or D6, if found
       
   732     //drop it.
       
   733     if (db_table_exists('sequences')) {
       
   734       db_drop_table('sequences');
       
   735     }
       
   736     db_create_table('sequences', $schema['sequences']);
       
   737     // Initialize the table with the maximum current increment of the tables
       
   738     // that will rely on it for their ids.
       
   739     $max_aid = db_query('SELECT MAX(aid) FROM {actions_aid}')->fetchField();
       
   740     $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField();
       
   741     $max_batch_id = db_query('SELECT MAX(bid) FROM {batch}')->fetchField();
       
   742     db_insert('sequences')->fields(array('value' => max($max_aid, $max_uid, $max_batch_id)))->execute();
       
   743 
       
   744     // Add column for locale context.
       
   745     if (db_table_exists('locales_source')) {
       
   746       db_add_field('locales_source', 'context', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'description' => 'The context this string applies to.'));
       
   747     }
       
   748 
       
   749     // Rename 'site_offline_message' variable to 'maintenance_mode_message'
       
   750     // and 'site_offline' variable to 'maintenance_mode'.
       
   751     // Old variable is removed in update for system.module, see
       
   752     // system_update_7072().
       
   753     if ($message = variable_get('site_offline_message', NULL)) {
       
   754       variable_set('maintenance_mode_message', $message);
       
   755     }
       
   756     // Old variable is removed in update for system.module, see
       
   757     // system_update_7069().
       
   758     $site_offline = variable_get('site_offline', -1);
       
   759     if ($site_offline != -1) {
       
   760       variable_set('maintenance_mode', $site_offline);
       
   761     }
       
   762 
       
   763     // Add ssid column and index.
       
   764     db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
       
   765     db_add_index('sessions', 'ssid', array('ssid'));
       
   766     // Drop existing primary key.
       
   767     db_drop_primary_key('sessions');
       
   768     // Add new primary key.
       
   769     db_add_primary_key('sessions', array('sid', 'ssid'));
       
   770 
       
   771     // Allow longer javascript file names.
       
   772     if (db_table_exists('languages')) {
       
   773       db_change_field('languages', 'javascript', 'javascript', array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''));
       
   774     }
       
   775 
       
   776     // Rename action description to label.
       
   777     db_change_field('actions', 'description', 'label', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0'));
       
   778 
       
   779     variable_set('update_d7_requirements', TRUE);
       
   780   }
       
   781 
       
   782   update_fix_d7_install_profile();
       
   783 }
       
   784 
       
   785 /**
       
   786  * Register the currently installed profile in the system table.
       
   787  *
       
   788  * Installation profiles are now treated as modules by Drupal, and have an
       
   789  * upgrade path based on their schema version in the system table.
       
   790  *
       
   791  * The installation profile will be set to schema_version 0, as it has already
       
   792  * been installed. Any other hook_update_N functions provided by the
       
   793  * installation profile will be run by update.php.
       
   794  */
       
   795 function update_fix_d7_install_profile() {
       
   796   $profile = drupal_get_profile();
       
   797 
       
   798   // 'Default' profile has been renamed to 'Standard' in D7.
       
   799   // We change the profile here to prevent a broken record in the system table.
       
   800   // See system_update_7049().
       
   801   if ($profile == 'default') {
       
   802     $profile = 'standard';
       
   803     variable_set('install_profile', $profile);
       
   804   }
       
   805 
       
   806   $results = db_select('system', 's')
       
   807     ->fields('s', array('name', 'schema_version'))
       
   808     ->condition('name', $profile)
       
   809     ->condition('type', 'module')
       
   810     ->execute()
       
   811     ->fetchAll();
       
   812 
       
   813   if (empty($results)) {
       
   814     $filename = 'profiles/' . $profile . '/' . $profile . '.profile';
       
   815 
       
   816     // Read profile info file
       
   817     $info = drupal_parse_info_file(dirname($filename) . '/' . $profile . '.info');
       
   818 
       
   819     // Merge in defaults.
       
   820     $info = $info + array(
       
   821       'dependencies' => array(),
       
   822       'description' => '',
       
   823       'package' => 'Other',
       
   824       'version' => NULL,
       
   825       'php' => DRUPAL_MINIMUM_PHP,
       
   826       'files' => array(),
       
   827     );
       
   828 
       
   829     $values = array(
       
   830       'filename' => $filename,
       
   831       'name' => $profile,
       
   832       'info' => serialize($info),
       
   833       'schema_version' => 0,
       
   834       'type' => 'module',
       
   835       'status' => 1,
       
   836       'owner' => '',
       
   837     );
       
   838 
       
   839     // Installation profile hooks are always executed last by the module system
       
   840     $values['weight'] = 1000;
       
   841 
       
   842     // Initializing the system table entry for the installation profile
       
   843     db_insert('system')
       
   844       ->fields(array_keys($values))
       
   845       ->values($values)
       
   846       ->execute();
       
   847 
       
   848     // Reset the cached schema version.
       
   849     drupal_get_installed_schema_version($profile, TRUE);
       
   850 
       
   851     // Load the updates again to make sure the installation profile updates
       
   852     // are loaded.
       
   853     drupal_load_updates();
       
   854   }
       
   855 }
       
   856 
       
   857 /**
       
   858  * Parse pre-Drupal 7 database connection URLs and return D7 compatible array.
       
   859  *
       
   860  * @return
       
   861  *   Drupal 7 DBTNG compatible array of database connection information.
       
   862  */
       
   863 function update_parse_db_url($db_url, $db_prefix) {
       
   864   $databases = array();
       
   865   if (!is_array($db_url)) {
       
   866     $db_url = array('default' => $db_url);
       
   867   }
       
   868   foreach ($db_url as $database => $url) {
       
   869     $url = parse_url($url);
       
   870     $databases[$database]['default'] = array(
       
   871       // MySQLi uses the mysql driver.
       
   872       'driver' => $url['scheme'] == 'mysqli' ? 'mysql' : $url['scheme'],
       
   873       // Remove the leading slash to get the database name.
       
   874       'database' => substr(urldecode($url['path']), 1),
       
   875       'username' => urldecode($url['user']),
       
   876       'password' => isset($url['pass']) ? urldecode($url['pass']) : '',
       
   877       'host' => urldecode($url['host']),
       
   878       'port' => isset($url['port']) ? urldecode($url['port']) : '',
       
   879     );
       
   880     if (isset($db_prefix)) {
       
   881       $databases[$database]['default']['prefix'] = $db_prefix;
       
   882     }
       
   883   }
       
   884   return $databases;
       
   885 }
       
   886 
       
   887 /**
       
   888  * Constructs a session name compatible with a D6 environment.
       
   889  *
       
   890  * @return
       
   891  *   D6-compatible session name string.
       
   892  *
       
   893  * @see drupal_settings_initialize()
       
   894  */
       
   895 function update_get_d6_session_name() {
       
   896   global $base_url, $cookie_domain;
       
   897   $cookie_secure = ini_get('session.cookie_secure');
       
   898 
       
   899   // If a custom cookie domain is set in settings.php, that variable forms
       
   900   // the basis of the session name. Re-compute the D7 hashing method to find
       
   901   // out if $cookie_domain was used as the session name.
       
   902   if (($cookie_secure ? 'SSESS' : 'SESS') . substr(hash('sha256', $cookie_domain), 0, 32) == session_name()) {
       
   903     $session_name = $cookie_domain;
       
   904   }
       
   905   else {
       
   906     // Otherwise use $base_url as session name, without the protocol
       
   907     // to use the same session identifiers across HTTP and HTTPS.
       
   908     list( , $session_name) = explode('://', $base_url, 2);
       
   909   }
       
   910 
       
   911   if ($cookie_secure) {
       
   912     $session_name .= 'SSL';
       
   913   }
       
   914 
       
   915   return 'SESS' . md5($session_name);
       
   916 }
       
   917 
       
   918 /**
       
   919  * Implements callback_batch_operation().
       
   920  *
       
   921  * Performs one update and stores the results for display on the results page.
       
   922  *
       
   923  * If an update function completes successfully, it should return a message
       
   924  * as a string indicating success, for example:
       
   925  * @code
       
   926  * return t('New index added successfully.');
       
   927  * @endcode
       
   928  *
       
   929  * Alternatively, it may return nothing. In that case, no message
       
   930  * will be displayed at all.
       
   931  *
       
   932  * If it fails for whatever reason, it should throw an instance of
       
   933  * DrupalUpdateException with an appropriate error message, for example:
       
   934  * @code
       
   935  * throw new DrupalUpdateException(t('Description of what went wrong'));
       
   936  * @endcode
       
   937  *
       
   938  * If an exception is thrown, the current update and all updates that depend on
       
   939  * it will be aborted. The schema version will not be updated in this case, and
       
   940  * all the aborted updates will continue to appear on update.php as updates
       
   941  * that have not yet been run.
       
   942  *
       
   943  * If an update function needs to be re-run as part of a batch process, it
       
   944  * should accept the $sandbox array by reference as its first parameter
       
   945  * and set the #finished property to the percentage completed that it is, as a
       
   946  * fraction of 1.
       
   947  *
       
   948  * @param $module
       
   949  *   The module whose update will be run.
       
   950  * @param $number
       
   951  *   The update number to run.
       
   952  * @param $dependency_map
       
   953  *   An array whose keys are the names of all update functions that will be
       
   954  *   performed during this batch process, and whose values are arrays of other
       
   955  *   update functions that each one depends on.
       
   956  * @param $context
       
   957  *   The batch context array.
       
   958  *
       
   959  * @see update_resolve_dependencies()
       
   960  */
       
   961 function update_do_one($module, $number, $dependency_map, &$context) {
       
   962   $function = $module . '_update_' . $number;
       
   963 
       
   964   // If this update was aborted in a previous step, or has a dependency that
       
   965   // was aborted in a previous step, go no further.
       
   966   if (!empty($context['results']['#abort']) && array_intersect($context['results']['#abort'], array_merge($dependency_map, array($function)))) {
       
   967     return;
       
   968   }
       
   969 
       
   970   $ret = array();
       
   971   if (function_exists($function)) {
       
   972     try {
       
   973       $ret['results']['query'] = $function($context['sandbox']);
       
   974       $ret['results']['success'] = TRUE;
       
   975     }
       
   976     // @TODO We may want to do different error handling for different
       
   977     // exception types, but for now we'll just log the exception and
       
   978     // return the message for printing.
       
   979     catch (Exception $e) {
       
   980       watchdog_exception('update', $e);
       
   981 
       
   982       require_once DRUPAL_ROOT . '/includes/errors.inc';
       
   983       $variables = _drupal_decode_exception($e);
       
   984       // The exception message is run through check_plain() by _drupal_decode_exception().
       
   985       $ret['#abort'] = array('success' => FALSE, 'query' => t('%type: !message in %function (line %line of %file).', $variables));
       
   986     }
       
   987   }
       
   988 
       
   989   if (isset($context['sandbox']['#finished'])) {
       
   990     $context['finished'] = $context['sandbox']['#finished'];
       
   991     unset($context['sandbox']['#finished']);
       
   992   }
       
   993 
       
   994   if (!isset($context['results'][$module])) {
       
   995     $context['results'][$module] = array();
       
   996   }
       
   997   if (!isset($context['results'][$module][$number])) {
       
   998     $context['results'][$module][$number] = array();
       
   999   }
       
  1000   $context['results'][$module][$number] = array_merge($context['results'][$module][$number], $ret);
       
  1001 
       
  1002   if (!empty($ret['#abort'])) {
       
  1003     // Record this function in the list of updates that were aborted.
       
  1004     $context['results']['#abort'][] = $function;
       
  1005   }
       
  1006 
       
  1007   // Record the schema update if it was completed successfully.
       
  1008   if ($context['finished'] == 1 && empty($ret['#abort'])) {
       
  1009     drupal_set_installed_schema_version($module, $number);
       
  1010   }
       
  1011 
       
  1012   $context['message'] = 'Updating ' . check_plain($module) . ' module';
       
  1013 }
       
  1014 
       
  1015 /**
       
  1016  * @class Exception class used to throw error if a module update fails.
       
  1017  */
       
  1018 class DrupalUpdateException extends Exception { }
       
  1019 
       
  1020 /**
       
  1021  * Starts the database update batch process.
       
  1022  *
       
  1023  * @param $start
       
  1024  *   An array whose keys contain the names of modules to be updated during the
       
  1025  *   current batch process, and whose values contain the number of the first
       
  1026  *   requested update for that module. The actual updates that are run (and the
       
  1027  *   order they are run in) will depend on the results of passing this data
       
  1028  *   through the update dependency system.
       
  1029  * @param $redirect
       
  1030  *   Path to redirect to when the batch has finished processing.
       
  1031  * @param $url
       
  1032  *   URL of the batch processing page (should only be used for separate
       
  1033  *   scripts like update.php).
       
  1034  * @param $batch
       
  1035  *   Optional parameters to pass into the batch API.
       
  1036  * @param $redirect_callback
       
  1037  *   (optional) Specify a function to be called to redirect to the progressive
       
  1038  *   processing page.
       
  1039  *
       
  1040  * @see update_resolve_dependencies()
       
  1041  */
       
  1042 function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $redirect_callback = 'drupal_goto') {
       
  1043   // During the update, bring the site offline so that schema changes do not
       
  1044   // affect visiting users.
       
  1045   $_SESSION['maintenance_mode'] = variable_get('maintenance_mode', FALSE);
       
  1046   if ($_SESSION['maintenance_mode'] == FALSE) {
       
  1047     variable_set('maintenance_mode', TRUE);
       
  1048   }
       
  1049 
       
  1050   // Resolve any update dependencies to determine the actual updates that will
       
  1051   // be run and the order they will be run in.
       
  1052   $updates = update_resolve_dependencies($start);
       
  1053 
       
  1054   // Store the dependencies for each update function in an array which the
       
  1055   // batch API can pass in to the batch operation each time it is called. (We
       
  1056   // do not store the entire update dependency array here because it is
       
  1057   // potentially very large.)
       
  1058   $dependency_map = array();
       
  1059   foreach ($updates as $function => $update) {
       
  1060     $dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : array();
       
  1061   }
       
  1062 
       
  1063   $operations = array();
       
  1064   foreach ($updates as $update) {
       
  1065     if ($update['allowed']) {
       
  1066       // Set the installed version of each module so updates will start at the
       
  1067       // correct place. (The updates are already sorted, so we can simply base
       
  1068       // this on the first one we come across in the above foreach loop.)
       
  1069       if (isset($start[$update['module']])) {
       
  1070         drupal_set_installed_schema_version($update['module'], $update['number'] - 1);
       
  1071         unset($start[$update['module']]);
       
  1072       }
       
  1073       // Add this update function to the batch.
       
  1074       $function = $update['module'] . '_update_' . $update['number'];
       
  1075       $operations[] = array('update_do_one', array($update['module'], $update['number'], $dependency_map[$function]));
       
  1076     }
       
  1077   }
       
  1078   $batch['operations'] = $operations;
       
  1079   $batch += array(
       
  1080     'title' => 'Updating',
       
  1081     'init_message' => 'Starting updates',
       
  1082     'error_message' => 'An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.',
       
  1083     'finished' => 'update_finished',
       
  1084     'file' => 'includes/update.inc',
       
  1085   );
       
  1086   batch_set($batch);
       
  1087   batch_process($redirect, $url, $redirect_callback);
       
  1088 }
       
  1089 
       
  1090 /**
       
  1091  * Implements callback_batch_finished().
       
  1092  *
       
  1093  * Finishes the update process and stores the results for eventual display.
       
  1094  *
       
  1095  * After the updates run, all caches are flushed. The update results are
       
  1096  * stored into the session (for example, to be displayed on the update results
       
  1097  * page in update.php). Additionally, if the site was off-line, now that the
       
  1098  * update process is completed, the site is set back online.
       
  1099  *
       
  1100  * @param $success
       
  1101  *   Indicate that the batch API tasks were all completed successfully.
       
  1102  * @param $results
       
  1103  *   An array of all the results that were updated in update_do_one().
       
  1104  * @param $operations
       
  1105  *   A list of all the operations that had not been completed by the batch API.
       
  1106  *
       
  1107  * @see update_batch()
       
  1108  */
       
  1109 function update_finished($success, $results, $operations) {
       
  1110   // Remove the D6 upgrade flag variable so that subsequent update runs do not
       
  1111   // get the wrong context.
       
  1112   variable_del('update_d6');
       
  1113 
       
  1114   // Clear the caches in case the data has been updated.
       
  1115   drupal_flush_all_caches();
       
  1116 
       
  1117   $_SESSION['update_results'] = $results;
       
  1118   $_SESSION['update_success'] = $success;
       
  1119   $_SESSION['updates_remaining'] = $operations;
       
  1120 
       
  1121   // Now that the update is done, we can put the site back online if it was
       
  1122   // previously in maintenance mode.
       
  1123   if (isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
       
  1124     variable_set('maintenance_mode', FALSE);
       
  1125     unset($_SESSION['maintenance_mode']);
       
  1126   }
       
  1127 }
       
  1128 
       
  1129 /**
       
  1130  * Returns a list of all the pending database updates.
       
  1131  *
       
  1132  * @return
       
  1133  *   An associative array keyed by module name which contains all information
       
  1134  *   about database updates that need to be run, and any updates that are not
       
  1135  *   going to proceed due to missing requirements. The system module will
       
  1136  *   always be listed first.
       
  1137  *
       
  1138  *   The subarray for each module can contain the following keys:
       
  1139  *   - start: The starting update that is to be processed. If this does not
       
  1140  *       exist then do not process any updates for this module as there are
       
  1141  *       other requirements that need to be resolved.
       
  1142  *   - warning: Any warnings about why this module can not be updated.
       
  1143  *   - pending: An array of all the pending updates for the module including
       
  1144  *       the update number and the description from source code comment for
       
  1145  *       each update function. This array is keyed by the update number.
       
  1146  */
       
  1147 function update_get_update_list() {
       
  1148   // Make sure that the system module is first in the list of updates.
       
  1149   $ret = array('system' => array());
       
  1150 
       
  1151   $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE);
       
  1152   foreach ($modules as $module => $schema_version) {
       
  1153     // Skip uninstalled and incompatible modules.
       
  1154     if ($schema_version == SCHEMA_UNINSTALLED || update_check_incompatibility($module)) {
       
  1155       continue;
       
  1156     }
       
  1157     // Otherwise, get the list of updates defined by this module.
       
  1158     $updates = drupal_get_schema_versions($module);
       
  1159     if ($updates !== FALSE) {
       
  1160       // module_invoke returns NULL for nonexisting hooks, so if no updates
       
  1161       // are removed, it will == 0.
       
  1162       $last_removed = module_invoke($module, 'update_last_removed');
       
  1163       if ($schema_version < $last_removed) {
       
  1164         $ret[$module]['warning'] = '<em>' . $module . '</em> module can not be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.';
       
  1165         continue;
       
  1166       }
       
  1167 
       
  1168       $updates = drupal_map_assoc($updates);
       
  1169       foreach (array_keys($updates) as $update) {
       
  1170         if ($update > $schema_version) {
       
  1171           // The description for an update comes from its Doxygen.
       
  1172           $func = new ReflectionFunction($module . '_update_' . $update);
       
  1173           $description = str_replace(array("\n", '*', '/'), '', $func->getDocComment());
       
  1174           $ret[$module]['pending'][$update] = "$update - $description";
       
  1175           if (!isset($ret[$module]['start'])) {
       
  1176             $ret[$module]['start'] = $update;
       
  1177           }
       
  1178         }
       
  1179       }
       
  1180       if (!isset($ret[$module]['start']) && isset($ret[$module]['pending'])) {
       
  1181         $ret[$module]['start'] = $schema_version;
       
  1182       }
       
  1183     }
       
  1184   }
       
  1185 
       
  1186   if (empty($ret['system'])) {
       
  1187     unset($ret['system']);
       
  1188   }
       
  1189   return $ret;
       
  1190 }
       
  1191 
       
  1192 /**
       
  1193  * Resolves dependencies in a set of module updates, and orders them correctly.
       
  1194  *
       
  1195  * This function receives a list of requested module updates and determines an
       
  1196  * appropriate order to run them in such that all update dependencies are met.
       
  1197  * Any updates whose dependencies cannot be met are included in the returned
       
  1198  * array but have the key 'allowed' set to FALSE; the calling function should
       
  1199  * take responsibility for ensuring that these updates are ultimately not
       
  1200  * performed.
       
  1201  *
       
  1202  * In addition, the returned array also includes detailed information about the
       
  1203  * dependency chain for each update, as provided by the depth-first search
       
  1204  * algorithm in drupal_depth_first_search().
       
  1205  *
       
  1206  * @param $starting_updates
       
  1207  *   An array whose keys contain the names of modules with updates to be run
       
  1208  *   and whose values contain the number of the first requested update for that
       
  1209  *   module.
       
  1210  *
       
  1211  * @return
       
  1212  *   An array whose keys are the names of all update functions within the
       
  1213  *   provided modules that would need to be run in order to fulfill the
       
  1214  *   request, arranged in the order in which the update functions should be
       
  1215  *   run. (This includes the provided starting update for each module and all
       
  1216  *   subsequent updates that are available.) The values are themselves arrays
       
  1217  *   containing all the keys provided by the drupal_depth_first_search()
       
  1218  *   algorithm, which encode detailed information about the dependency chain
       
  1219  *   for this update function (for example: 'paths', 'reverse_paths', 'weight',
       
  1220  *   and 'component'), as well as the following additional keys:
       
  1221  *   - 'allowed': A boolean which is TRUE when the update function's
       
  1222  *     dependencies are met, and FALSE otherwise. Calling functions should
       
  1223  *     inspect this value before running the update.
       
  1224  *   - 'missing_dependencies': An array containing the names of any other
       
  1225  *     update functions that are required by this one but that are unavailable
       
  1226  *     to be run. This array will be empty when 'allowed' is TRUE.
       
  1227  *   - 'module': The name of the module that this update function belongs to.
       
  1228  *   - 'number': The number of this update function within that module.
       
  1229  *
       
  1230  * @see drupal_depth_first_search()
       
  1231  */
       
  1232 function update_resolve_dependencies($starting_updates) {
       
  1233   // Obtain a dependency graph for the requested update functions.
       
  1234   $update_functions = update_get_update_function_list($starting_updates);
       
  1235   $graph = update_build_dependency_graph($update_functions);
       
  1236 
       
  1237   // Perform the depth-first search and sort the results.
       
  1238   require_once DRUPAL_ROOT . '/includes/graph.inc';
       
  1239   drupal_depth_first_search($graph);
       
  1240   uasort($graph, 'drupal_sort_weight');
       
  1241 
       
  1242   foreach ($graph as $function => &$data) {
       
  1243     $module = $data['module'];
       
  1244     $number = $data['number'];
       
  1245     // If the update function is missing and has not yet been performed, mark
       
  1246     // it and everything that ultimately depends on it as disallowed.
       
  1247     if (update_is_missing($module, $number, $update_functions) && !update_already_performed($module, $number)) {
       
  1248       $data['allowed'] = FALSE;
       
  1249       foreach (array_keys($data['paths']) as $dependent) {
       
  1250         $graph[$dependent]['allowed'] = FALSE;
       
  1251         $graph[$dependent]['missing_dependencies'][] = $function;
       
  1252       }
       
  1253     }
       
  1254     elseif (!isset($data['allowed'])) {
       
  1255       $data['allowed'] = TRUE;
       
  1256       $data['missing_dependencies'] = array();
       
  1257     }
       
  1258     // Now that we have finished processing this function, remove it from the
       
  1259     // graph if it was not part of the original list. This ensures that we
       
  1260     // never try to run any updates that were not specifically requested.
       
  1261     if (!isset($update_functions[$module][$number])) {
       
  1262       unset($graph[$function]);
       
  1263     }
       
  1264   }
       
  1265 
       
  1266   return $graph;
       
  1267 }
       
  1268 
       
  1269 /**
       
  1270  * Returns an organized list of update functions for a set of modules.
       
  1271  *
       
  1272  * @param $starting_updates
       
  1273  *   An array whose keys contain the names of modules and whose values contain
       
  1274  *   the number of the first requested update for that module.
       
  1275  *
       
  1276  * @return
       
  1277  *   An array containing all the update functions that should be run for each
       
  1278  *   module, including the provided starting update and all subsequent updates
       
  1279  *   that are available. The keys of the array contain the module names, and
       
  1280  *   each value is an ordered array of update functions, keyed by the update
       
  1281  *   number.
       
  1282  *
       
  1283  * @see update_resolve_dependencies()
       
  1284  */
       
  1285 function update_get_update_function_list($starting_updates) {
       
  1286   // Go through each module and find all updates that we need (including the
       
  1287   // first update that was requested and any updates that run after it).
       
  1288   $update_functions = array();
       
  1289   foreach ($starting_updates as $module => $version) {
       
  1290     $update_functions[$module] = array();
       
  1291     $updates = drupal_get_schema_versions($module);
       
  1292     if ($updates !== FALSE) {
       
  1293       $max_version = max($updates);
       
  1294       if ($version <= $max_version) {
       
  1295         foreach ($updates as $update) {
       
  1296           if ($update >= $version) {
       
  1297             $update_functions[$module][$update] = $module . '_update_' . $update;
       
  1298           }
       
  1299         }
       
  1300       }
       
  1301     }
       
  1302   }
       
  1303   return $update_functions;
       
  1304 }
       
  1305 
       
  1306 /**
       
  1307  * Constructs a graph which encodes the dependencies between module updates.
       
  1308  *
       
  1309  * This function returns an associative array which contains a "directed graph"
       
  1310  * representation of the dependencies between a provided list of update
       
  1311  * functions, as well as any outside update functions that they directly depend
       
  1312  * on but that were not in the provided list. The vertices of the graph
       
  1313  * represent the update functions themselves, and each edge represents a
       
  1314  * requirement that the first update function needs to run before the second.
       
  1315  * For example, consider this graph:
       
  1316  *
       
  1317  * system_update_7000 ---> system_update_7001 ---> system_update_7002
       
  1318  *
       
  1319  * Visually, this indicates that system_update_7000() must run before
       
  1320  * system_update_7001(), which in turn must run before system_update_7002().
       
  1321  *
       
  1322  * The function takes into account standard dependencies within each module, as
       
  1323  * shown above (i.e., the fact that each module's updates must run in numerical
       
  1324  * order), but also finds any cross-module dependencies that are defined by
       
  1325  * modules which implement hook_update_dependencies(), and builds them into the
       
  1326  * graph as well.
       
  1327  *
       
  1328  * @param $update_functions
       
  1329  *   An organized array of update functions, in the format returned by
       
  1330  *   update_get_update_function_list().
       
  1331  *
       
  1332  * @return
       
  1333  *   A multidimensional array representing the dependency graph, suitable for
       
  1334  *   passing in to drupal_depth_first_search(), but with extra information
       
  1335  *   about each update function also included. Each array key contains the name
       
  1336  *   of an update function, including all update functions from the provided
       
  1337  *   list as well as any outside update functions which they directly depend
       
  1338  *   on. Each value is an associative array containing the following keys:
       
  1339  *   - 'edges': A representation of any other update functions that immediately
       
  1340  *     depend on this one. See drupal_depth_first_search() for more details on
       
  1341  *     the format.
       
  1342  *   - 'module': The name of the module that this update function belongs to.
       
  1343  *   - 'number': The number of this update function within that module.
       
  1344  *
       
  1345  * @see drupal_depth_first_search()
       
  1346  * @see update_resolve_dependencies()
       
  1347  */
       
  1348 function update_build_dependency_graph($update_functions) {
       
  1349   // Initialize an array that will define a directed graph representing the
       
  1350   // dependencies between update functions.
       
  1351   $graph = array();
       
  1352 
       
  1353   // Go through each update function and build an initial list of dependencies.
       
  1354   foreach ($update_functions as $module => $functions) {
       
  1355     $previous_function = NULL;
       
  1356     foreach ($functions as $number => $function) {
       
  1357       // Add an edge to the directed graph representing the fact that each
       
  1358       // update function in a given module must run after the update that
       
  1359       // numerically precedes it.
       
  1360       if ($previous_function) {
       
  1361         $graph[$previous_function]['edges'][$function] = TRUE;
       
  1362       }
       
  1363       $previous_function = $function;
       
  1364 
       
  1365       // Define the module and update number associated with this function.
       
  1366       $graph[$function]['module'] = $module;
       
  1367       $graph[$function]['number'] = $number;
       
  1368     }
       
  1369   }
       
  1370 
       
  1371   // Now add any explicit update dependencies declared by modules.
       
  1372   $update_dependencies = update_retrieve_dependencies();
       
  1373   foreach ($graph as $function => $data) {
       
  1374     if (!empty($update_dependencies[$data['module']][$data['number']])) {
       
  1375       foreach ($update_dependencies[$data['module']][$data['number']] as $module => $number) {
       
  1376         $dependency = $module . '_update_' . $number;
       
  1377         $graph[$dependency]['edges'][$function] = TRUE;
       
  1378         $graph[$dependency]['module'] = $module;
       
  1379         $graph[$dependency]['number'] = $number;
       
  1380       }
       
  1381     }
       
  1382   }
       
  1383 
       
  1384   return $graph;
       
  1385 }
       
  1386 
       
  1387 /**
       
  1388  * Determines if a module update is missing or unavailable.
       
  1389  *
       
  1390  * @param $module
       
  1391  *   The name of the module.
       
  1392  * @param $number
       
  1393  *   The number of the update within that module.
       
  1394  * @param $update_functions
       
  1395  *   An organized array of update functions, in the format returned by
       
  1396  *   update_get_update_function_list(). This should represent all module
       
  1397  *   updates that are requested to run at the time this function is called.
       
  1398  *
       
  1399  * @return
       
  1400  *   TRUE if the provided module update is not installed or is not in the
       
  1401  *   provided list of updates to run; FALSE otherwise.
       
  1402  */
       
  1403 function update_is_missing($module, $number, $update_functions) {
       
  1404   return !isset($update_functions[$module][$number]) || !function_exists($update_functions[$module][$number]);
       
  1405 }
       
  1406 
       
  1407 /**
       
  1408  * Determines if a module update has already been performed.
       
  1409  *
       
  1410  * @param $module
       
  1411  *   The name of the module.
       
  1412  * @param $number
       
  1413  *   The number of the update within that module.
       
  1414  *
       
  1415  * @return
       
  1416  *   TRUE if the database schema indicates that the update has already been
       
  1417  *   performed; FALSE otherwise.
       
  1418  */
       
  1419 function update_already_performed($module, $number) {
       
  1420   return $number <= drupal_get_installed_schema_version($module);
       
  1421 }
       
  1422 
       
  1423 /**
       
  1424  * Invokes hook_update_dependencies() in all installed modules.
       
  1425  *
       
  1426  * This function is similar to module_invoke_all(), with the main difference
       
  1427  * that it does not require that a module be enabled to invoke its hook, only
       
  1428  * that it be installed. This allows the update system to properly perform
       
  1429  * updates even on modules that are currently disabled.
       
  1430  *
       
  1431  * @return
       
  1432  *   An array of return values obtained by merging the results of the
       
  1433  *   hook_update_dependencies() implementations in all installed modules.
       
  1434  *
       
  1435  * @see module_invoke_all()
       
  1436  * @see hook_update_dependencies()
       
  1437  */
       
  1438 function update_retrieve_dependencies() {
       
  1439   $return = array();
       
  1440   // Get a list of installed modules, arranged so that we invoke their hooks in
       
  1441   // the same order that module_invoke_all() does.
       
  1442   $modules = db_query("SELECT name FROM {system} WHERE type = 'module' AND schema_version <> :schema ORDER BY weight ASC, name ASC", array(':schema' => SCHEMA_UNINSTALLED))->fetchCol();
       
  1443   foreach ($modules as $module) {
       
  1444     $function = $module . '_update_dependencies';
       
  1445     if (function_exists($function)) {
       
  1446       $result = $function();
       
  1447       // Each implementation of hook_update_dependencies() returns a
       
  1448       // multidimensional, associative array containing some keys that
       
  1449       // represent module names (which are strings) and other keys that
       
  1450       // represent update function numbers (which are integers). We cannot use
       
  1451       // array_merge_recursive() to properly merge these results, since it
       
  1452       // treats strings and integers differently. Therefore, we have to
       
  1453       // explicitly loop through the expected array structure here and perform
       
  1454       // the merge manually.
       
  1455       if (isset($result) && is_array($result)) {
       
  1456         foreach ($result as $module => $module_data) {
       
  1457           foreach ($module_data as $update => $update_data) {
       
  1458             foreach ($update_data as $module_dependency => $update_dependency) {
       
  1459               // If there are redundant dependencies declared for the same
       
  1460               // update function (so that it is declared to depend on more than
       
  1461               // one update from a particular module), record the dependency on
       
  1462               // the highest numbered update here, since that automatically
       
  1463               // implies the previous ones. For example, if one module's
       
  1464               // implementation of hook_update_dependencies() required this
       
  1465               // ordering:
       
  1466               //
       
  1467               // system_update_7001 ---> user_update_7000
       
  1468               //
       
  1469               // but another module's implementation of the hook required this
       
  1470               // one:
       
  1471               //
       
  1472               // system_update_7002 ---> user_update_7000
       
  1473               //
       
  1474               // we record the second one, since system_update_7001() is always
       
  1475               // guaranteed to run before system_update_7002() anyway (within
       
  1476               // an individual module, updates are always run in numerical
       
  1477               // order).
       
  1478               if (!isset($return[$module][$update][$module_dependency]) || $update_dependency > $return[$module][$update][$module_dependency]) {
       
  1479                 $return[$module][$update][$module_dependency] = $update_dependency;
       
  1480               }
       
  1481             }
       
  1482           }
       
  1483         }
       
  1484       }
       
  1485     }
       
  1486   }
       
  1487 
       
  1488   return $return;
       
  1489 }