- #49501: Improve error reporting in the update system
parent
9a014043a4
commit
3f2b287d7c
|
@ -1458,8 +1458,9 @@ function system_update_169() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: 'access' table manually updated in update.php
|
||||||
return _system_update_utf8(array(
|
return _system_update_utf8(array(
|
||||||
'access', 'accesslog', 'aggregator_category',
|
'accesslog', 'aggregator_category',
|
||||||
'aggregator_category_feed', 'aggregator_category_item',
|
'aggregator_category_feed', 'aggregator_category_item',
|
||||||
'aggregator_feed', 'aggregator_item', 'authmap', 'blocks',
|
'aggregator_feed', 'aggregator_item', 'authmap', 'blocks',
|
||||||
'book', 'boxes', 'cache', 'comments', 'contact',
|
'book', 'boxes', 'cache', 'comments', 'contact',
|
||||||
|
@ -1477,7 +1478,7 @@ function system_update_169() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts tables to UTF-8 encoding.
|
* Converts a set of tables to UTF-8 encoding.
|
||||||
*
|
*
|
||||||
* This update is designed to be re-usable by contrib modules and is
|
* This update is designed to be re-usable by contrib modules and is
|
||||||
* used by system_update_169().
|
* used by system_update_169().
|
||||||
|
@ -1513,51 +1514,11 @@ function _system_update_utf8($tables) {
|
||||||
$_SESSION['update_utf8_total'] = count($tables);
|
$_SESSION['update_utf8_total'] = count($tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch remaining tables list
|
// Fetch remaining tables list and convert next table
|
||||||
$list = &$_SESSION['update_utf8'];
|
$list = &$_SESSION['update_utf8'];
|
||||||
$ret = array();
|
|
||||||
|
|
||||||
// Convert a table to UTF-8.
|
|
||||||
// We change all text columns to their correspending binary type,
|
|
||||||
// then back to text, but with a UTF-8 character set.
|
|
||||||
// See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html
|
|
||||||
$types = array('char' => 'binary',
|
|
||||||
'varchar' => 'varbinary',
|
|
||||||
'tinytext' => 'tinyblob',
|
|
||||||
'text' => 'blob',
|
|
||||||
'mediumtext' => 'mediumblob',
|
|
||||||
'longtext' => 'longblob');
|
|
||||||
|
|
||||||
// Get next table in list
|
|
||||||
$table = array_shift($list);
|
|
||||||
$convert_to_binary = array();
|
|
||||||
$convert_to_utf8 = array();
|
|
||||||
|
|
||||||
// Set table default charset
|
|
||||||
$ret[] = update_sql('ALTER TABLE {'. $table .'} DEFAULT CHARACTER SET utf8');
|
|
||||||
|
|
||||||
// Find out which columns need converting and build SQL statements
|
|
||||||
$result = db_query('SHOW FULL COLUMNS FROM {'. $table .'}');
|
|
||||||
while ($column = db_fetch_array($result)) {
|
|
||||||
list($type) = explode('(', $column['Type']);
|
|
||||||
if (isset($types[$type])) {
|
|
||||||
$names = 'CHANGE `'. $column['Field'] .'` `'. $column['Field'] .'` ';
|
|
||||||
$attributes = ' DEFAULT '. ($column['Default'] == 'NULL' ? 'NULL ' :
|
|
||||||
"'". db_escape_string($column['Default']) ."' ") .
|
|
||||||
($column['Null'] == 'YES' ? 'NULL' : 'NOT NULL');
|
|
||||||
|
|
||||||
$convert_to_binary[] = $names . preg_replace('/'. $type .'/i', $types[$type], $column['Type']) . $attributes;
|
|
||||||
$convert_to_utf8[] = $names . $column['Type'] .' CHARACTER SET utf8'. $attributes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($convert_to_binary)) {
|
|
||||||
// Convert text columns to binary
|
|
||||||
$ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_binary));
|
|
||||||
// Convert binary columns to UTF-8
|
|
||||||
$ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_utf8));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$ret = update_convert_table_utf8(array_shift($list));
|
||||||
|
|
||||||
// Are we done?
|
// Are we done?
|
||||||
if (count($list) == 0) {
|
if (count($list) == 0) {
|
||||||
unset($_SESSION['update_utf8']);
|
unset($_SESSION['update_utf8']);
|
||||||
|
|
|
@ -8,11 +8,12 @@
|
||||||
* e.g. pb = new progressBar('myProgressBar');
|
* e.g. pb = new progressBar('myProgressBar');
|
||||||
* some_element.appendChild(pb.element);
|
* some_element.appendChild(pb.element);
|
||||||
*/
|
*/
|
||||||
function progressBar(id, callback, method) {
|
function progressBar(id, updateCallback, method, errorCallback) {
|
||||||
var pb = this;
|
var pb = this;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.method = method ? method : HTTPGet;
|
this.method = method ? method : HTTPGet;
|
||||||
this.callback = callback;
|
this.updateCallback = updateCallback;
|
||||||
|
this.errorCallback = errorCallback;
|
||||||
|
|
||||||
this.element = document.createElement('div');
|
this.element = document.createElement('div');
|
||||||
this.element.id = id;
|
this.element.id = id;
|
||||||
|
@ -41,8 +42,8 @@ progressBar.prototype.setProgress = function (percentage, message) {
|
||||||
divs[i].innerHTML = message;
|
divs[i].innerHTML = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.callback) {
|
if (this.updateCallback) {
|
||||||
this.callback(percentage, message, this);
|
this.updateCallback(percentage, message, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,13 +83,13 @@ progressBar.prototype.sendPing = function () {
|
||||||
*/
|
*/
|
||||||
progressBar.prototype.receivePing = function (string, xmlhttp, pb) {
|
progressBar.prototype.receivePing = function (string, xmlhttp, pb) {
|
||||||
if (xmlhttp.status != 200) {
|
if (xmlhttp.status != 200) {
|
||||||
return alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
|
return pb.displayError('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
|
||||||
}
|
}
|
||||||
// Parse response
|
// Parse response
|
||||||
var progress = parseJson(string);
|
var progress = parseJson(string);
|
||||||
// Display errors
|
// Display errors
|
||||||
if (progress.status == 0) {
|
if (progress.status == 0) {
|
||||||
alert(progress.data);
|
pb.displayError(progress.data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,3 +98,19 @@ progressBar.prototype.receivePing = function (string, xmlhttp, pb) {
|
||||||
// Schedule next timer
|
// Schedule next timer
|
||||||
pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
|
pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display errors on the page.
|
||||||
|
*/
|
||||||
|
progressBar.prototype.displayError = function (string) {
|
||||||
|
var error = document.createElement('div');
|
||||||
|
error.className = 'error';
|
||||||
|
error.appendChild(document.createTextNode(string));
|
||||||
|
|
||||||
|
this.element.style.display = 'none';
|
||||||
|
this.element.parentNode.insertBefore(error, this.element);
|
||||||
|
|
||||||
|
if (this.errorCallback) {
|
||||||
|
this.errorCallback(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,11 @@ if (isJsEnabled()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var progress = new progressBar('updateprogress', updateCallback, HTTPPost);
|
errorCallback = function (pb) {
|
||||||
|
window.location = window.location.href.split('op=')[0] +'op=error';
|
||||||
|
}
|
||||||
|
|
||||||
|
var progress = new progressBar('updateprogress', updateCallback, HTTPPost, errorCallback);
|
||||||
progress.setProgress(-1, 'Starting updates');
|
progress.setProgress(-1, 'Starting updates');
|
||||||
$('progress').appendChild(progress.element);
|
$('progress').appendChild(progress.element);
|
||||||
progress.startMonitoring('update.php?op=do_update', 0);
|
progress.startMonitoring('update.php?op=do_update', 0);
|
||||||
|
|
119
update.php
119
update.php
|
@ -420,6 +420,9 @@ function update_do_updates() {
|
||||||
return array($percentage, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete');
|
return array($percentage, isset($update['module']) ? 'Updating '. $update['module'] .' module' : 'Updating complete');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform updates for the JS version and return progress.
|
||||||
|
*/
|
||||||
function update_do_update_page() {
|
function update_do_update_page() {
|
||||||
global $conf;
|
global $conf;
|
||||||
|
|
||||||
|
@ -430,24 +433,27 @@ function update_do_update_page() {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any errors which happen would cause the result to not be parsed properly,
|
|
||||||
// so we need to supporess them. All errors are still logged.
|
|
||||||
if (!isset($conf['error_level'])) {
|
|
||||||
$conf['error_level'] = 0;
|
|
||||||
}
|
|
||||||
ini_set('display_errors', FALSE);
|
|
||||||
|
|
||||||
list($percentage, $message) = update_do_updates();
|
list($percentage, $message) = update_do_updates();
|
||||||
print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
|
print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform updates for the non-JS version and return the status page.
|
||||||
|
*/
|
||||||
function update_progress_page_nojs() {
|
function update_progress_page_nojs() {
|
||||||
$new_op = 'do_update_nojs';
|
$new_op = 'do_update_nojs';
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||||
|
// Store a fallback redirect in case of a fatal PHP error
|
||||||
|
ob_start();
|
||||||
|
print '<html><head><meta http-equiv="Refresh" content="0; URL=update.php?op=error"></head></html>';
|
||||||
|
|
||||||
list($percentage, $message) = update_do_updates();
|
list($percentage, $message) = update_do_updates();
|
||||||
if ($percentage == 100) {
|
if ($percentage == 100) {
|
||||||
$new_op = 'finished';
|
$new_op = 'finished';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates succesful, remove fallback
|
||||||
|
ob_end_clean();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This is the first page so return some output immediately.
|
// This is the first page so return some output immediately.
|
||||||
|
@ -463,15 +469,23 @@ function update_progress_page_nojs() {
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_finished_page() {
|
function update_finished_page($success) {
|
||||||
drupal_set_title('Drupal database update');
|
drupal_set_title('Drupal database update');
|
||||||
// NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
|
// NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
|
||||||
$links[] = '<a href="'. base_path() .'">main page</a>';
|
$links[] = '<a href="'. base_path() .'">main page</a>';
|
||||||
$links[] = '<a href="'. base_path() .'?q=admin">administration pages</a>';
|
$links[] = '<a href="'. base_path() .'?q=admin">administration pages</a>';
|
||||||
$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">logged</a>.</p>';
|
|
||||||
|
if ($success) {
|
||||||
|
$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">logged</a>.</p>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$output = '<p class="error">The update process did not complete. All errors have been <a href="index.php?q=admin/logs">logged</a>. You may need to check the <code>watchdog</code> table manually.';
|
||||||
|
}
|
||||||
|
|
||||||
if ($GLOBALS['access_check'] == FALSE) {
|
if ($GLOBALS['access_check'] == FALSE) {
|
||||||
$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>";
|
$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>";
|
||||||
}
|
}
|
||||||
|
|
||||||
$output .= theme('item_list', $links);
|
$output .= theme('item_list', $links);
|
||||||
|
|
||||||
// Output a list of queries executed
|
// Output a list of queries executed
|
||||||
|
@ -546,8 +560,89 @@ function update_fix_system_table() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This code may be removed later. It is part of the Drupal 4.6 to 4.7 migration.
|
||||||
|
function update_fix_access_table() {
|
||||||
|
if (variable_get('update_access_fixed', FALSE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($GLOBALS['db_type']) {
|
||||||
|
// Only for MySQL 4.1+
|
||||||
|
case 'mysqli':
|
||||||
|
break;
|
||||||
|
case 'mysql':
|
||||||
|
if (version_compare(mysql_get_server_info($GLOBALS['active_db']), '4.1.0', '<')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'pgsql':
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert access table to UTF-8 if needed.
|
||||||
|
$result = db_fetch_array(db_query('SHOW CREATE TABLE `access`'));
|
||||||
|
if (!preg_match('/utf8/i', array_pop($result))) {
|
||||||
|
update_convert_table_utf8('access');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't run again
|
||||||
|
variable_set('update_access_fixed', TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a single MySQL table to UTF-8.
|
||||||
|
*
|
||||||
|
* We change all text columns to their correspending binary type,
|
||||||
|
* then back to text, but with a UTF-8 character set.
|
||||||
|
* See: http://dev.mysql.com/doc/refman/4.1/en/charset-conversion.html
|
||||||
|
*/
|
||||||
|
function update_convert_table_utf8($table) {
|
||||||
|
$ret = array();
|
||||||
|
$types = array('char' => 'binary',
|
||||||
|
'varchar' => 'varbinary',
|
||||||
|
'tinytext' => 'tinyblob',
|
||||||
|
'text' => 'blob',
|
||||||
|
'mediumtext' => 'mediumblob',
|
||||||
|
'longtext' => 'longblob');
|
||||||
|
|
||||||
|
// Get next table in list
|
||||||
|
$convert_to_binary = array();
|
||||||
|
$convert_to_utf8 = array();
|
||||||
|
|
||||||
|
// Set table default charset
|
||||||
|
$ret[] = update_sql('ALTER TABLE {'. $table .'} DEFAULT CHARACTER SET utf8');
|
||||||
|
|
||||||
|
// Find out which columns need converting and build SQL statements
|
||||||
|
$result = db_query('SHOW FULL COLUMNS FROM {'. $table .'}');
|
||||||
|
while ($column = db_fetch_array($result)) {
|
||||||
|
list($type) = explode('(', $column['Type']);
|
||||||
|
if (isset($types[$type])) {
|
||||||
|
$names = 'CHANGE `'. $column['Field'] .'` `'. $column['Field'] .'` ';
|
||||||
|
$attributes = ' DEFAULT '. ($column['Default'] == 'NULL' ? 'NULL ' :
|
||||||
|
"'". db_escape_string($column['Default']) ."' ") .
|
||||||
|
($column['Null'] == 'YES' ? 'NULL' : 'NOT NULL');
|
||||||
|
|
||||||
|
$convert_to_binary[] = $names . preg_replace('/'. $type .'/i', $types[$type], $column['Type']) . $attributes;
|
||||||
|
$convert_to_utf8[] = $names . $column['Type'] .' CHARACTER SET utf8'. $attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($convert_to_binary)) {
|
||||||
|
// Convert text columns to binary
|
||||||
|
$ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_binary));
|
||||||
|
// Convert binary columns to UTF-8
|
||||||
|
$ret[] = update_sql('ALTER TABLE {'. $table .'} '. implode(', ', $convert_to_utf8));
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some unavoidable errors happen because the database is not yet up to date.
|
||||||
|
// We suppress them to avoid confusion. All errors are still logged.
|
||||||
|
ini_set('display_errors', FALSE);
|
||||||
|
|
||||||
include_once './includes/bootstrap.inc';
|
include_once './includes/bootstrap.inc';
|
||||||
update_fix_system_table();
|
update_fix_system_table();
|
||||||
|
update_fix_access_table();
|
||||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
||||||
drupal_maintenance_theme();
|
drupal_maintenance_theme();
|
||||||
|
|
||||||
|
@ -567,7 +662,11 @@ if (($access_check == FALSE) || ($user->uid == 1)) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'finished':
|
case 'finished':
|
||||||
$output = update_finished_page();
|
$output = update_finished_page(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'error':
|
||||||
|
$output = update_finished_page(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'do_update':
|
case 'do_update':
|
||||||
|
|
Loading…
Reference in New Issue