update_6.inc

  1. 8.0.x commands/core/drupal/update_6.inc
  2. 6.x commands/core/drupal/update_6.inc
  3. 7.x commands/core/drupal/update_6.inc
  4. 3.x commands/core/drupal/update_6.inc
  5. 4.x commands/core/drupal/update_6.inc
  6. 5.x commands/core/drupal/update_6.inc

Update.php for provisioned sites. This file is a derivative of the standard drupal update.php, which has been modified to allow being run from the command line.

Functions

Namesort descending Description
db_add_column Add a column to a database using syntax appropriate for PostgreSQL. Save result of SQL commands in $ret array.
db_change_column Change a column definition using syntax appropriate for PostgreSQL. Save result of SQL commands in $ret array.
updatedb_status Return a 2 item array with
update_check_incompatibility Helper function to test compatibility of a module or theme.
update_check_requirements Check update requirements and report any errors.
update_create_batch_table Create the batch table.
update_fix_compatibility Disable anything in the {system} table that is not compatible with the current version of Drupal core.
update_fix_d6_requirements Perform Drupal 5.x to 6.x updates that are required for update.php to function properly.
update_main
update_main_prepare
_update_batch_command
_update_do_one A simplified version of the batch_do_one function from update.php

Constants

Namesort descending Description
MAINTENANCE_MODE @file Update.php for provisioned sites. This file is a derivative of the standard drupal update.php, which has been modified to allow being run from the command line.

File

commands/core/drupal/update_6.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Update.php for provisioned sites.
  5. * This file is a derivative of the standard drupal update.php,
  6. * which has been modified to allow being run from the command
  7. * line.
  8. */
  9. define('MAINTENANCE_MODE', 'update');
  10. /**
  11. * Add a column to a database using syntax appropriate for PostgreSQL.
  12. * Save result of SQL commands in $ret array.
  13. *
  14. * Note: when you add a column with NOT NULL and you are not sure if there are
  15. * already rows in the table, you MUST also add DEFAULT. Otherwise PostgreSQL
  16. * won't work when the table is not empty, and db_add_column() will fail.
  17. * To have an empty string as the default, you must use: 'default' => "''"
  18. * in the $attributes array. If NOT NULL and DEFAULT are set the PostgreSQL
  19. * version will set values of the added column in old rows to the
  20. * DEFAULT value.
  21. *
  22. * @param $ret
  23. * Array to which results will be added.
  24. * @param $table
  25. * Name of the table, without {}
  26. * @param $column
  27. * Name of the column
  28. * @param $type
  29. * Type of column
  30. * @param $attributes
  31. * Additional optional attributes. Recognized attributes:
  32. * not null => TRUE|FALSE
  33. * default => NULL|FALSE|value (the value must be enclosed in '' marks)
  34. * @return
  35. * nothing, but modifies $ret parameter.
  36. */
  37. function db_add_column(&$ret, $table, $column, $type, $attributes = array()) {
  38. if (array_key_exists('not null', $attributes) and $attributes['not null']) {
  39. $not_null = 'NOT NULL';
  40. }
  41. if (array_key_exists('default', $attributes)) {
  42. if (!isset($attributes['default'])) {
  43. $default_val = 'NULL';
  44. $default = 'default NULL';
  45. }
  46. elseif ($attributes['default'] === FALSE) {
  47. $default = '';
  48. }
  49. else {
  50. $default_val = "$attributes[default]";
  51. $default = "default $attributes[default]";
  52. }
  53. }
  54. $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column $type");
  55. if (!empty($default)) {
  56. $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default");
  57. }
  58. if (!empty($not_null)) {
  59. if (!empty($default)) {
  60. $ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val");
  61. }
  62. $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET NOT NULL");
  63. }
  64. }
  65. /**
  66. * Change a column definition using syntax appropriate for PostgreSQL.
  67. * Save result of SQL commands in $ret array.
  68. *
  69. * Remember that changing a column definition involves adding a new column
  70. * and dropping an old one. This means that any indices, primary keys and
  71. * sequences from serial-type columns are dropped and might need to be
  72. * recreated.
  73. *
  74. * @param $ret
  75. * Array to which results will be added.
  76. * @param $table
  77. * Name of the table, without {}
  78. * @param $column
  79. * Name of the column to change
  80. * @param $column_new
  81. * New name for the column (set to the same as $column if you don't want to change the name)
  82. * @param $type
  83. * Type of column
  84. * @param $attributes
  85. * Additional optional attributes. Recognized attributes:
  86. * not null => TRUE|FALSE
  87. * default => NULL|FALSE|value (with or without '', it won't be added)
  88. * @return
  89. * nothing, but modifies $ret parameter.
  90. */
  91. function db_change_column(&$ret, $table, $column, $column_new, $type, $attributes = array()) {
  92. if (array_key_exists('not null', $attributes) and $attributes['not null']) {
  93. $not_null = 'NOT NULL';
  94. }
  95. if (array_key_exists('default', $attributes)) {
  96. if (!isset($attributes['default'])) {
  97. $default_val = 'NULL';
  98. $default = 'default NULL';
  99. }
  100. elseif ($attributes['default'] === FALSE) {
  101. $default = '';
  102. }
  103. else {
  104. $default_val = "$attributes[default]";
  105. $default = "default $attributes[default]";
  106. }
  107. }
  108. $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME $column TO ". $column ."_old");
  109. $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column_new $type");
  110. $ret[] = update_sql("UPDATE {". $table ."} SET $column_new = ". $column ."_old");
  111. if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET $default"); }
  112. if ($not_null) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET NOT NULL"); }
  113. $ret[] = update_sql("ALTER TABLE {". $table ."} DROP ". $column ."_old");
  114. }
  115. /**
  116. * Disable anything in the {system} table that is not compatible with the
  117. * current version of Drupal core.
  118. */
  119. function update_fix_compatibility() {
  120. $ret = array();
  121. $incompatible = array();
  122. $query = db_query("SELECT name, type, status FROM {system} WHERE status = 1 AND type IN ('module','theme')");
  123. while ($result = db_fetch_object($query)) {
  124. if (update_check_incompatibility($result->name, $result->type)) {
  125. $incompatible[] = $result->name;
  126. drush_log(dt("!type !name is incompatible with this release of Drupal, and will be disabled.",
  127. array("!type" => $result->type, '!name' => $result->name)), "warning");
  128. }
  129. }
  130. if (!empty($incompatible)) {
  131. $ret[] = update_sql("UPDATE {system} SET status = 0 WHERE name IN ('". implode("','", $incompatible) ."')");
  132. }
  133. return $ret;
  134. }
  135. /**
  136. * Helper function to test compatibility of a module or theme.
  137. */
  138. function update_check_incompatibility($name, $type = 'module') {
  139. static $themes, $modules;
  140. // Store values of expensive functions for future use.
  141. if (empty($themes) || empty($modules)) {
  142. drush_include_engine('drupal', 'environment');
  143. $themes = _system_theme_data();
  144. $modules = module_rebuild_cache();
  145. }
  146. if ($type == 'module' && isset($modules[$name])) {
  147. $file = $modules[$name];
  148. }
  149. else if ($type == 'theme' && isset($themes[$name])) {
  150. $file = $themes[$name];
  151. }
  152. if (!isset($file)
  153. || !isset($file->info['core'])
  154. || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY
  155. || version_compare(phpversion(), $file->info['php']) < 0) {
  156. return TRUE;
  157. }
  158. return FALSE;
  159. }
  160. /**
  161. * Perform Drupal 5.x to 6.x updates that are required for update.php
  162. * to function properly.
  163. *
  164. * This function runs when update.php is run the first time for 6.x,
  165. * even before updates are selected or performed. It is important
  166. * that if updates are not ultimately performed that no changes are
  167. * made which make it impossible to continue using the prior version.
  168. * Just adding columns is safe. However, renaming the
  169. * system.description column to owner is not. Therefore, we add the
  170. * system.owner column and leave it to system_update_6008() to copy
  171. * the data from description and remove description. The same for
  172. * renaming locales_target.locale to locales_target.language, which
  173. * will be finished by locale_update_6002().
  174. */
  175. function update_fix_d6_requirements() {
  176. $ret = array();
  177. if (drupal_get_installed_schema_version('system') < 6000 && !variable_get('update_d6_requirements', FALSE)) {
  178. $spec = array('type' => 'int', 'size' => 'small', 'default' => 0, 'not null' => TRUE);
  179. db_add_field($ret, 'cache', 'serialized', $spec);
  180. db_add_field($ret, 'cache_filter', 'serialized', $spec);
  181. db_add_field($ret, 'cache_page', 'serialized', $spec);
  182. db_add_field($ret, 'cache_menu', 'serialized', $spec);
  183. db_add_field($ret, 'system', 'info', array('type' => 'text'));
  184. db_add_field($ret, 'system', 'owner', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
  185. if (db_table_exists('locales_target')) {
  186. db_add_field($ret, 'locales_target', 'language', array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''));
  187. }
  188. if (db_table_exists('locales_source')) {
  189. db_add_field($ret, 'locales_source', 'textgroup', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'default'));
  190. db_add_field($ret, 'locales_source', 'version', array('type' => 'varchar', 'length' => 20, 'not null' => TRUE, 'default' => 'none'));
  191. }
  192. variable_set('update_d6_requirements', TRUE);
  193. // Create the cache_block table. See system_update_6027() for more details.
  194. $schema['cache_block'] = array(
  195. 'fields' => array(
  196. 'cid' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
  197. 'data' => array('type' => 'blob', 'not null' => FALSE, 'size' => 'big'),
  198. 'expire' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  199. 'created' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  200. 'headers' => array('type' => 'text', 'not null' => FALSE),
  201. 'serialized' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
  202. ),
  203. 'indexes' => array('expire' => array('expire')),
  204. 'primary key' => array('cid'),
  205. );
  206. db_create_table($ret, 'cache_block', $schema['cache_block']);
  207. // Create the semaphore table now -- the menu system after 6.15 depends on
  208. // this table, and menu code runs in updates prior to the table being
  209. // created in its original update function, system_update_6054().
  210. $schema['semaphore'] = array(
  211. 'fields' => array(
  212. 'name' => array(
  213. 'type' => 'varchar',
  214. 'length' => 255,
  215. 'not null' => TRUE,
  216. 'default' => ''),
  217. 'value' => array(
  218. 'type' => 'varchar',
  219. 'length' => 255,
  220. 'not null' => TRUE,
  221. 'default' => ''),
  222. 'expire' => array(
  223. 'type' => 'float',
  224. 'size' => 'big',
  225. 'not null' => TRUE),
  226. ),
  227. 'indexes' => array('expire' => array('expire')),
  228. 'primary key' => array('name'),
  229. );
  230. db_create_table($ret, 'semaphore', $schema['semaphore']);
  231. }
  232. return $ret;
  233. }
  234. /**
  235. * Check update requirements and report any errors.
  236. */
  237. function update_check_requirements() {
  238. // Check the system module requirements only.
  239. $requirements = module_invoke('system', 'requirements', 'update');
  240. $severity = drupal_requirements_severity($requirements);
  241. // If there are issues, report them.
  242. if ($severity != REQUIREMENT_OK) {
  243. foreach ($requirements as $requirement) {
  244. if (isset($requirement['severity']) && $requirement['severity'] != REQUIREMENT_OK) {
  245. $message = isset($requirement['description']) ? $requirement['description'] : '';
  246. if (isset($requirement['value']) && $requirement['value']) {
  247. $message .= ' (Currently using '. $requirement['title'] .' '. $requirement['value'] .')';
  248. }
  249. drush_log($message, 'warning');
  250. }
  251. }
  252. }
  253. }
  254. /**
  255. * Create the batch table.
  256. *
  257. * This is part of the Drupal 5.x to 6.x migration.
  258. */
  259. function update_create_batch_table() {
  260. // If batch table exists, update is not necessary
  261. if (db_table_exists('batch')) {
  262. return;
  263. }
  264. $schema['batch'] = array(
  265. 'fields' => array(
  266. 'bid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
  267. 'token' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE),
  268. 'timestamp' => array('type' => 'int', 'not null' => TRUE),
  269. 'batch' => array('type' => 'text', 'not null' => FALSE, 'size' => 'big')
  270. ),
  271. 'primary key' => array('bid'),
  272. 'indexes' => array('token' => array('token')),
  273. );
  274. $ret = array();
  275. db_create_table($ret, 'batch', $schema['batch']);
  276. return $ret;
  277. }
  278. function update_main_prepare() {
  279. global $profile;
  280. // Some unavoidable errors happen because the database is not yet up-to-date.
  281. // Our custom error handler is not yet installed, so we just suppress them.
  282. drush_errors_off();
  283. require_once './includes/bootstrap.inc';
  284. // Minimum load of components.
  285. // This differs from the Drupal 6 update.php workflow for compatbility with
  286. // the Drupal 6 backport of module_implements() caching.
  287. // @see http://drupal.org/node/557542
  288. drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_DATABASE);
  289. require_once './includes/install.inc';
  290. require_once './includes/file.inc';
  291. require_once './modules/system/system.install';
  292. // Load module basics.
  293. include_once './includes/module.inc';
  294. $module_list['system']['filename'] = 'modules/system/system.module';
  295. $module_list['filter']['filename'] = 'modules/filter/filter.module';
  296. module_list(TRUE, FALSE, FALSE, $module_list);
  297. module_implements('', FALSE, TRUE);
  298. drupal_load('module', 'system');
  299. drupal_load('module', 'filter');
  300. // Set up $language, since the installer components require it.
  301. drupal_init_language();
  302. // Set up theme system for the maintenance page.
  303. drupal_maintenance_theme();
  304. // Check the update requirements for Drupal.
  305. update_check_requirements();
  306. drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
  307. $profile = variable_get('install_profile', 'default');
  308. // Updates only run reliably if user ID #1 is logged in. For example, node_delete() requires elevated perms in D5/6.
  309. if (!drush_get_context('DRUSH_USER')) {
  310. drush_set_option('user', 1);
  311. drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_LOGIN);
  312. }
  313. // This must happen *after* drupal_bootstrap(), since it calls
  314. // variable_(get|set), which only works after a full bootstrap.
  315. _drush_log_update_sql(update_create_batch_table());
  316. // Turn error reporting back on. From now on, only fatal errors (which are
  317. // not passed through the error handler) will cause a message to be printed.
  318. drush_errors_on();
  319. // Perform Drupal 5.x to 6.x updates that are required for update.php to function properly.
  320. _drush_log_update_sql(update_fix_d6_requirements());
  321. // Must unset $theme->status in order to safely rescan and repopulate
  322. // the system table to ensure we have a full picture of the platform.
  323. // This is needed because $theme->status is set to 0 in a call to
  324. // list_themes() done by drupal_maintenance_theme().
  325. // It is a issue with _system_theme_data() that returns its own cache
  326. // variable and can be modififed by others. When this is fixed in
  327. // drupal core we can remove this unset.
  328. // For reference see: http://drupal.org/node/762754
  329. $themes = _system_theme_data();
  330. foreach ($themes as $theme) {
  331. unset($theme->status);
  332. }
  333. drush_get_extensions();
  334. include_once './includes/batch.inc';
  335. drupal_load_updates();
  336. // Disable anything in the {system} table that is not compatible with the current version of Drupal core.
  337. _drush_log_update_sql(update_fix_compatibility());
  338. }
  339. function update_main() {
  340. update_main_prepare();
  341. list($pending, $start) = updatedb_status();
  342. // Print a list of pending updates for this module and get confirmation.
  343. if ($pending) {
  344. // @todo get table header working
  345. // array_unshift($pending, array(dt('Module'), dt('ID'), dt('Description')));
  346. drush_print_table($pending, FALSE);
  347. if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
  348. return drush_user_abort();
  349. }
  350. // Proceed with running all pending updates.
  351. $operations = array();
  352. foreach ($start as $module => $version) {
  353. drupal_set_installed_schema_version($module, $version - 1);
  354. $updates = drupal_get_schema_versions($module);
  355. $max_version = max($updates);
  356. if ($version <= $max_version) {
  357. drush_log(dt('Updating module @module from schema version @start to schema version @max', array('@module' => $module, '@start' => $version - 1, '@max' => $max_version)));
  358. foreach ($updates as $update) {
  359. if ($update >= $version) {
  360. $operations[] = array('_update_do_one', array($module, $update));
  361. }
  362. }
  363. }
  364. else {
  365. drush_log(dt('No database updates for module @module', array('@module' => $module)), 'success');
  366. }
  367. }
  368. $batch = array(
  369. 'operations' => $operations,
  370. 'title' => 'Updating',
  371. 'init_message' => 'Starting updates',
  372. '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.',
  373. 'finished' => 'update_finished',
  374. );
  375. batch_set($batch);
  376. $batch =& batch_get();
  377. $batch['progressive'] = FALSE;
  378. drush_backend_batch_process('updatedb-batch-process');
  379. }
  380. else {
  381. drush_log(dt("No database updates required"), 'success');
  382. }
  383. }
  384. /**
  385. * A simplified version of the batch_do_one function from update.php
  386. *
  387. * This does not mess with sessions and the like, as it will be used
  388. * from the command line
  389. */
  390. function _update_do_one($module, $number, &$context) {
  391. // If updates for this module have been aborted
  392. // in a previous step, go no further.
  393. if (!empty($context['results'][$module]['#abort'])) {
  394. return;
  395. }
  396. $function = $module .'_update_'. $number;
  397. drush_log("Executing $function", 'success');
  398. if (function_exists($function)) {
  399. $ret = $function($context['sandbox']);
  400. $context['results'][$module] = $ret;
  401. _drush_log_update_sql($ret);
  402. }
  403. if (isset($ret['#finished'])) {
  404. $context['finished'] = $ret['#finished'];
  405. unset($ret['#finished']);
  406. }
  407. if ($context['finished'] == 1 && empty($context['results'][$module]['#abort'])) {
  408. drupal_set_installed_schema_version($module, $number);
  409. }
  410. }
  411. function _update_batch_command($id) {
  412. update_main_prepare();
  413. drush_batch_command($id);
  414. }
  415. /**
  416. * Return a 2 item array with
  417. * - an array where each item is a 3 item associative array describing a pending update.
  418. * - an array listing the first update to run, keyed by module.
  419. */
  420. function updatedb_status() {
  421. $return = array();
  422. $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE);
  423. foreach ($modules as $module => $schema_version) {
  424. $updates = drupal_get_schema_versions($module);
  425. // Skip incompatible module updates completely, otherwise test schema versions.
  426. if (!update_check_incompatibility($module) && $updates !== FALSE && $schema_version >= 0) {
  427. // module_invoke returns NULL for nonexisting hooks, so if no updates
  428. // are removed, it will == 0.
  429. $last_removed = module_invoke($module, 'update_last_removed');
  430. if ($schema_version < $last_removed) {
  431. drush_set_error('PROVISION_DRUPAL_UPDATE_FAILED', dt( $module .' 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 '. $module .' module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.'));
  432. continue;
  433. }
  434. $updates = drupal_map_assoc($updates);
  435. // Record the starting update number for each module.
  436. foreach (array_keys($updates) as $update) {
  437. if ($update > $schema_version) {
  438. $start[$module] = $update;
  439. break;
  440. }
  441. }
  442. if (isset($start['system'])) {
  443. // Ensure system module's updates run first.
  444. $start = array('system' => $start['system']) + $start;
  445. }
  446. // Record any pending updates. Used for confirmation prompt.
  447. foreach (array_keys($updates) as $update) {
  448. if ($update > $schema_version) {
  449. if (class_exists('ReflectionFunction')) {
  450. // The description for an update comes from its Doxygen.
  451. $func = new ReflectionFunction($module. '_update_'. $update);
  452. $description = trim(str_replace(array("\n", '*', '/'), '', $func->getDocComment()));
  453. }
  454. if (empty($description)) {
  455. $description = dt('description not available');
  456. }
  457. $return[] = array('module' => ucfirst($module), 'update_id' => $update, 'description' => $description);
  458. }
  459. }
  460. }
  461. }
  462. return array($return, $start);
  463. }