You are here

public function DatabaseSchema_sqlsrv::changeField in Drupal driver for SQL Server and SQL Azure 7

Same name and namespace in other branches
  1. 7.3 sqlsrv/schema.inc \DatabaseSchema_sqlsrv::changeField()
  2. 7.2 sqlsrv/schema.inc \DatabaseSchema_sqlsrv::changeField()

Override DatabaseSchema::changeField().

@status complete

Overrides DatabaseSchema::changeField

File

sqlsrv/schema.inc, line 498
Database schema code for Microsoft SQL Server database servers.

Class

DatabaseSchema_sqlsrv

Code

public function changeField($table, $field, $field_new, $spec, $new_keys = 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,
    )));
  }

  // SQL Server supports transactional DDL, so we can just start a transaction
  // here and pray for the best.
  $transaction = $this->connection
    ->startTransaction();

  // Introspect the schema and save the current primary key if the column
  // we are modifying is part of it.
  $primary_key_sql = $this
    ->introspectPrimaryKey($table, $field);

  // If there is a generated unique key for this field, we will need to
  // add it back in when we are done
  $unique_key = $this
    ->uniqueKeyExists($table, $field);

  // Drop the related objects.
  $this
    ->dropFieldRelatedObjects($table, $field);

  // Start by renaming the current column.
  $this->connection
    ->query('EXEC sp_rename :old, :new, :type', array(
    ':old' => $this->connection
      ->prefixTables('{' . $table . '}.' . $field),
    ':new' => $field . '_old',
    ':type' => 'COLUMN',
  ));

  // If the field is declared NOT NULL, we have to first create it NULL insert
  // the initial data then switch to NOT NULL.
  if (!empty($spec['not null']) && !isset($spec['default'])) {
    $fixnull = TRUE;
    $spec['not null'] = FALSE;
  }

  // Create a new field.
  $this
    ->addField($table, $field_new, $spec);

  // Migrate the data over.
  // Explicitly cast the old value to the new value to avoid conversion errors.
  $field_spec = $this
    ->processField($spec);
  $this->connection
    ->query('UPDATE [{' . $table . '}] SET [' . $field_new . '] = CAST([' . $field . '_old] AS ' . $field_spec['sqlsrv_type'] . ')');

  // Switch to NOT NULL now.
  if (!empty($fixnull)) {
    $spec['not null'] = TRUE;
    $this->connection
      ->query('ALTER TABLE {' . $table . '} ALTER COLUMN ' . $this
      ->createFieldSql($table, $field_new, $this
      ->processField($spec), TRUE));
  }

  // Recreate the primary key.
  if ($primary_key_sql) {
    $this
      ->recreatePrimaryKey($table, $primary_key_sql);
  }
  if ($unique_key) {
    $fields = array();
    $fields[] = $field;
    $this
      ->addUniqueKey($table, $field, $fields);
  }

  // Drop the old field.
  $this
    ->dropField($table, $field . '_old');

  // Add the new keys.
  if (isset($new_keys)) {
    $this
      ->recreateTableKeys($table, $new_keys);
  }
}