#1004068 by Damien Tournoud, dmigtrig01: Complete the implementation of DatabaseSchema::addField() for SQLite... gets us to 100% tests passing in SQLite! :D

merge-requests/26/head
Angie Byron 2010-12-23 01:43:38 +00:00
parent 925722a804
commit bb344c82d5
1 changed files with 71 additions and 24 deletions

View File

@ -276,7 +276,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
return TRUE;
}
public function addField($table, $field, $spec, $keys_new = array()) {
public function addField($table, $field, $specification, $keys_new = array()) {
if (!$this->tableExists($table)) {
throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
}
@ -284,10 +284,50 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
}
// TODO: $keys_new is not supported yet.
$query = 'ALTER TABLE {' . $table . '} ADD ';
$query .= $this->createFieldSql($field, $this->processField($spec));
$this->connection->query($query);
// SQLite doesn't have a full-featured ALTER TABLE statement. It only
// supports adding new fields to a table, in some simple cases. In most
// cases, we have to create a new table and copy the data over.
if (empty($keys_new) && (empty($specification['not null']) || isset($specification['default']))) {
// When we don't have to create new keys and we are not creating a
// NOT NULL column without a default value, we can use the quicker version.
$query = 'ALTER TABLE {' . $table . '} ADD ' . $this->createFieldSql($field, $this->processField($specification));
$this->connection->query($query);
// Apply the initial value if set.
if (isset($specification['initial'])) {
$this->connection->update($table)
->fields(array($field => $specification['initial']))
->execute();
}
}
else {
// We cannot add the field directly. Use the slower table alteration
// method, starting from the old schema.
$old_schema = $this->introspectSchema($table);
$new_schema = $old_schema;
// Add the new field.
$new_schema['fields'][$field] = $specification;
// Build the mapping between the old fields and the new fields.
$mapping = array();
if (isset($specification['initial'])) {
// If we have a initial value, copy it over.
$mapping[$field] = array(
'expression' => ':newfieldinitial',
'arguments' => array(':newfieldinitial' => $specification['initial']),
);
}
else {
// Else use the default of the field.
$mapping[$field] = NULL;
}
// Add the new indexes.
$new_schema += $keys_new;
$this->alterTable($table, $old_schema, $new_schema, $mapping);
}
}
/**
@ -303,7 +343,13 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
* @param $new_schema
* The new schema array for the table.
* @param $mapping
* An optional mapping between old fields => new fields.
* An optional mapping between the fields of the old specification and the
* fields of the new specification. An associative array, whose keys are
* the fields of the new table, and values can take two possible forms:
* - a simple string, which is interpreted as the name of a field of the
* old table,
* - an associative array with two keys 'expression' and 'arguments',
* that will be used as an expression field.
*/
protected function alterTable($table, $old_schema, $new_schema, array $mapping = array()) {
$i = 0;
@ -313,22 +359,25 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
$this->createTable($new_table, $new_schema);
// Complete the mapping.
$old_keys = array_keys($old_schema['fields']);
$mapping += array_combine($old_keys, $old_keys);
// Build a SQL query to migrate the data from the old table to the new.
$select = $this->connection->select($table);
$fields = &$select->getFields();
// Map the fields.
foreach ($old_keys as $key) {
if (isset($mapping[$key])) {
// Don't use ->addField() here because it messes-up with the aliases.
$fields[$mapping[$key]] = array(
'field' => $key,
'table' => $table,
'alias' => $mapping[$key],
);
// Complete the mapping.
$possible_keys = array_keys($new_schema['fields']);
$mapping += array_combine($possible_keys, $possible_keys);
// Now add the fields.
foreach ($mapping as $field_alias => $field_source) {
// Just ignore this field (ie. use it's default value).
if (!isset($field_source)) {
continue;
}
if (is_array($field_source)) {
$select->addExpression($field_source['expression'], $field_alias, $field_source['arguments']);
}
else {
$select->addField($table, $field_source, $field_alias);
}
}
@ -427,8 +476,6 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
$old_schema = $this->introspectSchema($table);
$new_schema = $old_schema;
$mapping = array($field => NULL);
unset($new_schema['fields'][$field]);
foreach ($new_schema['indexes'] as $index => $fields) {
foreach ($fields as $key => $field_name) {
@ -441,7 +488,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
unset($new_schema['indexes'][$index]);
}
}
$this->alterTable($table, $old_schema, $new_schema, $mapping);
$this->alterTable($table, $old_schema, $new_schema);
return TRUE;
}
@ -458,7 +505,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
// Map the old field to the new field.
if ($field != $field_new) {
$mapping[$field] = $field_new;
$mapping[$field_new] = $field;
}
else {
$mapping = array();