Commit 6e51cc1d authored by alexpott's avatar alexpott

Issue #1668644 by Island Usurper, phayes, daffie, Brandonian, gease:...

Issue #1668644 by Island Usurper, phayes, daffie, Brandonian, gease: PostgreSQL: Impossible to change a field to serial, bigserial, or numeric
parent 23ed78ec
......@@ -668,21 +668,21 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
$spec = $this->processField($spec);
// We need to typecast the new column to best be able to transfer the data
// Schema_pgsql::getFieldTypeMap() will return possibilities that are not
// 'cast-able' such as 'serial' - so they need to be casted int instead.
if (in_array($spec['pgsql_type'], array('serial', 'bigserial', 'numeric'))) {
$typecast = 'int';
// 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'], array('serial', 'bigserial'))) {
$field_def = 'int';
}
else {
$typecast = $spec['pgsql_type'];
$field_def = $spec['pgsql_type'];
}
if (in_array($spec['pgsql_type'], array('varchar', 'character', 'text')) && isset($spec['length'])) {
$typecast .= '(' . $spec['length'] . ')';
$field_def .= '(' . $spec['length'] . ')';
}
elseif (isset($spec['precision']) && isset($spec['scale'])) {
$typecast .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
$field_def .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
}
// Remove old check constraints.
......@@ -700,7 +700,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
// the typecast does not work for conversions to bytea.
// @see http://www.postgresql.org/docs/current/static/datatype-binary.html
if ($spec['pgsql_type'] != 'bytea') {
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $typecast . ' USING "' . $field . '"::' . $typecast);
$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.
......@@ -709,7 +709,7 @@ public function changeField($table, $field, $field_new, $spec, $new_keys = array
// 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 ' . $typecast . ' USING decode(replace("' . $field . '"' . ", '\\', '\\\\'), 'escape');");
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", '\\', '\\\\'), 'escape');");
}
}
......
......@@ -477,4 +477,64 @@ protected function assertFieldCharacteristics($table_name, $field_name, $field_s
$this->assertEqual($field_value, $field_spec['default'], 'Default value registered.');
}
}
/**
* Tests changing columns between numeric types.
*/
function testSchemaChangeField() {
$field_specs = array(
array('type' => 'int', 'size' => 'normal','not null' => FALSE),
array('type' => 'int', 'size' => 'normal', 'not null' => TRUE, 'initial' => 1, 'default' => 17),
array('type' => 'float', 'size' => 'normal', 'not null' => FALSE),
array('type' => 'float', 'size' => 'normal', 'not null' => TRUE, 'initial' => 1, 'default' => 7.3),
array('type' => 'numeric', 'scale' => 2, 'precision' => 10, 'not null' => FALSE),
array('type' => 'numeric', 'scale' => 2, 'precision' => 10, 'not null' => TRUE, 'initial' => 1, 'default' => 7),
);
foreach ($field_specs as $i => $old_spec) {
foreach ($field_specs as $j => $new_spec) {
if ($i === $j) {
// Do not change a field into itself.
continue;
}
$this->assertFieldChange($old_spec, $new_spec);
}
}
}
/**
* Asserts that a field can be changed from one spec to another.
*
* @param $old_spec
* The beginning field specification.
* @param $new_spec
* The ending field specification.
*/
protected function assertFieldChange($old_spec, $new_spec) {
$table_name = 'test_table_' . ($this->counter++);
$table_spec = array(
'fields' => array(
'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
'test_field' => $old_spec,
),
'primary key' => array('serial_column'),
);
db_create_table($table_name, $table_spec);
$this->pass(format_string('Table %table created.', array('%table' => $table_name)));
// Check the characteristics of the field.
$this->assertFieldCharacteristics($table_name, 'test_field', $old_spec);
// Remove inserted rows.
db_truncate($table_name)->execute();
// Change the field.
db_change_field($table_name, 'test_field', 'test_field', $new_spec);
// Check the field was changed.
$this->assertFieldCharacteristics($table_name, 'test_field', $new_spec);
// Clean-up.
db_drop_table($table_name);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment