diff --git a/core/includes/database.inc b/core/includes/database.inc
index 5f08559..2858ea2 100644
--- a/core/includes/database.inc
+++ b/core/includes/database.inc
@@ -699,7 +699,7 @@ function db_rename_table($table, $new_name) {
  * @return \Drupal\Core\Database\StatementInterface
  *   The result of the executed query.
  *
- * @see \Drupal\Core\Database\Schema::copyTable()
+ * @see \Drupal\Core\Database\SchemaInterface::copyTable()
  */
 function db_copy_table_schema($source, $destination) {
   return Database::getConnection()->schema()->copyTable($source, $destination);
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index 6e87303..f433026 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Connection
+ * Contains \Drupal\Core\Database\Connection.
  */
 
 namespace Drupal\Core\Database;
@@ -757,7 +757,7 @@ public function truncate($table, array $options = array()) {
    *
    * This method will lazy-load the appropriate schema library file.
    *
-   * @return \Drupal\Core\Database\Schema
+   * @return \Drupal\Core\Database\SchemaInterface
    *   The database Schema object for this connection.
    */
   public function schema() {
diff --git a/core/lib/Drupal/Core/Database/Schema.php b/core/lib/Drupal/Core/Database/DatabaseSchema.php
similarity index 58%
rename from core/lib/Drupal/Core/Database/Schema.php
rename to core/lib/Drupal/Core/Database/DatabaseSchema.php
index bf7107a..0499dbd 100644
--- a/core/lib/Drupal/Core/Database/Schema.php
+++ b/core/lib/Drupal/Core/Database/DatabaseSchema.php
@@ -2,14 +2,13 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Schema
+ * Contains \Drupal\Core\Database\DatabaseSchema.
  */
 
 namespace Drupal\Core\Database;
 
-use Drupal\Core\Database\SchemaObjectExistsException;
 use Drupal\Core\Database\Query\Condition;
-use Drupal\Core\Database\Query\PlaceholderInterface;
+use Drupal\Core\Database\Query\PlaceholderTrait;
 
 /**
  * @defgroup schemaapi Schema API
@@ -162,15 +161,13 @@
  *
  * @see drupal_install_schema()
  */
-
-abstract class Schema implements PlaceholderInterface {
-
-  protected $connection;
+abstract class DatabaseSchema implements SchemaInterface {
+  use PlaceholderTrait;
 
   /**
-   * The placeholder counter.
+   * @var \Drupal\Core\Database\Connection
    */
-  protected $placeholder = 0;
+  protected $connection;
 
   /**
    * Definition of prefixInfo array structure.
@@ -183,12 +180,7 @@
    */
   protected $defaultSchema = 'public';
 
-  /**
-   * A unique identifier for this query object.
-   */
-  protected $uniqueIdentifier;
-
-  public function __construct($connection) {
+  public function __construct(Connection $connection) {
     $this->uniqueIdentifier = uniqid('', TRUE);
     $this->connection = $connection;
   }
@@ -201,29 +193,15 @@ public function __clone() {
   }
 
   /**
-   * Implements PlaceHolderInterface::uniqueIdentifier().
-   */
-  public function uniqueIdentifier() {
-    return $this->uniqueIdentifier;
-  }
-
-  /**
-   * Implements PlaceHolderInterface::nextPlaceholder().
-   */
-  public function nextPlaceholder() {
-    return $this->placeholder++;
-  }
-
-  /**
    * Get information about the table name and schema from the prefix.
    *
-   * @param
-   *   Name of table to look prefix up for. Defaults to 'default' because thats
-   *   default key for prefix.
-   * @param $add_prefix
+   * @param string $table
+   *   Name of table to look prefix up for. Defaults to 'default' because that
+   *   is the default key for prefix.
+   * @param bool $add_prefix
    *   Boolean that indicates whether the given table name should be prefixed.
    *
-   * @return
+   * @return array
    *   A keyed array with information about the schema, table name and prefix.
    */
   protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
@@ -251,11 +229,9 @@ protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
   }
 
   /**
-   * Create names for indexes, primary keys and constraints.
-   *
-   * This prevents using {} around non-table names like indexes and keys.
+   * {@inheritdoc}
    */
-  function prefixNonTable($table) {
+  public function prefixNonTable($table) {
     $args = func_get_args();
     $info = $this->getPrefixInfo($table);
     $args[0] = $info['table'];
@@ -302,13 +278,7 @@ protected function buildTableNameCondition($table_name, $operator = '=', $add_pr
   }
 
   /**
-   * Check if a table exists.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   *
-   * @return
-   *   TRUE if the given table exists, otherwise FALSE.
+   * {@inheritdoc}
    */
   public function tableExists($table) {
     $condition = $this->buildTableNameCondition($table);
@@ -322,14 +292,7 @@ public function tableExists($table) {
   }
 
   /**
-   * Find all tables that are like the specified base table name.
-   *
-   * @param $table_expression
-   *   An SQL expression, for example "simpletest%" (without the quotes).
-   *   BEWARE: this is not prefixed, the caller should take care of that.
-   *
-   * @return
-   *   Array, both the keys and the values are the matching tables.
+   * {@inheritdoc}
    */
   public function findTables($table_expression) {
     $condition = $this->buildTableNameCondition($table_expression, 'LIKE', FALSE);
@@ -344,15 +307,7 @@ public function findTables($table_expression) {
   }
 
   /**
-   * Check if a column exists in the given table.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   * @param $name
-   *   The name of the column.
-   *
-   * @return
-   *   TRUE if the given column exists, otherwise FALSE.
+   * {@inheritdoc}
    */
   public function fieldExists($table, $column) {
     $condition = $this->buildTableNameCondition($table);
@@ -367,359 +322,119 @@ public function fieldExists($table, $column) {
   }
 
   /**
-   * Returns a mapping of Drupal schema field names to DB-native field types.
-   *
-   * Because different field types do not map 1:1 between databases, Drupal has
-   * its own normalized field type names. This function returns a driver-specific
-   * mapping table from Drupal names to the native names for each database.
-   *
-   * @return array
-   *   An array of Schema API field types to driver-specific field types.
+   * {@inheritdoc}
+   */
+  public function createTable($name, $table) {
+    if ($this->tableExists($name)) {
+      throw new SchemaObjectExistsException(t('Table @name already exists.', array('@name' => $name)));
+    }
+    $statements = $this->createTableSql($name, $table);
+    foreach ($statements as $statement) {
+      $this->connection->query($statement);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldNames($fields) {
+    $return = array();
+    foreach ($fields as $field) {
+      if (is_array($field)) {
+        $return[] = $field[0];
+      }
+      else {
+        $return[] = $field;
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareComment($comment, $length = NULL) {
+    return $this->connection->quote($comment);
+  }
+
+  /**
+   * {@inheritdoc}
    */
   abstract public function getFieldTypeMap();
 
   /**
-   * Rename a table.
-   *
-   * @param $table
-   *   The table to be renamed.
-   * @param $new_name
-   *   The new name for the table.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If a table with the specified new name already exists.
+   * {@inheritdoc}
    */
   abstract public function renameTable($table, $new_name);
 
   /**
-   * Drop a table.
-   *
-   * @param $table
-   *   The table to be dropped.
-   *
-   * @return
-   *   TRUE if the table was successfully dropped, FALSE if there was no table
-   *   by that name to begin with.
+   * {@inheritdoc}
    */
   abstract public function dropTable($table);
 
   /**
-   * Copies the table schema.
-   *
-   * @param string $source
-   *   The name of the table to be used as source.
-   * @param string $destination
-   *   The name of the table to be used as destination.
-   *
-   * @return \Drupal\Core\Database\StatementInterface
-   *   The result of the executed query.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   Thrown when the source table does not exist.
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   Thrown when the destination table already exists.
+   * {@inheritdoc}
    */
   abstract public function copyTable($source, $destination);
 
   /**
-   * Add a new field to a table.
-   *
-   * @param $table
-   *   Name of the table to be altered.
-   * @param $field
-   *   Name of the field to be added.
-   * @param $spec
-   *   The field specification array, as taken from a schema definition.
-   *   The specification may also contain the key 'initial', the newly
-   *   created field will be set to the value of the key in all rows.
-   *   This is most useful for creating NOT NULL columns with no default
-   *   value in existing tables.
-   * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
-   *   table along with adding the field. The format is the same as a
-   *   table specification but without the 'fields' element. If you are
-   *   adding a type 'serial' field, you MUST specify at least one key
-   *   or index including it in this array. See db_change_field() for more
-   *   explanation why.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified table already has a field by that name.
+   * {@inheritdoc}
    */
   abstract public function addField($table, $field, $spec, $keys_new = array());
 
   /**
-   * Drop a field.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be dropped.
-   *
-   * @return
-   *   TRUE if the field was successfully dropped, FALSE if there was no field
-   *   by that name to begin with.
+   * {@inheritdoc}
+   */
+  abstract public function changeField($table, $field, $field_new, $spec, $keys_new = array());
+
+  /**
+   * {@inheritdoc}
    */
   abstract public function dropField($table, $field);
 
   /**
-   * Set the default value for a field.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be altered.
-   * @param $default
-   *   Default value to be set. NULL for 'default NULL'.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table or field doesn't exist.
+   * {@inheritdoc}
    */
   abstract public function fieldSetDefault($table, $field, $default);
 
   /**
-   * Set a field to have no default value.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be altered.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table or field doesn't exist.
+   * {@inheritdoc}
    */
   abstract public function fieldSetNoDefault($table, $field);
 
   /**
-   * Checks if an index exists in the given table.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   * @param $name
-   *   The name of the index in drupal (no prefixing).
-   *
-   * @return
-   *   TRUE if the given index exists, otherwise FALSE.
+   * {@inheritdoc}
    */
   abstract public function indexExists($table, $name);
 
   /**
-   * Add a primary key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $fields
-   *   Fields for the primary key.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified table already has a primary key.
+   * {@inheritdoc}
    */
   abstract public function addPrimaryKey($table, $fields);
 
   /**
-   * Drop the primary key.
-   *
-   * @param $table
-   *   The table to be altered.
-   *
-   * @return
-   *   TRUE if the primary key was successfully dropped, FALSE if there was no
-   *   primary key on this table to begin with.
+   * {@inheritdoc}
    */
   abstract public function dropPrimaryKey($table);
 
   /**
-   * Add a unique key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the key.
-   * @param $fields
-   *   An array of field names.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified table already has a key by that name.
+   * {@inheritdoc}
    */
   abstract public function addUniqueKey($table, $name, $fields);
 
   /**
-   * Drop a unique key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the key.
-   *
-   * @return
-   *   TRUE if the key was successfully dropped, FALSE if there was no key by
-   *   that name to begin with.
+   * {@inheritdoc}
    */
   abstract public function dropUniqueKey($table, $name);
 
   /**
-   * Add an index.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the index.
-   * @param $fields
-   *   An array of field names.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified table already has an index by that name.
+   * {@inheritdoc}
    */
   abstract public function addIndex($table, $name, $fields);
 
   /**
-   * Drop an index.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the index.
-   *
-   * @return
-   *   TRUE if the index was successfully dropped, FALSE if there was no index
-   *   by that name to begin with.
+   * {@inheritdoc}
    */
   abstract public function dropIndex($table, $name);
 
-  /**
-   * Change a field definition.
-   *
-   * IMPORTANT NOTE: To maintain database portability, you have to explicitly
-   * recreate all indices and primary keys that are using the changed field.
-   *
-   * That means that you have to drop all affected keys and indexes with
-   * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
-   * To recreate the keys and indices, pass the key definitions as the
-   * optional $keys_new argument directly to db_change_field().
-   *
-   * For example, suppose you have:
-   * @code
-   * $schema['foo'] = array(
-   *   'fields' => array(
-   *     'bar' => array('type' => 'int', 'not null' => TRUE)
-   *   ),
-   *   'primary key' => array('bar')
-   * );
-   * @endcode
-   * and you want to change foo.bar to be type serial, leaving it as the
-   * primary key. The correct sequence is:
-   * @code
-   * db_drop_primary_key('foo');
-   * db_change_field('foo', 'bar', 'bar',
-   *   array('type' => 'serial', 'not null' => TRUE),
-   *   array('primary key' => array('bar')));
-   * @endcode
-   *
-   * The reasons for this are due to the different database engines:
-   *
-   * On PostgreSQL, changing a field definition involves adding a new field
-   * and dropping an old one which* causes any indices, primary keys and
-   * sequences (from serial-type fields) that use the changed field to be dropped.
-   *
-   * On MySQL, all type 'serial' fields must be part of at least one key
-   * or index as soon as they are created. You cannot use
-   * db_add_{primary_key,unique_key,index}() for this purpose because
-   * the ALTER TABLE command will fail to add the column without a key
-   * or index specification. The solution is to use the optional
-   * $keys_new argument to create the key or index at the same time as
-   * field.
-   *
-   * You could use db_add_{primary_key,unique_key,index}() in all cases
-   * unless you are converting a field to be type serial. You can use
-   * the $keys_new argument in all cases.
-   *
-   * @param $table
-   *   Name of the table.
-   * @param $field
-   *   Name of the field to change.
-   * @param $field_new
-   *   New name for the field (set to the same as $field if you don't want to change the name).
-   * @param $spec
-   *   The field specification for the new field.
-   * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
-   *   table along with changing the field. The format is the same as a
-   *   table specification but without the 'fields' element.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
-   *   If the specified table or source field doesn't exist.
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified destination field already exists.
-   */
-  abstract public function changeField($table, $field, $field_new, $spec, $keys_new = array());
-
-  /**
-   * Create a new table from a Drupal table definition.
-   *
-   * @param $name
-   *   The name of the table to create.
-   * @param $table
-   *   A Schema API table definition array.
-   *
-   * @throws \Drupal\Core\Database\SchemaObjectExistsException
-   *   If the specified table already exists.
-   */
-  public function createTable($name, $table) {
-    if ($this->tableExists($name)) {
-      throw new SchemaObjectExistsException(t('Table @name already exists.', array('@name' => $name)));
-    }
-    $statements = $this->createTableSql($name, $table);
-    foreach ($statements as $statement) {
-      $this->connection->query($statement);
-    }
-  }
-
-  /**
-   * Return an array of field names from an array of key/index column specifiers.
-   *
-   * This is usually an identity function but if a key/index uses a column prefix
-   * specification, this function extracts just the name.
-   *
-   * @param $fields
-   *   An array of key/index column specifiers.
-   *
-   * @return
-   *   An array of field names.
-   */
-  public function fieldNames($fields) {
-    $return = array();
-    foreach ($fields as $field) {
-      if (is_array($field)) {
-        $return[] = $field[0];
-      }
-      else {
-        $return[] = $field;
-      }
-    }
-    return $return;
-  }
-
-  /**
-   * Prepare a table or column comment for database query.
-   *
-   * @param $comment
-   *   The comment string to prepare.
-   * @param $length
-   *   Optional upper limit on the returned string length.
-   *
-   * @return
-   *   The prepared comment.
-   */
-  public function prepareComment($comment, $length = NULL) {
-    return $this->connection->quote($comment);
-  }
 }
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
index e6940dc..bbc040c 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -2,17 +2,17 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Driver\mysql\Schema
+ * Contains Drupal\Core\Database\Driver\mysql\Schema.
  */
 
 namespace Drupal\Core\Database\Driver\mysql;
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Database\DatabaseSchema;
 use Drupal\Core\Database\Query\Condition;
 use Drupal\Core\Database\SchemaObjectExistsException;
 use Drupal\Core\Database\SchemaObjectDoesNotExistException;
-use Drupal\Core\Database\Schema as DatabaseSchema;
 
 /**
  * @addtogroup schemaapi
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
index 72686ea..ae4d1bf 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
@@ -2,17 +2,14 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Driver\pgsql\Schema
+ * Contains \Drupal\Core\Database\Driver\pgsql\Schema.
  */
 
 namespace Drupal\Core\Database\Driver\pgsql;
 
-use Drupal\Component\Utility\String;
-use Drupal\Core\Database\Database;
-use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Database\DatabaseSchema;
 use Drupal\Core\Database\SchemaObjectExistsException;
 use Drupal\Core\Database\SchemaObjectDoesNotExistException;
-use Drupal\Core\Database\Schema as DatabaseSchema;
 
 /**
  * @addtogroup schemaapi
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
index 45149da..00bb998 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
@@ -2,15 +2,15 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Driver\sqlite\Schema
+ * Contains \Drupal\Core\Database\Driver\sqlite\Schema.
  */
 
 namespace Drupal\Core\Database\Driver\sqlite;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Database\DatabaseSchema;
 use Drupal\Core\Database\SchemaObjectExistsException;
 use Drupal\Core\Database\SchemaObjectDoesNotExistException;
-use Drupal\Core\Database\Schema as DatabaseSchema;
 
 /**
  * @ingroup schemaapi
diff --git a/core/lib/Drupal/Core/Database/Query/PlaceholderTrait.php b/core/lib/Drupal/Core/Database/Query/PlaceholderTrait.php
new file mode 100644
index 0000000..5660a7f
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/PlaceholderTrait.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\Database\Query\PlaceholderTrait.
+ */
+
+namespace Drupal\Core\Database\Query;
+
+/**
+ * @see \Drupal\Core\Database\Query\PlaceholderInterface
+ */
+trait PlaceholderTrait {
+
+  /**
+   * A unique identifier for this query object.
+   */
+  protected $uniqueIdentifier;
+
+  /**
+   * The placeholder counter.
+   */
+  protected $placeholder = 0;
+
+  /**
+   * Implements \Drupal\Core\Database\Query\PlaceholderInterface::uniqueIdentifier().
+   */
+  public function uniqueIdentifier() {
+    return $this->uniqueIdentifier;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function nextPlaceholder() {
+    return $this->placeholder++;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Query.php b/core/lib/Drupal/Core/Database/Query/Query.php
index ad1f75e..3365225 100644
--- a/core/lib/Drupal/Core/Database/Query/Query.php
+++ b/core/lib/Drupal/Core/Database/Query/Query.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Query\Query
+ * Contains \Drupal\Core\Database\Query\Query.
  */
 
 namespace Drupal\Core\Database\Query;
@@ -17,6 +17,7 @@
  * query object into a prepared statement.
  */
 abstract class Query implements PlaceholderInterface {
+  use PlaceholderTrait;
 
   /**
    * The connection object on which to run this query.
@@ -47,16 +48,6 @@
   protected $queryOptions;
 
   /**
-   * A unique identifier for this query object.
-   */
-  protected $uniqueIdentifier;
-
-  /**
-   * The placeholder counter.
-   */
-  protected $nextPlaceholder = 0;
-
-  /**
    * An array of comments that can be prepended to a query.
    *
    * @var array
@@ -121,23 +112,6 @@ public function __clone() {
   abstract public function __toString();
 
   /**
-   * Returns a unique identifier for this object.
-   */
-  public function uniqueIdentifier() {
-    return $this->uniqueIdentifier;
-  }
-
-  /**
-   * Gets the next placeholder value for this query object.
-   *
-   * @return int
-   *   Next placeholder value.
-   */
-  public function nextPlaceholder() {
-    return $this->nextPlaceholder++;
-  }
-
-  /**
    * Adds a comment to the query.
    *
    * By adding a comment to a query, you can more easily find it in your
diff --git a/core/lib/Drupal/Core/Database/Query/SelectExtender.php b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
index 9a378d2..bec0123 100644
--- a/core/lib/Drupal/Core/Database/Query/SelectExtender.php
+++ b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Definition of Drupal\Core\Database\Query\SelectExtender
+ * Contains \Drupal\Core\Database\Query\SelectExtender.
  */
 
 namespace Drupal\Core\Database\Query;
@@ -13,6 +13,7 @@
  * The base extender class for Select queries.
  */
 class SelectExtender implements SelectInterface {
+  use PlaceholderTrait;
 
   /**
    * The Select query object we are extending/decorating.
@@ -28,36 +29,12 @@ class SelectExtender implements SelectInterface {
    */
   protected $connection;
 
-  /**
-   * A unique identifier for this query object.
-   */
-  protected $uniqueIdentifier;
-
-  /**
-   * The placeholder counter.
-   */
-  protected $placeholder = 0;
-
   public function __construct(SelectInterface $query, Connection $connection) {
     $this->uniqueIdentifier = uniqid('', TRUE);
     $this->query = $query;
     $this->connection = $connection;
   }
 
-  /**
-   * Implements Drupal\Core\Database\Query\PlaceholderInterface::uniqueIdentifier().
-   */
-  public function uniqueIdentifier() {
-    return $this->uniqueIdentifier;
-  }
-
-  /**
-   * Implements Drupal\Core\Database\Query\PlaceholderInterface::nextPlaceholder().
-   */
-  public function nextPlaceholder() {
-    return $this->placeholder++;
-  }
-
   /* Implementations of Drupal\Core\Database\Query\AlterableInterface. */
 
   public function addTag($tag) {
diff --git a/core/lib/Drupal/Core/Database/SchemaInterface.php b/core/lib/Drupal/Core/Database/SchemaInterface.php
new file mode 100644
index 0000000..e8a05c3
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/SchemaInterface.php
@@ -0,0 +1,423 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\Database\SchemaInterface.
+ */
+
+namespace Drupal\Core\Database;
+
+use Drupal\Core\Database\Query\PlaceholderInterface;
+
+interface SchemaInterface extends PlaceholderInterface {
+
+  /**
+   * Create names for indexes, primary keys and constraints.
+   *
+   * This prevents using {} around non-table names like indexes and keys.
+   *
+   * @param string $table
+   *   Name of table to look prefix up for. Defaults to 'default' because that
+   *   is the default key for prefix.
+   *
+   * @return string
+   *   A string identifier based upon the parameters passed to this method.
+   */
+  public function prefixNonTable($table);
+
+  /**
+   * Check if a table exists.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   *
+   * @return bool
+   *   TRUE if the given table exists, otherwise FALSE.
+   */
+  public function tableExists($table);
+
+  /**
+   * Find all tables that are like the specified base table name.
+   *
+   * @param string $table_expression
+   *   An SQL expression, for example "simpletest%" (without the quotes).
+   *   BEWARE: this is not prefixed, the caller should take care of that.
+   *
+   * @return array
+   *   Array, both the keys and the values are the matching tables.
+   */
+  public function findTables($table_expression);
+
+  /**
+   * Check if a column exists in the given table.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   * @param $column
+   *   The name of the column.
+   *
+   * @return bool
+   *   TRUE if the given column exists, otherwise FALSE.
+   */
+  public function fieldExists($table, $column);
+
+  /**
+   * Returns a mapping of Drupal schema field names to DB-native field types.
+   *
+   * Because different field types do not map 1:1 between databases, Drupal has
+   * its own normalized field type names. This function returns a driver-specific
+   * mapping table from Drupal names to the native names for each database.
+   *
+   * @return array
+   *   An array of Schema API field types to driver-specific field types.
+   */
+  public function getFieldTypeMap();
+
+  /**
+   * Rename a table.
+   *
+   * @param $table
+   *   The table to be renamed.
+   * @param $new_name
+   *   The new name for the table.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If a table with the specified new name already exists.
+   */
+  public function renameTable($table, $new_name);
+
+  /**
+   * Drop a table.
+   *
+   * @param $table
+   *   The table to be dropped.
+   *
+   * @return bool
+   *   TRUE if the table was successfully dropped, FALSE if there was no table
+   *   by that name to begin with.
+   */
+  public function dropTable($table);
+
+  /**
+   * Copies the table schema.
+   *
+   * @param string $source
+   *   The name of the table to be used as source.
+   * @param string $destination
+   *   The name of the table to be used as destination.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   Thrown when the source table does not exist.
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   Thrown when the destination table already exists.
+   */
+  public function copyTable($source, $destination);
+
+  /**
+   * Add a new field to a table.
+   *
+   * @param $table
+   *   Name of the table to be altered.
+   * @param $field
+   *   Name of the field to be added.
+   * @param $spec
+   *   The field specification array, as taken from a schema definition.
+   *   The specification may also contain the key 'initial', the newly
+   *   created field will be set to the value of the key in all rows.
+   *   This is most useful for creating NOT NULL columns with no default
+   *   value in existing tables.
+   * @param $keys_new
+   *   Optional keys and indexes specification to be created on the
+   *   table along with adding the field. The format is the same as a
+   *   table specification but without the 'fields' element. If you are
+   *   adding a type 'serial' field, you MUST specify at least one key
+   *   or index including it in this array. See db_change_field() for more
+   *   explanation why.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified table already has a field by that name.
+   */
+  public function addField($table, $field, $spec, $keys_new = array());
+
+  /**
+   * Drop a field.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be dropped.
+   *
+   * @return bool
+   *   TRUE if the field was successfully dropped, FALSE if there was no field
+   *   by that name to begin with.
+   */
+  public function dropField($table, $field);
+
+  /**
+   * Set the default value for a field.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be altered.
+   * @param $default
+   *   Default value to be set. NULL for 'default NULL'.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table or field doesn't exist.
+   */
+  public function fieldSetDefault($table, $field, $default);
+
+  /**
+   * Set a field to have no default value.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be altered.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table or field doesn't exist.
+   */
+  public function fieldSetNoDefault($table, $field);
+
+  /**
+   * Checks if an index exists in the given table.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   * @param $name
+   *   The name of the index in drupal (no prefixing).
+   *
+   * @return bool
+   *   TRUE if the given index exists, otherwise FALSE.
+   */
+  public function indexExists($table, $name);
+
+  /**
+   * Add a primary key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $fields
+   *   Fields for the primary key.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified table already has a primary key.
+   */
+  public function addPrimaryKey($table, $fields);
+
+  /**
+   * Drop the primary key.
+   *
+   * @param $table
+   *   The table to be altered.
+   *
+   * @return bool
+   *   TRUE if the primary key was successfully dropped, FALSE if there was no
+   *   primary key on this table to begin with.
+   */
+  public function dropPrimaryKey($table);
+
+  /**
+   * Add a unique key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the key.
+   * @param $fields
+   *   An array of field names.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified table already has a key by that name.
+   */
+  public function addUniqueKey($table, $name, $fields);
+
+  /**
+   * Drop a unique key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the key.
+   *
+   * @return bool
+   *   TRUE if the key was successfully dropped, FALSE if there was no key by
+   *   that name to begin with.
+   */
+  public function dropUniqueKey($table, $name);
+
+  /**
+   * Add an index.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the index.
+   * @param $fields
+   *   An array of field names.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified table already has an index by that name.
+   */
+  public function addIndex($table, $name, $fields);
+
+  /**
+   * Drop an index.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the index.
+   *
+   * @return bool
+   *   TRUE if the index was successfully dropped, FALSE if there was no index
+   *   by that name to begin with.
+   */
+  public function dropIndex($table, $name);
+
+  /**
+   * Change a field definition.
+   *
+   * IMPORTANT NOTE: To maintain database portability, you have to explicitly
+   * recreate all indices and primary keys that are using the changed field.
+   *
+   * That means that you have to drop all affected keys and indexes with
+   * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
+   * To recreate the keys and indices, pass the key definitions as the
+   * optional $keys_new argument directly to db_change_field().
+   *
+   * For example, suppose you have:
+   * @code
+   * $schema['foo'] = array(
+   *   'fields' => array(
+   *     'bar' => array('type' => 'int', 'not null' => TRUE)
+   *   ),
+   *   'primary key' => array('bar')
+   * );
+   * @endcode
+   * and you want to change foo.bar to be type serial, leaving it as the
+   * primary key. The correct sequence is:
+   * @code
+   * db_drop_primary_key('foo');
+   * db_change_field('foo', 'bar', 'bar',
+   *   array('type' => 'serial', 'not null' => TRUE),
+   *   array('primary key' => array('bar')));
+   * @endcode
+   *
+   * The reasons for this are due to the different database engines:
+   *
+   * On PostgreSQL, changing a field definition involves adding a new field
+   * and dropping an old one which* causes any indices, primary keys and
+   * sequences (from serial-type fields) that use the changed field to be dropped.
+   *
+   * On MySQL, all type 'serial' fields must be part of at least one key
+   * or index as soon as they are created. You cannot use
+   * db_add_{primary_key,unique_key,index}() for this purpose because
+   * the ALTER TABLE command will fail to add the column without a key
+   * or index specification. The solution is to use the optional
+   * $keys_new argument to create the key or index at the same time as
+   * field.
+   *
+   * You could use db_add_{primary_key,unique_key,index}() in all cases
+   * unless you are converting a field to be type serial. You can use
+   * the $keys_new argument in all cases.
+   *
+   * @param $table
+   *   Name of the table.
+   * @param $field
+   *   Name of the field to change.
+   * @param $field_new
+   *   New name for the field (set to the same as $field if you don't want to change the name).
+   * @param $spec
+   *   The field specification for the new field.
+   * @param $keys_new
+   *   Optional keys and indexes specification to be created on the
+   *   table along with changing the field. The format is the same as a
+   *   table specification but without the 'fields' element.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
+   *   If the specified table or source field doesn't exist.
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified destination field already exists.
+   */
+  public function changeField($table, $field, $field_new, $spec, $keys_new = array());
+
+  /**
+   * Create a new table from a Drupal table definition.
+   *
+   * @param $name
+   *   The name of the table to create.
+   * @param $table
+   *   A Schema API table definition array.
+   *
+   * @return \Drupal\Core\Database\StatementInterface
+   *   The result of the executed query.
+   *
+   * @throws \Drupal\Core\Database\SchemaObjectExistsException
+   *   If the specified table already exists.
+   */
+  public function createTable($name, $table);
+
+  /**
+   * Return an array of field names from an array of key/index column specifiers.
+   *
+   * This is usually an identity function but if a key/index uses a column prefix
+   * specification, this function extracts just the name.
+   *
+   * @param array $fields
+   *   An array of key/index column specifiers.
+   *
+   * @return array
+   *   An array of field names.
+   */
+  public function fieldNames($fields);
+
+  /**
+   * Prepare a table or column comment for database query.
+   *
+   * @param string $comment
+   *   The comment string to prepare.
+   * @param mixed integer|NULL $length
+   *   Optional upper limit on the returned string length.
+   *
+   * @return mixed string|bool
+   *   The prepared comment.
+   */
+  public function prepareComment($comment, $length = NULL);
+
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
index 5c1424d..5d17559 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\migrate\Tests;
 
-use Drupal\Core\Database\Schema;
+use Drupal\Core\Database\DatabaseSchema;
 
-class FakeDatabaseSchema extends Schema {
+class FakeDatabaseSchema extends DatabaseSchema {
 
   /**
    * As set on MigrateSqlSourceTestCase::databaseContents.
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
index d63caa4..25c2fb7 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
@@ -96,9 +96,7 @@ public function testEnsureTablesNotExist() {
       'fields' => $fields,
       'primary key' => array('sourceid1'),
     );
-    $schema = $this->getMockBuilder('Drupal\Core\Database\Schema')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $schema = $this->getMock('Drupal\Core\Database\SchemaInterface');
     $schema->expects($this->at(0))
       ->method('tableExists')
       ->with('migrate_map_sql_idmap_test')
@@ -144,9 +142,7 @@ public function testEnsureTablesNotExist() {
    * Tests the ensureTables method when the tables exist.
    */
   public function testEnsureTablesExist() {
-    $schema = $this->getMockBuilder('Drupal\Core\Database\Schema')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $schema = $this->getMock('Drupal\Core\Database\SchemaInterface');
     $schema->expects($this->at(0))
       ->method('tableExists')
       ->with('migrate_map_sql_idmap_test')
