function Schema::changeField

Same name in this branch
  1. 11.x core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
  2. 11.x core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
  3. 11.x core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Schema.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Schema::changeField()
  4. 11.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
Same name and namespace 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. 8.9.x core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php \Drupal\Core\Database\Driver\sqlite\Schema::changeField()
  7. 8.9.x core/lib/Drupal/Core/Database/Driver/mysql/Schema.php \Drupal\Core\Database\Driver\mysql\Schema::changeField()
  8. 8.9.x core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php \Drupal\Core\Database\Driver\pgsql\Schema::changeField()
  9. 8.9.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
  10. 10 core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
  11. 10 core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
  12. 10 core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
  13. 10 core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Schema.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Schema::changeField()
  14. 10 core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()

Overrides Schema::changeField

File

core/modules/pgsql/src/Driver/Database/pgsql/Schema.php, line 903

Class

Schema
PostgreSQL implementation of <a href="/api/drupal/core%21lib%21Drupal%21Core%21Database%21Schema.php/class/Schema/11.x" title="Provides a base implementation for Database Schema." class="local">\Drupal\Core\Database\Schema</a>.

Namespace

Drupal\pgsql\Driver\Database\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.
    $field_def = match ($spec['pgsql_type']) {    'serial' => 'int',
        'bigserial' => 'bigint',
        default => $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);
    // Remove old sequence.
    $seq_name = $this->getSequenceName($table, $field);
    if (!empty($seq_name)) {
        // We need to add CASCADE otherwise we cannot alter the sequence because
        // the table depends on it.
        $this->connection
            ->query('DROP SEQUENCE IF EXISTS ' . $seq_name . ' CASCADE');
    }
    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']) {
            $null_action = 'SET NOT NULL';
        }
        else {
            $null_action = 'DROP NOT NULL';
        }
        $this->connection
            ->query('ALTER TABLE {' . $table . '} ALTER [' . $field . '] ' . $null_action);
    }
    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 . " OWNED BY {" . $table . "}.[" . $field_new . ']');
        // 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.