Issue #3191391 by Arantxio, larowlan, _utsavsharma, daffie: Schema::changeField() has bug when changing regular serial field to big serial field

(cherry picked from commit 6367bb87ee)
merge-requests/3234/head
Lee Rowlands 2023-03-28 12:44:23 +10:00
parent d36085602f
commit 251a94657a
No known key found for this signature in database
GPG Key ID: 2B829A3DF9204DC4
2 changed files with 75 additions and 6 deletions

View File

@ -893,12 +893,11 @@ EOD;
// Type 'serial' is known to PostgreSQL, but only during table creation, // 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 // not when altering. Because of that, we create it here as an 'int'. After
// we create it we manually re-apply the sequence. // we create it we manually re-apply the sequence.
if (in_array($spec['pgsql_type'], ['serial', 'bigserial'])) { $field_def = match($spec['pgsql_type']) {
$field_def = 'int'; 'serial' => 'int',
} 'bigserial' => 'bigint',
else { default => $spec['pgsql_type'],
$field_def = $spec['pgsql_type']; };
}
if (in_array($spec['pgsql_type'], ['varchar', 'character', 'text']) && isset($spec['length'])) { if (in_array($spec['pgsql_type'], ['varchar', 'character', 'text']) && isset($spec['length'])) {
$field_def .= '(' . $spec['length'] . ')'; $field_def .= '(' . $spec['length'] . ')';
@ -910,6 +909,14 @@ EOD;
// Remove old check constraints. // Remove old check constraints.
$field_info = $this->queryFieldInformation($table, $field); $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) { foreach ($field_info as $check) {
$this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT [' . $check . ']'); $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT [' . $check . ']');
} }
@ -1062,6 +1069,26 @@ EOD;
])->fetchField(); ])->fetchField();
} }
/**
* Retrieves a sequence name that is owned by the table and column..
*
* @param string $table
* A table name that is not prefixed or quoted.
* @param string $column
* The column name.
*
* @return string|null
* The name of the sequence or NULL if it does not exist.
*/
protected function getSequenceName(string $table, string $column): ?string {
return $this->connection
->query("SELECT pg_get_serial_sequence(:table, :column)", [
':table' => $this->connection->getPrefix() . $table,
':column' => $column,
])
->fetchField();
}
} }
/** /**

View File

@ -1308,4 +1308,46 @@ abstract class DriverSpecificSchemaTestBase extends DriverSpecificKernelTestBase
$this->assertFalse($this->schema->tableExists($table_name_new)); $this->assertFalse($this->schema->tableExists($table_name_new));
} }
/**
* Tests changing a field length.
*/
public function testChangeSerialFieldLength(): void {
$specification = [
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique ID.',
],
'text' => [
'type' => 'text',
'description' => 'A text field',
],
],
'primary key' => ['id'],
];
$this->schema->createTable('change_serial_to_big', $specification);
// Increase the size of the field.
$new_specification = [
'size' => 'big',
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique ID.',
];
$this->schema->changeField('change_serial_to_big', 'id', 'id', $new_specification);
$this->assertTrue($this->schema->fieldExists('change_serial_to_big', 'id'));
// Test if we can actually add a big int.
$id = $this->connection->insert('change_serial_to_big')->fields([
'id' => 21474836470,
])->execute();
$id_two = $this->connection->insert('change_serial_to_big')->fields([
'text' => 'Testing for ID generation',
])->execute();
$this->assertEquals($id + 1, $id_two);
}
} }