function Schema::changeField
Same name in this branch
- 11.x core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
- 11.x core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
- 11.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
Same name in other branches
- 9 core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
- 9 core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
- 9 core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
- 9 core/tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefakeWithAllCustomClasses/Schema.php \Drupal\corefake\Driver\Database\corefakeWithAllCustomClasses\Schema::changeField()
- 9 core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
- 8.9.x core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php \Drupal\Core\Database\Driver\sqlite\Schema::changeField()
- 8.9.x core/lib/Drupal/Core/Database/Driver/mysql/Schema.php \Drupal\Core\Database\Driver\mysql\Schema::changeField()
- 8.9.x core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php \Drupal\Core\Database\Driver\pgsql\Schema::changeField()
- 8.9.x core/lib/Drupal/Core/Database/Schema.php \Drupal\Core\Database\Schema::changeField()
- 10 core/modules/sqlite/src/Driver/Database/sqlite/Schema.php \Drupal\sqlite\Driver\Database\sqlite\Schema::changeField()
- 10 core/modules/mysql/src/Driver/Database/mysql/Schema.php \Drupal\mysql\Driver\Database\mysql\Schema::changeField()
- 10 core/modules/pgsql/src/Driver/Database/pgsql/Schema.php \Drupal\pgsql\Driver\Database\pgsql\Schema::changeField()
- 10 core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Schema.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Schema::changeField()
- 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 904
Class
- Schema
- PostgreSQL implementation of \Drupal\Core\Database\Schema.
Namespace
Drupal\pgsql\Driver\Database\pgsqlCode
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.