diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc
index b6f95e4970de47885f66555234a1c89a659384b7..11ecd881a593a5ba52eb091f95cfd9648395cc55 100644
--- a/includes/database/sqlite/schema.inc
+++ b/includes/database/sqlite/schema.inc
@@ -276,7 +276,7 @@ public function dropTable($table) {
     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 @@ public function addField($table, $field, $spec, $keys_new = array()) {
       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 @@ public function addField($table, $field, $spec, $keys_new = array()) {
    * @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 @@ protected function alterTable($table, $old_schema, $new_schema, array $mapping =
 
     $this->createTable($new_table, $new_schema);
 
+    // Build a SQL query to migrate the data from the old table to the new.
+    $select = $this->connection->select($table);
+
     // Complete the mapping.
-    $old_keys = array_keys($old_schema['fields']);
-    $mapping += array_combine($old_keys, $old_keys);
+    $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;
+      }
 
-    $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],
-        );
+      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 @@ public function dropField($table, $field) {
     $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 @@ public function dropField($table, $field) {
         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 @@ public function changeField($table, $field, $field_new, $spec, $keys_new = array
 
     // Map the old field to the new field.
     if ($field != $field_new) {
-      $mapping[$field] = $field_new;
+      $mapping[$field_new] = $field;
     }
     else {
       $mapping = array();