You are here

public function DatabaseSchema_sqlite::changeField in Drupal 7

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 $keys_new argument directly to db_change_field().

For example, suppose you have:

$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:

db_drop_primary_key('foo');
db_change_field('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 $keys_new 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 $keys_new argument in all cases.

Parameters

$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.

$keys_new: (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.

Throws

DatabaseSchemaObjectDoesNotExistException If the specified table or source field doesn't exist.

DatabaseSchemaObjectExistsException If the specified destination field already exists.

Overrides DatabaseSchema::changeField

File

includes/database/sqlite/schema.inc, line 495
Database schema code for SQLite databases.

Class

DatabaseSchema_sqlite

Code

public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
  if (!$this
    ->fieldExists($table, $field)) {
    throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field @table.@name: field doesn't exist.", array(
      '@table' => $table,
      '@name' => $field,
    )));
  }
  if ($field != $field_new && $this
    ->fieldExists($table, $field_new)) {
    throw new DatabaseSchemaObjectExistsException(t("Cannot rename field @table.@name to @name_new: target field already exists.", array(
      '@table' => $table,
      '@name' => $field,
      '@name_new' => $field_new,
    )));
  }
  $old_schema = $this
    ->introspectSchema($table);
  $new_schema = $old_schema;

  // Map the old field to the new field.
  if ($field != $field_new) {
    $mapping[$field_new] = $field;
  }
  else {
    $mapping = array();
  }

  // Remove the previous definition and swap in the new one.
  unset($new_schema['fields'][$field]);
  $new_schema['fields'][$field_new] = $spec;

  // Map the former indexes to the new column name.
  $new_schema['primary key'] = $this
    ->mapKeyDefinition($new_schema['primary key'], $mapping);
  foreach (array(
    'unique keys',
    'indexes',
  ) as $k) {
    foreach ($new_schema[$k] as &$key_definition) {
      $key_definition = $this
        ->mapKeyDefinition($key_definition, $mapping);
    }
  }

  // Add in the keys from $keys_new.
  if (isset($keys_new['primary key'])) {
    $new_schema['primary key'] = $keys_new['primary key'];
  }
  foreach (array(
    'unique keys',
    'indexes',
  ) as $k) {
    if (!empty($keys_new[$k])) {
      $new_schema[$k] = $keys_new[$k] + $new_schema[$k];
    }
  }
  $this
    ->alterTable($table, $old_schema, $new_schema, $mapping);
}