db_change_field

Versions
6
db_change_field(&$ret, $table, $field, $field_new, $spec, $new_keys = array())
7
db_change_field($table, $field, $field_new, $spec, $keys_new = array())

Change a field definition.

IMPORTANT NOTE: To maintain database portability, you have to explicitly recreate all indices and primary keys that are using the changed field.

That means that you have to drop all affected keys and indexes with db_drop_{primary_key,unique_key,index}() before calling db_change_field(). To recreate the keys and indices, pass the key definitions as the optional $new_keys argument directly to db_change_field().

For example, suppose you have:

<?php

$schema['foo'] = array(
'fields' => array(
'bar' => array('type' => 'int', 'not null' => TRUE)
),
'primary key' => array('bar')
);

?>

and you want to change foo.bar to be type serial, leaving it as the primary key. The correct sequence is:

<?php

db_drop_primary_key($ret, 'foo');
db_change_field($ret, 'foo', 'bar', 'bar',
array('type' => 'serial', 'not null' => TRUE),
array('primary key' => array('bar')));

?>

The reasons for this are due to the different database engines:

On PostgreSQL, changing a field definition involves adding a new field and dropping an old one which* causes any indices, primary keys and sequences (from serial-type fields) that use the changed field to be dropped.

On MySQL, all type 'serial' fields must be part of at least one key or index as soon as they are created. You cannot use db_add_{primary_key,unique_key,index}() for this purpose because the ALTER TABLE command will fail to add the column without a key or index specification. The solution is to use the optional $new_keys argument to create the key or index at the same time as field.

You could use db_add_{primary_key,unique_key,index}() in all cases unless you are converting a field to be type serial. You can use the $new_keys argument in all cases.

Parameters

$ret Array to which query results will be added.

$table Name of the table.

$field Name of the field to change.

$field_new New name for the field (set to the same as $field if you don't want to change the name).

$spec The field specification for the new field.

$new_keys Optional keys and indexes specification to be created on the table along with changing the field. The format is the same as a table specification but without the 'fields' element.

Related topics

▾ 12 functions call db_change_field()

dblog_update_6000 in modules/dblog/dblog.install
Allow longer referrers.
statistics_update_6000 in modules/statistics/statistics.install
Allow longer referrers.
system_update_6002 in modules/system/system.install
Increase the maximum length of variable names from 48 to 128.
system_update_6019 in modules/system/system.install
Reconcile small differences in the previous, manually created mysql and pgsql schemas so they are the same and can be represented by a single schema structure.
system_update_6022 in modules/system/system.install
Update files tables to associate files to a uid by default instead of a nid. Rename file_revisions to upload since it should only be used by the upload module used by upload to link files to nodes.
system_update_6023 in modules/system/system.install
system_update_6025 in modules/system/system.install
Increase the maximum length of node titles from 128 to 255.
system_update_6032 in modules/system/system.install
profile_fields.name used to be nullable but is part of a unique key and so shouldn't be.
system_update_6033 in modules/system/system.install
Change node_comment_statistics to be not autoincrement.
system_update_6037 in modules/system/system.install
Create consistent empty region for disabled blocks.
system_update_6043 in modules/system/system.install
Update table indices to make them more rational and useful.
system_update_6048 in modules/system/system.install
Increase the size of the 'load_functions' and 'to_arg_functions' fields in table 'menu_router'.

Code

includes/database.pgsql.inc, line 907

<?php
function db_change_field(&$ret, $table, $field, $field_new, $spec, $new_keys = array()) {
  $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME "'. $field .'" TO "'. $field .'_old"');
  $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE;
  unset($spec['not null']);

  if (!array_key_exists('size', $spec)) {
    $spec['size'] = 'normal';
  }
  db_add_field($ret, $table, "$field_new", $spec);

  // We need to type cast the new column to best transfer the data
  // db_type_map will return possiblities that are not 'cast-able'
  // such as serial - they must be made 'int' instead.
  $map =  db_type_map();
  $typecast = $map[$spec['type'] .':'. $spec['size']];
  if (in_array($typecast, array('serial', 'bigserial', 'numeric'))) {
    $typecast = 'int';
  }
  $ret[] = update_sql('UPDATE {'. $table .'} SET '. $field_new .' = CAST('. $field .'_old AS '. $typecast .')');

  if ($not_null) {
    $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field_new SET NOT NULL");
  }

  db_drop_field($ret, $table, $field .'_old');

  if (isset($new_keys)) {
    _db_create_keys($ret, $table, $new_keys);
  }
}
?>
Login or register to post comments
 
 

All source code and documentation on this site is released under the terms of the GNU General Public License, version 2 and later. Drupal is a registered trademark of Dries Buytaert.