Imported drupal-5.5
[drupal.git] / update.php
blob3b8eb560dff5ec3dba0544ef1ebb24bcf0f08bb7
1 <?php
2 // $Id: update.php,v 1.211.2.2 2007/04/08 00:54:04 drumm Exp $
4 /**
5 * @file
6 * Administrative page for handling updates from one Drupal version to another.
8 * Point your browser to "http://www.example.com/update.php" and follow the
9 * instructions.
11 * If you are not logged in as administrator, you will need to modify the access
12 * check statement below. Change the TRUE to a FALSE to disable the access
13 * check. After finishing the upgrade, be sure to open this file and change the
14 * FALSE back to a TRUE!
17 // Enforce access checking?
18 $access_check = TRUE;
21 function update_sql($sql) {
22 $result = db_query($sql);
23 return array('success' => $result !== FALSE, 'query' => check_plain($sql));
26 /**
27 * Add a column to a database using syntax appropriate for PostgreSQL.
28 * Save result of SQL commands in $ret array.
30 * Note: when you add a column with NOT NULL and you are not sure if there are
31 * already rows in the table, you MUST also add DEFAULT. Otherwise PostgreSQL
32 * won't work when the table is not empty, and db_add_column() will fail.
33 * To have an empty string as the default, you must use: 'default' => "''"
34 * in the $attributes array. If NOT NULL and DEFAULT are set the PostgreSQL
35 * version will set values of the added column in old rows to the
36 * DEFAULT value.
38 * @param $ret
39 * Array to which results will be added.
40 * @param $table
41 * Name of the table, without {}
42 * @param $column
43 * Name of the column
44 * @param $type
45 * Type of column
46 * @param $attributes
47 * Additional optional attributes. Recognized attributes:
48 * not null => TRUE|FALSE
49 * default => NULL|FALSE|value (the value must be enclosed in '' marks)
50 * @return
51 * nothing, but modifies $ret parameter.
53 function db_add_column(&$ret, $table, $column, $type, $attributes = array()) {
54 if (array_key_exists('not null', $attributes) and $attributes['not null']) {
55 $not_null = 'NOT NULL';
57 if (array_key_exists('default', $attributes)) {
58 if (is_null($attributes['default'])) {
59 $default_val = 'NULL';
60 $default = 'default NULL';
62 elseif ($attributes['default'] === FALSE) {
63 $default = '';
65 else {
66 $default_val = "$attributes[default]";
67 $default = "default $attributes[default]";
71 $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column $type");
72 if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default"); }
73 if ($not_null) {
74 if ($default) { $ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val"); }
75 $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET NOT NULL");
79 /**
80 * Change a column definition using syntax appropriate for PostgreSQL.
81 * Save result of SQL commands in $ret array.
83 * Remember that changing a column definition involves adding a new column
84 * and dropping an old one. This means that any indices, primary keys and
85 * sequences from serial-type columns are dropped and might need to be
86 * recreated.
88 * @param $ret
89 * Array to which results will be added.
90 * @param $table
91 * Name of the table, without {}
92 * @param $column
93 * Name of the column to change
94 * @param $column_new
95 * New name for the column (set to the same as $column if you don't want to change the name)
96 * @param $type
97 * Type of column
98 * @param $attributes
99 * Additional optional attributes. Recognized attributes:
100 * not null => TRUE|FALSE
101 * default => NULL|FALSE|value (with or without '', it won't be added)
102 * @return
103 * nothing, but modifies $ret parameter.
105 function db_change_column(&$ret, $table, $column, $column_new, $type, $attributes = array()) {
106 if (array_key_exists('not null', $attributes) and $attributes['not null']) {
107 $not_null = 'NOT NULL';
109 if (array_key_exists('default', $attributes)) {
110 if (is_null($attributes['default'])) {
111 $default_val = 'NULL';
112 $default = 'default NULL';
114 elseif ($attributes['default'] === FALSE) {
115 $default = '';
117 else {
118 $default_val = "$attributes[default]";
119 $default = "default $attributes[default]";
123 $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME $column TO ". $column ."_old");
124 $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column_new $type");
125 $ret[] = update_sql("UPDATE {". $table ."} SET $column_new = ". $column ."_old");
126 if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET $default"); }
127 if ($not_null) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET NOT NULL"); }
128 $ret[] = update_sql("ALTER TABLE {". $table ."} DROP ". $column ."_old");
132 * If the schema version for Drupal core is stored in the variables table
133 * (4.6.x and earlier) move it to the schema_version column of the system
134 * table.
136 * This function may be removed when update 156 is removed, which is the last
137 * update in the 4.6 to 4.7 migration.
139 function update_fix_schema_version() {
140 if ($update_start = variable_get('update_start', FALSE)) {
141 // Some updates were made to the 4.6 branch and 4.7 branch. This sets
142 // temporary variables to prevent the updates from being executed twice and
143 // throwing errors.
144 switch ($update_start) {
145 case '2005-04-14':
146 variable_set('update_132_done', TRUE);
147 break;
149 case '2005-05-06':
150 variable_set('update_132_done', TRUE);
151 variable_set('update_135_done', TRUE);
152 break;
154 case '2005-05-07':
155 variable_set('update_132_done', TRUE);
156 variable_set('update_135_done', TRUE);
157 variable_set('update_137_done', TRUE);
158 break;
161 // The schema_version column (added below) was changed during 4.7beta.
162 // Update_170 is only for those beta users.
163 variable_set('update_170_done', TRUE);
165 $sql_updates = array(
166 '2004-10-31: first update since Drupal 4.5.0 release' => 110,
167 '2004-11-07' => 111, '2004-11-15' => 112, '2004-11-28' => 113,
168 '2004-12-05' => 114, '2005-01-07' => 115, '2005-01-14' => 116,
169 '2005-01-18' => 117, '2005-01-19' => 118, '2005-01-20' => 119,
170 '2005-01-25' => 120, '2005-01-26' => 121, '2005-01-27' => 122,
171 '2005-01-28' => 123, '2005-02-11' => 124, '2005-02-23' => 125,
172 '2005-03-03' => 126, '2005-03-18' => 127, '2005-03-21' => 128,
173 // The following three updates were made on the 4.6 branch
174 '2005-04-14' => 128, '2005-05-06' => 128, '2005-05-07' => 128,
175 '2005-04-08: first update since Drupal 4.6.0 release' => 129,
176 '2005-04-10' => 130, '2005-04-11' => 131, '2005-04-14' => 132,
177 '2005-04-24' => 133, '2005-04-30' => 134, '2005-05-06' => 135,
178 '2005-05-08' => 136, '2005-05-09' => 137, '2005-05-10' => 138,
179 '2005-05-11' => 139, '2005-05-12' => 140, '2005-05-22' => 141,
180 '2005-07-29' => 142, '2005-07-30' => 143, '2005-08-08' => 144,
181 '2005-08-15' => 145, '2005-08-25' => 146, '2005-09-07' => 147,
182 '2005-09-18' => 148, '2005-09-27' => 149, '2005-10-15' => 150,
183 '2005-10-23' => 151, '2005-10-28' => 152, '2005-11-03' => 153,
184 '2005-11-14' => 154, '2005-11-27' => 155, '2005-12-03' => 156,
187 // Add schema version column
188 switch ($GLOBALS['db_type']) {
189 case 'pgsql':
190 $ret = array();
191 db_add_column($ret, 'system', 'schema_version', 'smallint', array('not null' => TRUE, 'default' => -1));
192 break;
194 case 'mysql':
195 case 'mysqli':
196 db_query('ALTER TABLE {system} ADD schema_version smallint(3) not null default -1');
197 break;
199 // Set all enabled (contrib) modules to schema version 0 (installed)
200 db_query('UPDATE {system} SET schema_version = 0 WHERE status = 1');
202 // Set schema version for core
203 drupal_set_installed_schema_version('system', $sql_updates[$update_start]);
204 variable_del('update_start');
209 * System update 130 changes the sessions table, which breaks the update
210 * script's ability to use session variables. This changes the table
211 * appropriately.
213 * This code, including the 'update_sessions_fixed' variable, may be removed
214 * when update 130 is removed. It is part of the Drupal 4.6 to 4.7 migration.
216 function update_fix_sessions() {
217 $ret = array();
219 if (drupal_get_installed_schema_version('system') < 130 && !variable_get('update_sessions_fixed', FALSE)) {
220 if ($GLOBALS['db_type'] == 'mysql') {
221 db_query("ALTER TABLE {sessions} ADD cache int(11) NOT NULL default '0' AFTER timestamp");
223 elseif ($GLOBALS['db_type'] == 'pgsql') {
224 db_add_column($ret, 'sessions', 'cache', 'int', array('default' => 0, 'not null' => TRUE));
227 variable_set('update_sessions_fixed', TRUE);
232 * System update 115 changes the watchdog table, which breaks the update
233 * script's ability to use logging. This changes the table appropriately.
235 * This code, including the 'update_watchdog_115_fixed' variable, may be removed
236 * when update 115 is removed. It is part of the Drupal 4.5 to 4.7 migration.
238 function update_fix_watchdog_115() {
239 if (drupal_get_installed_schema_version('system') < 115 && !variable_get('update_watchdog_115_fixed', FALSE)) {
240 if ($GLOBALS['db_type'] == 'mysql') {
241 $ret[] = update_sql("ALTER TABLE {watchdog} ADD severity tinyint(3) unsigned NOT NULL default '0'");
243 else if ($GLOBALS['db_type'] == 'pgsql') {
244 $ret[] = update_sql('ALTER TABLE {watchdog} ADD severity smallint');
245 $ret[] = update_sql('UPDATE {watchdog} SET severity = 0');
246 $ret[] = update_sql('ALTER TABLE {watchdog} ALTER COLUMN severity SET NOT NULL');
247 $ret[] = update_sql('ALTER TABLE {watchdog} ALTER COLUMN severity SET DEFAULT 0');
250 variable_set('update_watchdog_115_fixed', TRUE);
255 * System update 142 changes the watchdog table, which breaks the update
256 * script's ability to use logging. This changes the table appropriately.
258 * This code, including the 'update_watchdog_fixed' variable, may be removed
259 * when update 142 is removed. It is part of the Drupal 4.6 to 4.7 migration.
261 function update_fix_watchdog() {
262 if (drupal_get_installed_schema_version('system') < 142 && !variable_get('update_watchdog_fixed', FALSE)) {
263 switch ($GLOBALS['db_type']) {
264 case 'pgsql':
265 $ret = array();
266 db_add_column($ret, 'watchdog', 'referer', 'varchar(128)', array('not null' => TRUE, 'default' => "''"));
267 break;
268 case 'mysql':
269 case 'mysqli':
270 db_query("ALTER TABLE {watchdog} ADD COLUMN referer varchar(128) NOT NULL");
271 break;
274 variable_set('update_watchdog_fixed', TRUE);
279 * Perform one update and store the results which will later be displayed on
280 * the finished page.
282 * @param $module
283 * The module whose update will be run.
284 * @param $number
285 * The update number to run.
287 * @return
288 * TRUE if the update was finished. Otherwise, FALSE.
290 function update_data($module, $number) {
291 $ret = module_invoke($module, 'update_'. $number);
292 // Assume the update finished unless the update results indicate otherwise.
293 $finished = 1;
294 if (isset($ret['#finished'])) {
295 $finished = $ret['#finished'];
296 unset($ret['#finished']);
299 // Save the query and results for display by update_finished_page().
300 if (!isset($_SESSION['update_results'])) {
301 $_SESSION['update_results'] = array();
303 if (!isset($_SESSION['update_results'][$module])) {
304 $_SESSION['update_results'][$module] = array();
306 if (!isset($_SESSION['update_results'][$module][$number])) {
307 $_SESSION['update_results'][$module][$number] = array();
309 $_SESSION['update_results'][$module][$number] = array_merge($_SESSION['update_results'][$module][$number], $ret);
311 if ($finished == 1) {
312 // Update the installed version
313 drupal_set_installed_schema_version($module, $number);
316 return $finished;
319 function update_selection_page() {
320 $output = '<p>The version of Drupal you are updating from has been automatically detected. You can select a different version, but you should not need to.</p>';
321 $output .= '<p>Click Update to start the update process.</p>';
323 drupal_set_title('Drupal database update');
324 // Prevent browser from using cached drupal.js or update.js
325 drupal_add_js('misc/update.js', 'core', 'header', FALSE, TRUE);
326 $output .= drupal_get_form('update_script_selection_form');
328 return $output;
331 function update_script_selection_form() {
332 $form = array();
333 $form['start'] = array(
334 '#tree' => TRUE,
335 '#type' => 'fieldset',
336 '#title' => 'Select versions',
337 '#collapsible' => TRUE,
338 '#collapsed' => TRUE,
341 // Ensure system.module's updates appear first
342 $form['start']['system'] = array();
344 foreach (module_list() as $module) {
345 $updates = drupal_get_schema_versions($module);
346 if ($updates !== FALSE) {
347 $updates = drupal_map_assoc($updates);
348 $updates[] = 'No updates available';
349 $default = drupal_get_installed_schema_version($module);
350 foreach (array_keys($updates) as $update) {
351 if ($update > $default) {
352 $default = $update;
353 break;
357 $form['start'][$module] = array(
358 '#type' => 'select',
359 '#title' => $module . ' module',
360 '#default_value' => $default,
361 '#options' => $updates,
366 $form['has_js'] = array(
367 '#type' => 'hidden',
368 '#default_value' => FALSE,
369 '#attributes' => array('id' => 'edit-has_js'),
371 $form['submit'] = array(
372 '#type' => 'submit',
373 '#value' => 'Update',
375 return $form;
378 function update_update_page() {
379 // Set the installed version so updates start at the correct place.
380 foreach ($_POST['start'] as $module => $version) {
381 drupal_set_installed_schema_version($module, $version - 1);
382 $updates = drupal_get_schema_versions($module);
383 $max_version = max($updates);
384 if ($version <= $max_version) {
385 foreach ($updates as $update) {
386 if ($update >= $version) {
387 $_SESSION['update_remaining'][] = array('module' => $module, 'version' => $update);
393 // Keep track of total number of updates
394 if (isset($_SESSION['update_remaining'])) {
395 $_SESSION['update_total'] = count($_SESSION['update_remaining']);
398 if ($_POST['has_js']) {
399 return update_progress_page();
401 else {
402 return update_progress_page_nojs();
406 function update_progress_page() {
407 // Prevent browser from using cached drupal.js or update.js
408 drupal_add_js('misc/progress.js', 'core', 'header', FALSE, TRUE);
409 drupal_add_js('misc/update.js', 'core', 'header', FALSE, TRUE);
411 drupal_set_title('Updating');
412 $output = '<div id="progress"></div>';
413 $output .= '<p id="wait">Please wait while your site is being updated.</p>';
414 return $output;
418 * Perform updates for one second or until finished.
420 * @return
421 * An array indicating the status after doing updates. The first element is
422 * the overall percentage finished. The second element is a status message.
424 function update_do_updates() {
425 while (isset($_SESSION['update_remaining']) && ($update = reset($_SESSION['update_remaining']))) {
426 $update_finished = update_data($update['module'], $update['version']);
427 if ($update_finished == 1) {
428 // Dequeue the completed update.
429 unset($_SESSION['update_remaining'][key($_SESSION['update_remaining'])]);
430 $update_finished = 0; // Make sure this step isn't counted double
432 if (timer_read('page') > 1000) {
433 break;
437 if ($_SESSION['update_total']) {
438 $percentage = floor(($_SESSION['update_total'] - count($_SESSION['update_remaining']) + $update_finished) / $_SESSION['update_total'] * 100);
440 else {
441 $percentage = 100;
444 // When no updates remain, clear the caches in case the data has been updated.
445 if (!isset($update['module'])) {
446 cache_clear_all('*', 'cache', TRUE);
447 cache_clear_all('*', 'cache_page', TRUE);
448 cache_clear_all('*', 'cache_menu', TRUE);
449 cache_clear_all('*', 'cache_filter', TRUE);
450 drupal_clear_css_cache();
453 return array($percentage, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete');
457 * Perform updates for the JS version and return progress.
459 function update_do_update_page() {
460 global $conf;
462 // HTTP Post required
463 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
464 drupal_set_message('HTTP Post is required.', 'error');
465 drupal_set_title('Error');
466 return '';
469 // Error handling: if PHP dies, the output will fail to parse as JSON, and
470 // the Javascript will tell the user to continue to the op=error page.
471 list($percentage, $message) = update_do_updates();
472 print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
476 * Perform updates for the non-JS version and return the status page.
478 function update_progress_page_nojs() {
479 drupal_set_title('Updating');
481 $new_op = 'do_update_nojs';
482 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
483 // Error handling: if PHP dies, it will output whatever is in the output
484 // buffer, followed by the error message.
485 ob_start();
486 $fallback = '<p class="error">An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference. Please continue to the <a href="update.php?op=error">update summary</a>.</p>';
487 print theme('maintenance_page', $fallback, FALSE, TRUE);
489 list($percentage, $message) = update_do_updates();
490 if ($percentage == 100) {
491 $new_op = 'finished';
494 // Updates successful; remove fallback
495 ob_end_clean();
497 else {
498 // This is the first page so return some output immediately.
499 $percentage = 0;
500 $message = 'Starting updates';
503 drupal_set_html_head('<meta http-equiv="Refresh" content="0; URL=update.php?op='. $new_op .'">');
504 $output = theme('progress_bar', $percentage, $message);
505 $output .= '<p>Updating your site will take a few seconds.</p>';
507 // Note: do not output drupal_set_message()s until the summary page.
508 print theme('maintenance_page', $output, FALSE);
509 return NULL;
512 function update_finished_page($success) {
513 drupal_set_title('Drupal database update');
514 // NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
515 $links[] = '<a href="'. base_path() .'">Main page</a>';
516 $links[] = '<a href="'. base_path() .'?q=admin">Administration pages</a>';
518 // Report end result
519 if ($success) {
520 $output = '<p>Updates were attempted. If you see no failures below, you may proceed happily to the <a href="index.php?q=admin">administration pages</a>. Otherwise, you may need to update your database manually. All errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>.</p>';
522 else {
523 $update = reset($_SESSION['update_remaining']);
524 $output = '<p class="error">The update process was aborted prematurely while running <strong>update #'. $update['version'] .' in '. $update['module'] .'.module</strong>. All other errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>. You may need to check the <code>watchdog</code> database table manually.</p>';
527 if ($GLOBALS['access_check'] == FALSE) {
528 $output .= "<p><strong>Reminder: don't forget to set the <code>\$access_check</code> value at the top of <code>update.php</code> back to <code>TRUE</code>.</strong></p>";
531 $output .= theme('item_list', $links);
533 // Output a list of queries executed
534 if (!empty($_SESSION['update_results'])) {
535 $output .= '<div id="update-results">';
536 $output .= '<h2>The following queries were executed</h2>';
537 foreach ($_SESSION['update_results'] as $module => $updates) {
538 $output .= '<h3>'. $module .' module</h3>';
539 foreach ($updates as $number => $queries) {
540 $output .= '<h4>Update #'. $number .'</h4>';
541 $output .= '<ul>';
542 foreach ($queries as $query) {
543 if ($query['success']) {
544 $output .= '<li class="success">'. $query['query'] .'</li>';
546 else {
547 $output .= '<li class="failure"><strong>Failed:</strong> '. $query['query'] .'</li>';
550 if (!count($queries)) {
551 $output .= '<li class="none">No queries</li>';
553 $output .= '</ul>';
556 $output .= '</div>';
557 unset($_SESSION['update_results']);
560 return $output;
563 function update_info_page() {
564 drupal_set_title('Drupal database update');
565 $output = "<ol>\n";
566 $output .= "<li>Use this script to <strong>upgrade an existing Drupal installation</strong>. You don't need this script when installing Drupal from scratch.</li>";
567 $output .= "<li>Before doing anything, backup your database. This process will change your database and its values, and some things might get lost.</li>\n";
568 $output .= "<li>Update your Drupal sources, check the notes below and <a href=\"update.php?op=selection\">run the database upgrade script</a>. Don't upgrade your database twice as it may cause problems.</li>\n";
569 $output .= "<li>Go through the various administration pages to change the existing and new settings to your liking.</li>\n";
570 $output .= "</ol>";
571 $output .= '<p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>';
572 return $output;
575 function update_access_denied_page() {
576 drupal_set_title('Access denied');
577 return '<p>Access denied. You are not authorized to access this page. Please log in as the admin user (the first user you created). If you cannot log in, you will have to edit <code>update.php</code> to bypass this access check. To do this:</p>
578 <ol>
579 <li>With a text editor find the update.php file on your system. It should be in the main Drupal directory that you installed all the files into.</li>
580 <li>There is a line near top of update.php that says <code>$access_check = TRUE;</code>. Change it to <code>$access_check = FALSE;</code>.</li>
581 <li>As soon as the script is done, you must change the update.php script back to its original form to <code>$access_check = TRUE;</code>.</li>
582 <li>To avoid having this problem in future, remember to log in to your website as the admin user (the user you first created) before you backup your database at the beginning of the update process.</li>
583 </ol>';
586 // This code may be removed later. It is part of the Drupal 4.5 to 4.8 migration.
587 function update_fix_system_table() {
588 drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
589 $core_modules = array('aggregator', 'archive', 'block', 'blog', 'blogapi', 'book', 'comment', 'contact', 'drupal', 'filter', 'forum', 'help', 'legacy', 'locale', 'menu', 'node', 'page', 'path', 'ping', 'poll', 'profile', 'search', 'statistics', 'story', 'system', 'taxonomy', 'throttle', 'tracker', 'upload', 'user', 'watchdog');
590 foreach ($core_modules as $module) {
591 $old_path = "modules/$module.module";
592 $new_path = "modules/$module/$module.module";
593 db_query("UPDATE {system} SET filename = '%s' WHERE filename = '%s'", $new_path, $old_path);
595 $row = db_fetch_object(db_query_range('SELECT * FROM {system}', 0, 1));
596 if (!isset($row->weight)) {
597 $ret = array();
598 switch ($GLOBALS['db_type']) {
599 case 'pgsql':
600 db_add_column($ret, 'system', 'weight', 'smallint', array('not null' => TRUE, 'default' => 0));
601 $ret[] = update_sql('CREATE INDEX {system}_weight_idx ON {system} (weight)');
602 break;
603 case 'mysql':
604 case 'mysqli':
605 $ret[] = update_sql("ALTER TABLE {system} ADD weight tinyint(2) default '0' NOT NULL, ADD KEY (weight)");
606 break;
611 // This code may be removed later. It is part of the Drupal 4.6 to 4.7 migration.
612 function update_fix_access_table() {
613 if (variable_get('update_access_fixed', FALSE)) {
614 return;
617 switch ($GLOBALS['db_type']) {
618 // Only for MySQL 4.1+
619 case 'mysqli':
620 break;
621 case 'mysql':
622 if (version_compare(mysql_get_server_info($GLOBALS['active_db']), '4.1.0', '<')) {
623 return;
625 break;
626 case 'pgsql':
627 return;
630 // Convert access table to UTF-8 if needed.
631 $result = db_fetch_array(db_query('SHOW CREATE TABLE {access}'));
632 if (!preg_match('/utf8/i', array_pop($result))) {
633 update_convert_table_utf8('access');
636 // Don't run again
637 variable_set('update_access_fixed', TRUE);
641 * Convert a single MySQL table to UTF-8.
643 * We change all text columns to their corresponding binary type,
644 * then back to text, but with a UTF-8 character set.
645 * See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html
647 function update_convert_table_utf8($table) {
648 $ret = array();
649 $types = array('char' => 'binary',
650 'varchar' => 'varbinary',
651 'tinytext' => 'tinyblob',
652 'text' => 'blob',
653 'mediumtext' => 'mediumblob',
654 'longtext' => 'longblob');
656 // Get next table in list
657 $convert_to_binary = array();
658 $convert_to_utf8 = array();
660 // Set table default charset
661 $ret[] = update_sql('ALTER TABLE {'. $table .'} DEFAULT CHARACTER SET utf8');
663 // Find out which columns need converting and build SQL statements
664 $result = db_query('SHOW FULL COLUMNS FROM {'. $table .'}');
665 while ($column = db_fetch_array($result)) {
666 list($type) = explode('(', $column['Type']);
667 if (isset($types[$type])) {
668 $names = 'CHANGE `'. $column['Field'] .'` `'. $column['Field'] .'` ';
669 $attributes = ' DEFAULT '. ($column['Default'] == 'NULL' ? 'NULL ' :
670 "'". db_escape_string($column['Default']) ."' ") .
671 ($column['Null'] == 'YES' ? 'NULL' : 'NOT NULL');
673 $convert_to_binary[] = $names . preg_replace('/'. $type .'/i', $types[$type], $column['Type']) . $attributes;
674 $convert_to_utf8[] = $names . $column['Type'] .' CHARACTER SET utf8'. $attributes;
678 if (count($convert_to_binary)) {
679 // Convert text columns to binary
680 $ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_binary));
681 // Convert binary columns to UTF-8
682 $ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_utf8));
684 return $ret;
688 * Create tables for the split cache.
690 * This is part of the Drupal 4.7.x to 5.x migration.
692 function update_create_cache_tables() {
694 // If cache_filter exists, update is not necessary
695 if (db_table_exists('cache_filter')) {
696 return;
699 $ret = array();
700 switch ($GLOBALS['db_type']) {
701 case 'mysql':
702 case 'mysqli':
703 $ret[] = update_sql("CREATE TABLE {cache_filter} (
704 cid varchar(255) NOT NULL default '',
705 data longblob,
706 expire int NOT NULL default '0',
707 created int NOT NULL default '0',
708 headers text,
709 PRIMARY KEY (cid),
710 INDEX expire (expire)
711 ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
712 $ret[] = update_sql("CREATE TABLE {cache_menu} (
713 cid varchar(255) NOT NULL default '',
714 data longblob,
715 expire int NOT NULL default '0',
716 created int NOT NULL default '0',
717 headers text,
718 PRIMARY KEY (cid),
719 INDEX expire (expire)
720 ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
721 $ret[] = update_sql("CREATE TABLE {cache_page} (
722 cid varchar(255) BINARY NOT NULL default '',
723 data longblob,
724 expire int NOT NULL default '0',
725 created int NOT NULL default '0',
726 headers text,
727 PRIMARY KEY (cid),
728 INDEX expire (expire)
729 ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
730 break;
731 case 'pgsql':
732 $ret[] = update_sql("CREATE TABLE {cache_filter} (
733 cid varchar(255) NOT NULL default '',
734 data bytea,
735 expire int NOT NULL default '0',
736 created int NOT NULL default '0',
737 headers text,
738 PRIMARY KEY (cid)
739 )");
740 $ret[] = update_sql("CREATE TABLE {cache_menu} (
741 cid varchar(255) NOT NULL default '',
742 data bytea,
743 expire int NOT NULL default '0',
744 created int NOT NULL default '0',
745 headers text,
746 PRIMARY KEY (cid)
747 )");
748 $ret[] = update_sql("CREATE TABLE {cache_page} (
749 cid varchar(255) NOT NULL default '',
750 data bytea,
751 expire int NOT NULL default '0',
752 created int NOT NULL default '0',
753 headers text,
754 PRIMARY KEY (cid)
755 )");
756 $ret[] = update_sql("CREATE INDEX {cache_filter}_expire_idx ON {cache_filter} (expire)");
757 $ret[] = update_sql("CREATE INDEX {cache_menu}_expire_idx ON {cache_menu} (expire)");
758 $ret[] = update_sql("CREATE INDEX {cache_page}_expire_idx ON {cache_page} (expire)");
759 break;
761 return $ret;
764 // Some unavoidable errors happen because the database is not yet up-to-date.
765 // Our custom error handler is not yet installed, so we just suppress them.
766 ini_set('display_errors', FALSE);
768 include_once './includes/bootstrap.inc';
769 update_fix_system_table();
771 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
772 drupal_maintenance_theme();
774 // This must happen *after* drupal_bootstrap(), since it calls
775 // variable_(get|set), which only works after a full bootstrap.
776 update_fix_access_table();
777 update_create_cache_tables();
779 // Turn error reporting back on. From now on, only fatal errors (which are
780 // not passed through the error handler) will cause a message to be printed.
781 ini_set('display_errors', TRUE);
783 // Access check:
784 if (($access_check == FALSE) || ($user->uid == 1)) {
786 include_once './includes/install.inc';
787 drupal_load_updates();
789 update_fix_schema_version();
790 update_fix_watchdog_115();
791 update_fix_watchdog();
792 update_fix_sessions();
794 $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
795 switch ($op) {
796 case 'Update':
797 $output = update_update_page();
798 break;
800 case 'finished':
801 $output = update_finished_page(TRUE);
802 break;
804 case 'error':
805 $output = update_finished_page(FALSE);
806 break;
808 case 'do_update':
809 $output = update_do_update_page();
810 break;
812 case 'do_update_nojs':
813 $output = update_progress_page_nojs();
814 break;
816 case 'selection':
817 $output = update_selection_page();
818 break;
820 default:
821 $output = update_info_page();
822 break;
825 else {
826 $output = update_access_denied_page();
829 if (isset($output)) {
830 print theme('maintenance_page', $output);