You are here

public function DatabaseSchema_sqlsrv::addField in Drupal driver for SQL Server and SQL Azure 7.3

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

Override DatabaseSchema::addField().

@status complete

Overrides DatabaseSchema::addField

1 call to DatabaseSchema_sqlsrv::addField()
DatabaseSchema_sqlsrv::changeField in sqlsrv/schema.inc
Override DatabaseSchema::changeField().

File

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

Class

DatabaseSchema_sqlsrv

Code

public function addField($table, $field, $spec, $new_keys = array()) {
  if (!$this
    ->tableExists($table, TRUE)) {
    throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array(
      '%field' => $field,
      '%table' => $table,
    )));
  }
  if ($this
    ->fieldExists($table, $field)) {
    throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array(
      '%field' => $field,
      '%table' => $table,
    )));
  }

  /** @var DatabaseTransaction_sqlsrv $transaction */
  $transaction = $this->connection
    ->startTransaction(NULL, DatabaseTransactionSettings::GetDDLCompatibleDefaults());

  // Prepare the specifications.
  $spec = $this
    ->processField($spec);

  // Clear column information for table.
  $this
    ->queryColumnInformationInvalidate($table);

  // Use already prefixed table name.
  $table_prefixed = $this->connection
    ->prefixTables('{' . $table . '}');

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

  // Create the field.
  // Because the default values of fields can contain string literals
  // with braces, we CANNOT allow the driver to prefix tables because the algorithm
  // to do so is a crappy str_replace.
  $query = "ALTER TABLE {$table_prefixed} ADD ";
  $query .= $this
    ->createFieldSql($table, $field, $spec);
  $this->connection
    ->query_direct($query, array(), array(
    'prefix_tables' => FALSE,
  ));

  // Clear column information for table.
  $this
    ->queryColumnInformationInvalidate($table);

  // Load the initial data.
  if (isset($spec['initial'])) {
    $this->connection
      ->update($table)
      ->fields(array(
      $field => $spec['initial'],
    ))
      ->execute();
  }

  // Switch to NOT NULL now.
  if ($fixnull === TRUE) {

    // There is no warranty that the old data did not have NULL values, we need to populate
    // nulls with the default value because this won't be done by MSSQL by default.
    if (isset($spec['default'])) {
      $default_expression = $this
        ->defaultValueExpression($spec['sqlsrv_type'], $spec['default']);
      $this->connection
        ->query_direct("UPDATE [{$table_prefixed}] SET [{$field}] = {$default_expression} WHERE [{$field}] IS NULL", array(), array(
        'prefix_tables' => FALSE,
      ));
    }

    // Now it's time to make this non-nullable.
    $spec['not null'] = TRUE;
    $this->connection
      ->query_direct("ALTER TABLE [{$table_prefixed}] ALTER COLUMN " . $this
      ->createFieldSql($table, $field, $spec, TRUE), array(), array(
      'prefix_tables' => FALSE,
    ));
  }

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

  // Commit.
  $transaction
    ->commit();

  // Clear column information for table.
  $this
    ->queryColumnInformationInvalidate($table);
}