function Schema::changeField

Same name in this branch
  1. 8.9.x core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php \Drupal\Core\Database\Driver\sqlite\Schema::changeField()
  2. 8.9.x core/lib/Drupal/Core/Database/Driver/mysql/Schema.php \Drupal\Core\Database\Driver\mysql\Schema::changeField()
  3. 8.9.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
Same name in other branches
  1. 9 core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
  2. 9 core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
  3. 9 core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
  4. 9 core/tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefakeWithAllCustomClasses/Schema.php \Drupal\corefake\Driver\Database\corefakeWithAllCustomClasses\Schema::changeField()
  5. 9 core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
  6. 10 core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
  7. 10 core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
  8. 10 core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
  9. 10 core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Schema.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Schema::changeField()
  10. 10 core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
  11. 11.x core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
  12. 11.x core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
  13. 11.x core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
  14. 11.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()

Overrides Schema::changeField

File

core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php, line 922

Class

Schema
PostgreSQL implementation of \Drupal\Core\Database\Schema.

Namespace

Drupal\Core\Database\Driver\pgsql

Code

public function changeField($table, $field, $field_new, $spec, $new_keys = []) {
    if (!$this->fieldExists($table, $field)) {
        throw new SchemaObjectDoesNotExistException("Cannot change the definition of field '{$table}.{$field}': field doesn't exist.");
    }
    if ($field != $field_new && $this->fieldExists($table, $field_new)) {
        throw new SchemaObjectExistsException("Cannot rename field '{$table}.{$field}' to '{$field_new}': target field already exists.");
    }
    if (isset($new_keys['primary key']) && in_array($field_new, $new_keys['primary key'], TRUE)) {
        $this->ensureNotNullPrimaryKey($new_keys['primary key'], [
            $field_new => $spec,
        ]);
    }
    $spec = $this->processField($spec);
    // Type 'serial' is known to PostgreSQL, but only during table creation,
    // not when altering. Because of that, we create it here as an 'int'. After
    // we create it we manually re-apply the sequence.
    if (in_array($spec['pgsql_type'], [
        'serial',
        'bigserial',
    ])) {
        $field_def = 'int';
    }
    else {
        $field_def = $spec['pgsql_type'];
    }
    if (in_array($spec['pgsql_type'], [
        'varchar',
        'character',
        'text',
    ]) && isset($spec['length'])) {
        $field_def .= '(' . $spec['length'] . ')';
    }
    elseif (isset($spec['precision']) && isset($spec['scale'])) {
        $field_def .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
    }
    // Remove old check constraints.
    $field_info = $this->queryFieldInformation($table, $field);
    foreach ($field_info as $check) {
        $this->connection
            ->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $check . '"');
    }
    // Remove old default.
    $this->connection
        ->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
    // Convert field type.
    // Usually, we do this via a simple typecast 'USING fieldname::type'. But
    // the typecast does not work for conversions to bytea.
    // @see http://www.postgresql.org/docs/current/static/datatype-binary.html
    $table_information = $this->queryTableInformation($table);
    $is_bytea = !empty($table_information->blob_fields[$field]);
    if ($spec['pgsql_type'] != 'bytea') {
        if ($is_bytea) {
            $this->connection
                ->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING convert_from("' . $field . '"' . ", 'UTF8')");
        }
        else {
            $this->connection
                ->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING "' . $field . '"::' . $field_def);
        }
    }
    else {
        // Do not attempt to convert a field that is bytea already.
        if (!$is_bytea) {
            // Convert to a bytea type by using the SQL replace() function to
            // convert any single backslashes in the field content to double
            // backslashes ('\' to '\\').
            $this->connection
                ->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", E'\\\\', E'\\\\\\\\'), 'escape');");
        }
    }
    if (isset($spec['not null'])) {
        if ($spec['not null']) {
            $nullaction = 'SET NOT NULL';
        }
        else {
            $nullaction = 'DROP NOT NULL';
        }
        $this->connection
            ->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" ' . $nullaction);
    }
    if (in_array($spec['pgsql_type'], [
        'serial',
        'bigserial',
    ])) {
        // Type "serial" is known to PostgreSQL, but *only* during table creation,
        // not when altering. Because of that, the sequence needs to be created
        // and initialized by hand.
        $seq = $this->connection
            ->makeSequenceName($table, $field_new);
        $this->connection
            ->query("CREATE SEQUENCE " . $seq);
        // Set sequence to maximal field value to not conflict with existing
        // entries.
        $this->connection
            ->query("SELECT setval('" . $seq . "', MAX(\"" . $field . '")) FROM {' . $table . "}");
        $this->connection
            ->query('ALTER TABLE {' . $table . '} ALTER ' . $field . ' SET DEFAULT nextval(' . $this->connection
            ->quote($seq) . ')');
    }
    // Rename the column if necessary.
    if ($field != $field_new) {
        $this->connection
            ->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '"');
    }
    // Add unsigned check if necessary.
    if (!empty($spec['unsigned'])) {
        $this->connection
            ->query('ALTER TABLE {' . $table . '} ADD CHECK ("' . $field_new . '" >= 0)');
    }
    // Add default if necessary.
    if (isset($spec['default'])) {
        $this->connection
            ->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field_new . '" SET DEFAULT ' . $this->escapeDefaultValue($spec['default']));
    }
    // Change description if necessary.
    if (!empty($spec['description'])) {
        $this->connection
            ->query('COMMENT ON COLUMN {' . $table . '}."' . $field_new . '" IS ' . $this->prepareComment($spec['description']));
    }
    if (isset($new_keys)) {
        $this->_createKeys($table, $new_keys);
    }
    $this->resetTableInformation($table);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.