Commit 39d776fa authored by Gábor Hojtsy's avatar Gábor Hojtsy

#157682 by bjaspan, chx and JirkaRybka: update.php for Drupal 6, to allow near flowless updates

parent 7531f956
......@@ -444,6 +444,48 @@ function db_field_names($fields) {
return $ret;
}
/**
* Given a Schema API field type, return the correct %-placeholder to
* embed in a query to be passed to db_query along with a value from a
* column of the specified type.
*
* @param $type
* The Schema API type of a field.
* @return
* The placeholder string to embed in a query for that type.
*/
function _db_type_placeholder($type) {
switch ($type) {
case 'varchar':
case 'text':
case 'datetime':
return '\'%s\'';
case 'numeric':
// For 'numeric' values, we use '%s', not '\'%s\'' as with
// string types, because numeric values should not be enclosed
// in quotes in queries (though they can be, at least on mysql
// and pgsql). Numerics should only have [0-9.+-] and
// presumably no db's "escape string" function will mess with
// those characters.
return '%s';
case 'serial':
case 'int':
return '%d';
case 'float':
return '%f';
case 'blob':
return '%b';
}
// There is no safe value to return here, so return something that
// will cause the query to fail.
return 'unsupported type '. $type . 'for _db_type_placeholder';
}
/**
* @} End of "defgroup schemaapi".
*/
......@@ -257,12 +257,31 @@ function db_drop_table(&$ret, $table) {
* @param $field
* Name of the field to be added.
* @param $spec
* The field specification array, as taken from a schema definition
* The field specification array, as taken from a schema definition.
* The specification may also contain the key 'initial', the newly
* created field will be set to the value of the key in all rows.
* This is most useful for creating NOT NULL columns with no default
* value in existing tables.
*/
function db_add_field(&$ret, $table, $field, $spec) {
$fixnull = FALSE;
if (!empty($spec['not null']) && !isset($spec['default'])) {
$fixnull = TRUE;
$spec['not null'] = FALSE;
}
$query = 'ALTER TABLE {'. $table .'} ADD ';
$query .= _db_create_field_sql($field, _db_process_field($spec));
$ret[] = update_sql($query);
if (isset($spec['initial'])) {
// All this because update_sql does not support %-placeholders.
$sql = 'UPDATE {'. $table .'} SET '. $field .' = '. _db_type_placeholder($spec['type']);
$result = db_query($sql, $spec['initial']);
$ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')'));
}
if ($fixnull) {
$spec['not null'] = TRUE;
db_change_field($ret, $table, $field, $field, $spec);
}
}
/**
......@@ -387,15 +406,7 @@ function db_drop_unique_key(&$ret, $table, $name) {
* An array of field names.
*/
function db_add_index(&$ret, $table, $name, $fields) {
$query = 'ALTER TABLE {'. $table .'} ADD INDEX '. $name .' (';
foreach ($fields as $current) {
$query .= $current .', ';
}
// Remove the last comma, add a closing bracket.
$query = substr($query, 0, -2) .')';
$query = 'ALTER TABLE {'. $table .'} ADD INDEX '. $name .' ('. _db_create_key_sql($fields) . ')';
$ret[] = update_sql($query);
}
......@@ -416,6 +427,15 @@ function db_drop_index(&$ret, $table, $name) {
/**
* Change a field definition.
*
* IMPORTANT NOTE: On some database systems (notably PostgreSQL),
* changing a field definition involves adding a new field and
* dropping an old one. This means that any indices, primary keys and
* sequences (from serial-type fields) that use the field to be
* changed get dropped. For database portability, you MUST drop them
* explicitly before calling db_change_field() and then re-create them
* afterwards. Use db_{add,drop}_{primary_key,unique_key,index} for
* this purpose.
*
* @param $ret
* Array to which query results will be added.
* @param $table
......
......@@ -251,7 +251,7 @@ function db_last_insert_id($table, $field) {
*/
function db_affected_rows() {
global $last_result;
return pg_affected_rows($last_result);
return empty($last_result) ? 0 : pg_affected_rows($last_result);
}
/**
......@@ -658,12 +658,30 @@ function db_drop_table(&$ret, $table) {
* @param $field
* Name of the field to be added.
* @param $spec
* The field specification array, as taken from a schema definition
* The field specification array, as taken from a schema definition.
* The specification may also contain the key 'initial', the newly
* created field will be set to the value of the key in all rows.
* This is most useful for creating NOT NULL columns with no default
* value in existing tables.
*/
function db_add_field(&$ret, $table, $field, $spec) {
$fixnull = FALSE;
if (!empty($spec['not null']) && !isset($spec['default'])) {
$fixnull = TRUE;
$spec['not null'] = FALSE;
}
$query = 'ALTER TABLE {'. $table .'} ADD COLUMN ';
$query .= _db_create_field_sql($field, _db_process_field($spec));
$ret[] = update_sql($query);
if (isset($spec['initial'])) {
// All this because update_sql does not support %-placeholders.
$sql = 'UPDATE {'. $table .'} SET '. $field .' = '. _db_type_placeholder($spec['type']);
$result = db_query($sql, $spec['initial']);
$ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')'));
}
if ($fixnull) {
$ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field SET NOT NULL");
}
}
/**
......@@ -811,10 +829,14 @@ function db_drop_index(&$ret, $table, $name) {
/**
* Change a field definition.
*
* Remember that changing a field definition involves adding a new field
* and dropping an old one. This means that any indices, primary keys and
* sequences from serial-type fields are dropped and might need to be
* recreated.
* IMPORTANT NOTE: On some database systems (notably PostgreSQL),
* changing a field definition involves adding a new field and
* dropping an old one. This means that any indices, primary keys and
* sequences (from serial-type fields) that use the field to be
* changed get dropped. For database portability, you MUST drop them
* explicitly before calling db_change_field() and then re-create them
* afterwards. Use db_{add,drop}_{primary_key,unique_key,index} for
* this purpose.
*
* @param $ret
* Array to which query results will be added.
......
......@@ -75,19 +75,15 @@ function locale_update_6001() {
}
/**
* Add multiple text group support to allow for user defined string translation.
* Change locale column to language. The language column is added by
* update_fix_d6_requirements() in update.php to avoid a large number
* of error messages from update.php. All we need to do here is copy
* locale to language and then drop locale.
*/
function locale_update_6002() {
$ret = array();
switch ($GLOBALS['db_type']) {
case 'mysql':
case 'mysqli':
$ret[] = update_sql("ALTER TABLE {locales_source} ADD textgroup varchar(255) NOT NULL default ''");
break;
case 'pgsql':
db_add_column($ret, 'locales_source', 'textgroup', 'varchar(255)', array('default' => "''", 'not null' => TRUE));
break;
}
$ret[] = update_sql('UPDATE {locales_target} SET language = locale');
db_drop_field($ret, 'locales_target', 'locale');
return $ret;
}
......
This diff is collapsed.
......@@ -63,9 +63,13 @@ function db_add_column(&$ret, $table, $column, $type, $attributes = array()) {
}
$ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column $type");
if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default"); }
if ($not_null) {
if ($default) { $ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val"); }
if (!empty($default)) {
$ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default");
}
if (!empty($not_null)) {
if (!empty($default)) {
$ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val");
}
$ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET NOT NULL");
}
}
......@@ -736,6 +740,45 @@ function update_fix_compatibility() {
return $ret;
}
/**
* Perform Drupal 5.x to 6.x updates that are required for update.php
* to function properly.
*
* This function runs when update.php is run the first time for 6.x,
* even before updates are selected or performed. It is important
* that if updates are not ultimately performed that no changes are
* made which make it impossible to continue using the prior version.
* Just adding columns is safe. However, renaming the
* system.description column to owner is not. Therefore, we add the
* system.owner column and leave it to system_update_6008() to copy
* the data from description and remove description. The same for
* renaming locales_target.locale to locales_target.language, which
* will be finished by locale_update_6002().
*/
function update_fix_d6_requirements() {
$ret = array();
if (drupal_get_installed_schema_version('system') < 6000 && !variable_get('update_d6_requirements', FALSE)) {
$spec = array('type' => 'int', 'size' => 'small', 'default' => 0, 'not null' => TRUE);
db_add_field($ret, 'cache', 'serialized', $spec);
db_add_field($ret, 'cache_filter', 'serialized', $spec);
db_add_field($ret, 'cache_page', 'serialized', $spec);
db_add_field($ret, 'cache_menu', 'serialized', $spec);
db_add_field($ret, 'system', 'info', array('type' => 'text'));
db_add_field($ret, 'system', 'owner', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
if (db_table_exists('locales_target')) {
db_add_field($ret, 'locales_target', 'language', array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''));
}
if (db_table_exists('locales_source')) {
db_add_field($ret, 'locales_source', 'textgroup', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'default'));
}
variable_set('update_d6_requirements', TRUE);
}
return $ret;
}
/**
* Add the update task list to the current page.
*/
......@@ -782,6 +825,7 @@ function update_task_list($active = NULL) {
update_fix_watchdog_115();
update_fix_watchdog();
update_fix_sessions();
update_fix_d6_requirements();
update_fix_compatibility();
$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment