diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 027e070a93af167a30ff25ae2fd535cd3c813985..52a8cb6a45b8d8c0067448d57295a6d48fd7c0ef 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1,5 +1,6 @@
 <?php
 
+use Drupal\Core\Database\Database;
 use Symfony\Component\ClassLoader\UniversalClassLoader;
 use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
 
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 757a0c642086f541288afba4329138f0902b1ab1..17f83ad63656ed349250af6f9e98d3a901003d0a 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Common functions that many Drupal modules will need to reference.
diff --git a/core/includes/database/database.inc b/core/includes/database/database.inc
index 7c96e070b006504551fd2373ed269b71703bdff7..c2df94988ffd6602810cb96ca3623a9d8deab81e 100644
--- a/core/includes/database/database.inc
+++ b/core/includes/database/database.inc
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Condition;
+
 /**
  * @file
  * Core systems for the database layer.
@@ -171,2109 +174,6 @@
  */
 
 
-/**
- * Base Database API class.
- *
- * This class provides a Drupal-specific extension of the PDO database
- * abstraction class in PHP. Every database driver implementation must provide a
- * concrete implementation of it to support special handling required by that
- * database.
- *
- * @see http://php.net/manual/en/book.pdo.php
- */
-abstract class DatabaseConnection extends PDO {
-
-  /**
-   * The database target this connection is for.
-   *
-   * We need this information for later auditing and logging.
-   *
-   * @var string
-   */
-  protected $target = NULL;
-
-  /**
-   * The key representing this connection.
-   *
-   * The key is a unique string which identifies a database connection. A
-   * connection can be a single server or a cluster of master and slaves (use
-   * target to pick between master and slave).
-   *
-   * @var string
-   */
-  protected $key = NULL;
-
-  /**
-   * The current database logging object for this connection.
-   *
-   * @var DatabaseLog
-   */
-  protected $logger = NULL;
-
-  /**
-   * Tracks the number of "layers" of transactions currently active.
-   *
-   * On many databases transactions cannot nest.  Instead, we track
-   * nested calls to transactions and collapse them into a single
-   * transaction.
-   *
-   * @var array
-   */
-  protected $transactionLayers = array();
-
-  /**
-   * Index of what driver-specific class to use for various operations.
-   *
-   * @var array
-   */
-  protected $driverClasses = array();
-
-  /**
-   * The name of the Statement class for this connection.
-   *
-   * @var string
-   */
-  protected $statementClass = 'DatabaseStatementBase';
-
-  /**
-   * Whether this database connection supports transactions.
-   *
-   * @var bool
-   */
-  protected $transactionSupport = TRUE;
-
-  /**
-   * Whether this database connection supports transactional DDL.
-   *
-   * Set to FALSE by default because few databases support this feature.
-   *
-   * @var bool
-   */
-  protected $transactionalDDLSupport = FALSE;
-
-  /**
-   * An index used to generate unique temporary table names.
-   *
-   * @var integer
-   */
-  protected $temporaryNameIndex = 0;
-
-  /**
-   * The connection information for this connection object.
-   *
-   * @var array
-   */
-  protected $connectionOptions = array();
-
-  /**
-   * The schema object for this connection.
-   *
-   * @var object
-   */
-  protected $schema = NULL;
-
-  /**
-   * The prefixes used by this database connection.
-   *
-   * @var array
-   */
-  protected $prefixes = array();
-
-  /**
-   * List of search values for use in prefixTables().
-   *
-   * @var array
-   */
-  protected $prefixSearch = array();
-
-  /**
-   * List of replacement values for use in prefixTables().
-   *
-   * @var array
-   */
-  protected $prefixReplace = array();
-
-  function __construct($dsn, $username, $password, $driver_options = array()) {
-    // Initialize and prepare the connection prefix.
-    $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
-
-    // Because the other methods don't seem to work right.
-    $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
-
-    // Call PDO::__construct and PDO::setAttribute.
-    parent::__construct($dsn, $username, $password, $driver_options);
-
-    // Set a specific PDOStatement class if the driver requires that.
-    if (!empty($this->statementClass)) {
-      $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
-    }
-  }
-
-  /**
-   * Returns the default query options for any given query.
-   *
-   * A given query can be customized with a number of option flags in an
-   * associative array:
-   * - target: The database "target" against which to execute a query. Valid
-   *   values are "default" or "slave". The system will first try to open a
-   *   connection to a database specified with the user-supplied key. If one
-   *   is not available, it will silently fall back to the "default" target.
-   *   If multiple databases connections are specified with the same target,
-   *   one will be selected at random for the duration of the request.
-   * - fetch: This element controls how rows from a result set will be
-   *   returned. Legal values include PDO::FETCH_ASSOC, PDO::FETCH_BOTH,
-   *   PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a
-   *   class. If a string is specified, each record will be fetched into a new
-   *   object of that class. The behavior of all other values is defined by PDO.
-   *   See http://php.net/manual/pdostatement.fetch.php
-   * - return: Depending on the type of query, different return values may be
-   *   meaningful. This directive instructs the system which type of return
-   *   value is desired. The system will generally set the correct value
-   *   automatically, so it is extremely rare that a module developer will ever
-   *   need to specify this value. Setting it incorrectly will likely lead to
-   *   unpredictable results or fatal errors. Legal values include:
-   *   - Database::RETURN_STATEMENT: Return the prepared statement object for
-   *     the query. This is usually only meaningful for SELECT queries, where
-   *     the statement object is how one accesses the result set returned by the
-   *     query.
-   *   - Database::RETURN_AFFECTED: Return the number of rows affected by an
-   *     UPDATE or DELETE query. Be aware that means the number of rows actually
-   *     changed, not the number of rows matched by the WHERE clause.
-   *   - Database::RETURN_INSERT_ID: Return the sequence ID (primary key)
-   *     created by an INSERT statement on a table that contains a serial
-   *     column.
-   *   - Database::RETURN_NULL: Do not return anything, as there is no
-   *     meaningful value to return. That is the case for INSERT queries on
-   *     tables that do not contain a serial column.
-   * - throw_exception: By default, the database system will catch any errors
-   *   on a query as an Exception, log it, and then rethrow it so that code
-   *   further up the call chain can take an appropriate action. To suppress
-   *   that behavior and simply return NULL on failure, set this option to
-   *   FALSE.
-   *
-   * @return
-   *   An array of default query options.
-   */
-  protected function defaultOptions() {
-    return array(
-      'target' => 'default',
-      'fetch' => PDO::FETCH_OBJ,
-      'return' => Database::RETURN_STATEMENT,
-      'throw_exception' => TRUE,
-    );
-  }
-
-  /**
-   * Returns the connection information for this connection object.
-   *
-   * Note that Database::getConnectionInfo() is for requesting information
-   * about an arbitrary database connection that is defined. This method
-   * is for requesting the connection information of this specific
-   * open connection object.
-   *
-   * @return
-   *   An array of the connection information. The exact list of
-   *   properties is driver-dependent.
-   */
-  public function getConnectionOptions() {
-    return $this->connectionOptions;
-  }
-
-  /**
-   * Set the list of prefixes used by this database connection.
-   *
-   * @param $prefix
-   *   The prefixes, in any of the multiple forms documented in
-   *   default.settings.php.
-   */
-  protected function setPrefix($prefix) {
-    if (is_array($prefix)) {
-      $this->prefixes = $prefix + array('default' => '');
-    }
-    else {
-      $this->prefixes = array('default' => $prefix);
-    }
-
-    // Set up variables for use in prefixTables(). Replace table-specific
-    // prefixes first.
-    $this->prefixSearch = array();
-    $this->prefixReplace = array();
-    foreach ($this->prefixes as $key => $val) {
-      if ($key != 'default') {
-        $this->prefixSearch[] = '{' . $key . '}';
-        $this->prefixReplace[] = $val . $key;
-      }
-    }
-    // Then replace remaining tables with the default prefix.
-    $this->prefixSearch[] = '{';
-    $this->prefixReplace[] = $this->prefixes['default'];
-    $this->prefixSearch[] = '}';
-    $this->prefixReplace[] = '';
-  }
-
-  /**
-   * Appends a database prefix to all tables in a query.
-   *
-   * Queries sent to Drupal should wrap all table names in curly brackets. This
-   * function searches for this syntax and adds Drupal's table prefix to all
-   * tables, allowing Drupal to coexist with other systems in the same database
-   * and/or schema if necessary.
-   *
-   * @param $sql
-   *   A string containing a partial or entire SQL query.
-   *
-   * @return
-   *   The properly-prefixed string.
-   */
-  public function prefixTables($sql) {
-    return str_replace($this->prefixSearch, $this->prefixReplace, $sql);
-  }
-
-  /**
-   * Find the prefix for a table.
-   *
-   * This function is for when you want to know the prefix of a table. This
-   * is not used in prefixTables due to performance reasons.
-   */
-  public function tablePrefix($table = 'default') {
-    if (isset($this->prefixes[$table])) {
-      return $this->prefixes[$table];
-    }
-    else {
-      return $this->prefixes['default'];
-    }
-  }
-
-  /**
-   * Prepares a query string and returns the prepared statement.
-   *
-   * This method caches prepared statements, reusing them when
-   * possible. It also prefixes tables names enclosed in curly-braces.
-   *
-   * @param $query
-   *   The query string as SQL, with curly-braces surrounding the
-   *   table names.
-   *
-   * @return DatabaseStatementInterface
-   *   A PDO prepared statement ready for its execute() method.
-   */
-  public function prepareQuery($query) {
-    $query = $this->prefixTables($query);
-
-    // Call PDO::prepare.
-    return parent::prepare($query);
-  }
-
-  /**
-   * Tells this connection object what its target value is.
-   *
-   * This is needed for logging and auditing. It's sloppy to do in the
-   * constructor because the constructor for child classes has a different
-   * signature. We therefore also ensure that this function is only ever
-   * called once.
-   *
-   * @param $target
-   *   The target this connection is for. Set to NULL (default) to disable
-   *   logging entirely.
-   */
-  public function setTarget($target = NULL) {
-    if (!isset($this->target)) {
-      $this->target = $target;
-    }
-  }
-
-  /**
-   * Returns the target this connection is associated with.
-   *
-   * @return
-   *   The target string of this connection.
-   */
-  public function getTarget() {
-    return $this->target;
-  }
-
-  /**
-   * Tells this connection object what its key is.
-   *
-   * @param $target
-   *   The key this connection is for.
-   */
-  public function setKey($key) {
-    if (!isset($this->key)) {
-      $this->key = $key;
-    }
-  }
-
-  /**
-   * Returns the key this connection is associated with.
-   *
-   * @return
-   *   The key of this connection.
-   */
-  public function getKey() {
-    return $this->key;
-  }
-
-  /**
-   * Associates a logging object with this connection.
-   *
-   * @param $logger
-   *   The logging object we want to use.
-   */
-  public function setLogger(DatabaseLog $logger) {
-    $this->logger = $logger;
-  }
-
-  /**
-   * Gets the current logging object for this connection.
-   *
-   * @return DatabaseLog
-   *   The current logging object for this connection. If there isn't one,
-   *   NULL is returned.
-   */
-  public function getLogger() {
-    return $this->logger;
-  }
-
-  /**
-   * Creates the appropriate sequence name for a given table and serial field.
-   *
-   * This information is exposed to all database drivers, although it is only
-   * useful on some of them. This method is table prefix-aware.
-   *
-   * @param $table
-   *   The table name to use for the sequence.
-   * @param $field
-   *   The field name to use for the sequence.
-   *
-   * @return
-   *   A table prefix-parsed string for the sequence name.
-   */
-  public function makeSequenceName($table, $field) {
-    return $this->prefixTables('{' . $table . '}_' . $field . '_seq');
-  }
-
-  /**
-   * Flatten an array of query comments into a single comment string.
-   *
-   * The comment string will be sanitized to avoid SQL injection attacks.
-   *
-   * @param $comments
-   *   An array of query comment strings.
-   *
-   * @return
-   *   A sanitized comment string.
-   */
-  public function makeComment($comments) {
-    if (empty($comments))
-      return '';
-
-    // Flatten the array of comments.
-    $comment = implode('; ', $comments);
-
-    // Sanitize the comment string so as to avoid SQL injection attacks.
-    return '/* ' . $this->filterComment($comment) . ' */ ';
-  }
-
-  /**
-   * Sanitize a query comment string.
-   *
-   * Ensure a query comment does not include strings such as "* /" that might
-   * terminate the comment early. This avoids SQL injection attacks via the
-   * query comment. The comment strings in this example are separated by a
-   * space to avoid PHP parse errors.
-   *
-   * For example, the comment:
-   * @code
-   * db_update('example')
-   *  ->condition('id', $id)
-   *  ->fields(array('field2' => 10))
-   *  ->comment('Exploit * / DROP TABLE node; --')
-   *  ->execute()
-   * @endcode
-   *
-   * Would result in the following SQL statement being generated:
-   * @code
-   * "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..."
-   * @endcode
-   *
-   * Unless the comment is sanitised first, the SQL server would drop the
-   * node table and ignore the rest of the SQL statement.
-   *
-   * @param $comment
-   *   A query comment string.
-   *
-   * @return
-   *   A sanitized version of the query comment string.
-   */
-  protected function filterComment($comment = '') {
-    return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
-  }
-
-  /**
-   * Executes a query string against the database.
-   *
-   * This method provides a central handler for the actual execution of every
-   * query. All queries executed by Drupal are executed as PDO prepared
-   * statements.
-   *
-   * @param $query
-   *   The query to execute. In most cases this will be a string containing
-   *   an SQL query with placeholders. An already-prepared instance of
-   *   DatabaseStatementInterface may also be passed in order to allow calling
-   *   code to manually bind variables to a query. If a
-   *   DatabaseStatementInterface is passed, the $args array will be ignored.
-   *   It is extremely rare that module code will need to pass a statement
-   *   object to this method. It is used primarily for database drivers for
-   *   databases that require special LOB field handling.
-   * @param $args
-   *   An array of arguments for the prepared statement. If the prepared
-   *   statement uses ? placeholders, this array must be an indexed array.
-   *   If it contains named placeholders, it must be an associative array.
-   * @param $options
-   *   An associative array of options to control how the query is run. See
-   *   the documentation for DatabaseConnection::defaultOptions() for details.
-   *
-   * @return DatabaseStatementInterface
-   *   This method will return one of: the executed statement, the number of
-   *   rows affected by the query (not the number matched), or the generated
-   *   insert IT of the last query, depending on the value of
-   *   $options['return']. Typically that value will be set by default or a
-   *   query builder and should not be set by a user. If there is an error,
-   *   this method will return NULL and may throw an exception if
-   *   $options['throw_exception'] is TRUE.
-   *
-   * @throws PDOException
-   */
-  public function query($query, array $args = array(), $options = array()) {
-
-    // Use default values if not already set.
-    $options += $this->defaultOptions();
-
-    try {
-      // We allow either a pre-bound statement object or a literal string.
-      // In either case, we want to end up with an executed statement object,
-      // which we pass to PDOStatement::execute.
-      if ($query instanceof DatabaseStatementInterface) {
-        $stmt = $query;
-        $stmt->execute(NULL, $options);
-      }
-      else {
-        $this->expandArguments($query, $args);
-        $stmt = $this->prepareQuery($query);
-        $stmt->execute($args, $options);
-      }
-
-      // Depending on the type of query we may need to return a different value.
-      // See DatabaseConnection::defaultOptions() for a description of each
-      // value.
-      switch ($options['return']) {
-        case Database::RETURN_STATEMENT:
-          return $stmt;
-        case Database::RETURN_AFFECTED:
-          return $stmt->rowCount();
-        case Database::RETURN_INSERT_ID:
-          return $this->lastInsertId();
-        case Database::RETURN_NULL:
-          return;
-        default:
-          throw new PDOException('Invalid return directive: ' . $options['return']);
-      }
-    }
-    catch (PDOException $e) {
-      if ($options['throw_exception']) {
-        // Add additional debug information.
-        if ($query instanceof DatabaseStatementInterface) {
-          $e->query_string = $stmt->getQueryString();
-        }
-        else {
-          $e->query_string = $query;
-        }
-        $e->args = $args;
-        throw $e;
-      }
-      return NULL;
-    }
-  }
-
-  /**
-   * Expands out shorthand placeholders.
-   *
-   * Drupal supports an alternate syntax for doing arrays of values. We
-   * therefore need to expand them out into a full, executable query string.
-   *
-   * @param $query
-   *   The query string to modify.
-   * @param $args
-   *   The arguments for the query.
-   *
-   * @return
-   *   TRUE if the query was modified, FALSE otherwise.
-   */
-  protected function expandArguments(&$query, &$args) {
-    $modified = FALSE;
-
-    // If the placeholder value to insert is an array, assume that we need
-    // to expand it out into a comma-delimited set of placeholders.
-    foreach (array_filter($args, 'is_array') as $key => $data) {
-      $new_keys = array();
-      foreach ($data as $i => $value) {
-        // This assumes that there are no other placeholders that use the same
-        // name.  For example, if the array placeholder is defined as :example
-        // and there is already an :example_2 placeholder, this will generate
-        // a duplicate key.  We do not account for that as the calling code
-        // is already broken if that happens.
-        $new_keys[$key . '_' . $i] = $value;
-      }
-
-      // Update the query with the new placeholders.
-      // preg_replace is necessary to ensure the replacement does not affect
-      // placeholders that start with the same exact text. For example, if the
-      // query contains the placeholders :foo and :foobar, and :foo has an
-      // array of values, using str_replace would affect both placeholders,
-      // but using the following preg_replace would only affect :foo because
-      // it is followed by a non-word character.
-      $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
-
-      // Update the args array with the new placeholders.
-      unset($args[$key]);
-      $args += $new_keys;
-
-      $modified = TRUE;
-    }
-
-    return $modified;
-  }
-
-  /**
-   * Gets the driver-specific override class if any for the specified class.
-   *
-   * @param string $class
-   *   The class for which we want the potentially driver-specific class.
-   * @param array $files
-   *   The name of the files in which the driver-specific class can be.
-   * @param $use_autoload
-   *   If TRUE, attempt to load classes using PHP's autoload capability
-   *   as well as the manual approach here.
-   * @return string
-   *   The name of the class that should be used for this driver.
-   */
-  public function getDriverClass($class, array $files = array(), $use_autoload = FALSE) {
-    if (empty($this->driverClasses[$class])) {
-      $driver = $this->driver();
-      $this->driverClasses[$class] = $class . '_' . $driver;
-      Database::loadDriverFile($driver, $files);
-      if (!class_exists($this->driverClasses[$class], $use_autoload)) {
-        $this->driverClasses[$class] = $class;
-      }
-    }
-    return $this->driverClasses[$class];
-  }
-
-  /**
-   * Prepares and returns a SELECT query object.
-   *
-   * @param $table
-   *   The base table for this query, that is, the first table in the FROM
-   *   clause. This table will also be used as the "base" table for query_alter
-   *   hook implementations.
-   * @param $alias
-   *   The alias of the base table of this query.
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return SelectQueryInterface
-   *   An appropriate SelectQuery object for this database connection. Note that
-   *   it may be a driver-specific subclass of SelectQuery, depending on the
-   *   driver.
-   *
-   * @see SelectQuery
-   */
-  public function select($table, $alias = NULL, array $options = array()) {
-    $class = $this->getDriverClass('SelectQuery', array('query.inc', 'select.inc'));
-    return new $class($table, $alias, $this, $options);
-  }
-
-  /**
-   * Prepares and returns an INSERT query object.
-   *
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return InsertQuery
-   *   A new InsertQuery object.
-   *
-   * @see InsertQuery
-   */
-  public function insert($table, array $options = array()) {
-    $class = $this->getDriverClass('InsertQuery', array('query.inc'));
-    return new $class($this, $table, $options);
-  }
-
-  /**
-   * Prepares and returns a MERGE query object.
-   *
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return MergeQuery
-   *   A new MergeQuery object.
-   *
-   * @see MergeQuery
-   */
-  public function merge($table, array $options = array()) {
-    $class = $this->getDriverClass('MergeQuery', array('query.inc'));
-    return new $class($this, $table, $options);
-  }
-
-
-  /**
-   * Prepares and returns an UPDATE query object.
-   *
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return UpdateQuery
-   *   A new UpdateQuery object.
-   *
-   * @see UpdateQuery
-   */
-  public function update($table, array $options = array()) {
-    $class = $this->getDriverClass('UpdateQuery', array('query.inc'));
-    return new $class($this, $table, $options);
-  }
-
-  /**
-   * Prepares and returns a DELETE query object.
-   *
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return DeleteQuery
-   *   A new DeleteQuery object.
-   *
-   * @see DeleteQuery
-   */
-  public function delete($table, array $options = array()) {
-    $class = $this->getDriverClass('DeleteQuery', array('query.inc'));
-    return new $class($this, $table, $options);
-  }
-
-  /**
-   * Prepares and returns a TRUNCATE query object.
-   *
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return TruncateQuery
-   *   A new TruncateQuery object.
-   *
-   * @see TruncateQuery
-   */
-  public function truncate($table, array $options = array()) {
-    $class = $this->getDriverClass('TruncateQuery', array('query.inc'));
-    return new $class($this, $table, $options);
-  }
-
-  /**
-   * Returns a DatabaseSchema object for manipulating the schema.
-   *
-   * This method will lazy-load the appropriate schema library file.
-   *
-   * @return DatabaseSchema
-   *   The DatabaseSchema object for this connection.
-   */
-  public function schema() {
-    if (empty($this->schema)) {
-      $class = $this->getDriverClass('DatabaseSchema', array('schema.inc'));
-      if (class_exists($class)) {
-        $this->schema = new $class($this);
-      }
-    }
-    return $this->schema;
-  }
-
-  /**
-   * Escapes a table name string.
-   *
-   * Force all table names to be strictly alphanumeric-plus-underscore.
-   * For some database drivers, it may also wrap the table name in
-   * database-specific escape characters.
-   *
-   * @return
-   *   The sanitized table name string.
-   */
-  public function escapeTable($table) {
-    return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
-  }
-
-  /**
-   * Escapes a field name string.
-   *
-   * Force all field names to be strictly alphanumeric-plus-underscore.
-   * For some database drivers, it may also wrap the field name in
-   * database-specific escape characters.
-   *
-   * @return
-   *   The sanitized field name string.
-   */
-  public function escapeField($field) {
-    return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
-  }
-
-  /**
-   * Escapes an alias name string.
-   *
-   * Force all alias names to be strictly alphanumeric-plus-underscore. In
-   * contrast to DatabaseConnection::escapeField() /
-   * DatabaseConnection::escapeTable(), this doesn't allow the period (".")
-   * because that is not allowed in aliases.
-   *
-   * @return
-   *   The sanitized field name string.
-   */
-  public function escapeAlias($field) {
-    return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
-  }
-
-  /**
-   * Escapes characters that work as wildcard characters in a LIKE pattern.
-   *
-   * The wildcard characters "%" and "_" as well as backslash are prefixed with
-   * a backslash. Use this to do a search for a verbatim string without any
-   * wildcard behavior.
-   *
-   * For example, the following does a case-insensitive query for all rows whose
-   * name starts with $prefix:
-   * @code
-   * $result = db_query(
-   *   'SELECT * FROM person WHERE name LIKE :pattern',
-   *   array(':pattern' => db_like($prefix) . '%')
-   * );
-   * @endcode
-   *
-   * Backslash is defined as escape character for LIKE patterns in
-   * DatabaseCondition::mapConditionOperator().
-   *
-   * @param $string
-   *   The string to escape.
-   *
-   * @return
-   *   The escaped string.
-   */
-  public function escapeLike($string) {
-    return addcslashes($string, '\%_');
-  }
-
-  /**
-   * Determines if there is an active transaction open.
-   *
-   * @return
-   *   TRUE if we're currently in a transaction, FALSE otherwise.
-   */
-  public function inTransaction() {
-    return ($this->transactionDepth() > 0);
-  }
-
-  /**
-   * Determines current transaction depth.
-   */
-  public function transactionDepth() {
-    return count($this->transactionLayers);
-  }
-
-  /**
-   * Returns a new DatabaseTransaction object on this connection.
-   *
-   * @param $name
-   *   Optional name of the savepoint.
-   *
-   * @see DatabaseTransaction
-   */
-  public function startTransaction($name = '') {
-    $class = $this->getDriverClass('DatabaseTransaction');
-    return new $class($this, $name);
-  }
-
-  /**
-   * Rolls back the transaction entirely or to a named savepoint.
-   *
-   * This method throws an exception if no transaction is active.
-   *
-   * @param $savepoint_name
-   *   The name of the savepoint. The default, 'drupal_transaction', will roll
-   *   the entire transaction back.
-   *
-   * @throws DatabaseTransactionNoActiveException
-   *
-   * @see DatabaseTransaction::rollback()
-   */
-  public function rollback($savepoint_name = 'drupal_transaction') {
-    if (!$this->supportsTransactions()) {
-      return;
-    }
-    if (!$this->inTransaction()) {
-      throw new DatabaseTransactionNoActiveException();
-    }
-    // A previous rollback to an earlier savepoint may mean that the savepoint
-    // in question has already been accidentally committed.
-    if (!isset($this->transactionLayers[$savepoint_name])) {
-      throw new DatabaseTransactionNoActiveException();
-    }
-
-    // We need to find the point we're rolling back to, all other savepoints
-    // before are no longer needed. If we rolled back other active savepoints,
-    // we need to throw an exception.
-    $rolled_back_other_active_savepoints = FALSE;
-    while ($savepoint = array_pop($this->transactionLayers)) {
-      if ($savepoint == $savepoint_name) {
-        // If it is the last the transaction in the stack, then it is not a
-        // savepoint, it is the transaction itself so we will need to roll back
-        // the transaction rather than a savepoint.
-        if (empty($this->transactionLayers)) {
-          break;
-        }
-        $this->query('ROLLBACK TO SAVEPOINT ' . $savepoint);
-        $this->popCommittableTransactions();
-        if ($rolled_back_other_active_savepoints) {
-          throw new DatabaseTransactionOutOfOrderException();
-        }
-        return;
-      }
-      else {
-        $rolled_back_other_active_savepoints = TRUE;
-      }
-    }
-    parent::rollBack();
-    if ($rolled_back_other_active_savepoints) {
-      throw new DatabaseTransactionOutOfOrderException();
-    }
-  }
-
-  /**
-   * Increases the depth of transaction nesting.
-   *
-   * If no transaction is already active, we begin a new transaction.
-   *
-   * @throws DatabaseTransactionNameNonUniqueException
-   *
-   * @see DatabaseTransaction
-   */
-  public function pushTransaction($name) {
-    if (!$this->supportsTransactions()) {
-      return;
-    }
-    if (isset($this->transactionLayers[$name])) {
-      throw new DatabaseTransactionNameNonUniqueException($name . " is already in use.");
-    }
-    // If we're already in a transaction then we want to create a savepoint
-    // rather than try to create another transaction.
-    if ($this->inTransaction()) {
-      $this->query('SAVEPOINT ' . $name);
-    }
-    else {
-      parent::beginTransaction();
-    }
-    $this->transactionLayers[$name] = $name;
-  }
-
-  /**
-   * Decreases the depth of transaction nesting.
-   *
-   * If we pop off the last transaction layer, then we either commit or roll
-   * back the transaction as necessary. If no transaction is active, we return
-   * because the transaction may have manually been rolled back.
-   *
-   * @param $name
-   *   The name of the savepoint
-   *
-   * @throws DatabaseTransactionNoActiveException
-   * @throws DatabaseTransactionCommitFailedException
-   *
-   * @see DatabaseTransaction
-   */
-  public function popTransaction($name) {
-    if (!$this->supportsTransactions()) {
-      return;
-    }
-    // The transaction has already been committed earlier. There is nothing we
-    // need to do. If this transaction was part of an earlier out-of-order
-    // rollback, an exception would already have been thrown by
-    // Database::rollback().
-    if (!isset($this->transactionLayers[$name])) {
-      return;
-    }
-
-    // Mark this layer as committable.
-    $this->transactionLayers[$name] = FALSE;
-    $this->popCommittableTransactions();
-  }
-
-  /**
-   * Internal function: commit all the transaction layers that can commit.
-   */
-  protected function popCommittableTransactions() {
-    // Commit all the committable layers.
-    foreach (array_reverse($this->transactionLayers) as $name => $active) {
-      // Stop once we found an active transaction.
-      if ($active) {
-        break;
-      }
-
-      // If there are no more layers left then we should commit.
-      unset($this->transactionLayers[$name]);
-      if (empty($this->transactionLayers)) {
-        if (!parent::commit()) {
-          throw new DatabaseTransactionCommitFailedException();
-        }
-      }
-      else {
-        $this->query('RELEASE SAVEPOINT ' . $name);
-      }
-    }
-  }
-
-  /**
-   * Runs a limited-range query on this database object.
-   *
-   * Use this as a substitute for ->query() when a subset of the query is to be
-   * returned. User-supplied arguments to the query should be passed in as
-   * separate parameters so that they can be properly escaped to avoid SQL
-   * injection attacks.
-   *
-   * @param $query
-   *   A string containing an SQL query.
-   * @param $args
-   *   An array of values to substitute into the query at placeholder markers.
-   * @param $from
-   *   The first result row to return.
-   * @param $count
-   *   The maximum number of result rows to return.
-   * @param $options
-   *   An array of options on the query.
-   *
-   * @return DatabaseStatementInterface
-   *   A database query result resource, or NULL if the query was not executed
-   *   correctly.
-   */
-  abstract public function queryRange($query, $from, $count, array $args = array(), array $options = array());
-
-  /**
-   * Generates a temporary table name.
-   *
-   * @return
-   *   A table name.
-   */
-  protected function generateTemporaryTableName() {
-    return "db_temporary_" . $this->temporaryNameIndex++;
-  }
-
-  /**
-   * Runs a SELECT query and stores its results in a temporary table.
-   *
-   * Use this as a substitute for ->query() when the results need to stored
-   * in a temporary table. Temporary tables exist for the duration of the page
-   * request. User-supplied arguments to the query should be passed in as
-   * separate parameters so that they can be properly escaped to avoid SQL
-   * injection attacks.
-   *
-   * Note that if you need to know how many results were returned, you should do
-   * a SELECT COUNT(*) on the temporary table afterwards.
-   *
-   * @param $query
-   *   A string containing a normal SELECT SQL query.
-   * @param $args
-   *   An array of values to substitute into the query at placeholder markers.
-   * @param $options
-   *   An associative array of options to control how the query is run. See
-   *   the documentation for DatabaseConnection::defaultOptions() for details.
-   *
-   * @return
-   *   The name of the temporary table.
-   */
-  abstract function queryTemporary($query, array $args = array(), array $options = array());
-
-  /**
-   * Returns the type of database driver.
-   *
-   * This is not necessarily the same as the type of the database itself. For
-   * instance, there could be two MySQL drivers, mysql and mysql_mock. This
-   * function would return different values for each, but both would return
-   * "mysql" for databaseType().
-   */
-  abstract public function driver();
-
-  /**
-   * Returns the version of the database server.
-   */
-  public function version() {
-    return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
-  }
-
-  /**
-   * Determines if this driver supports transactions.
-   *
-   * @return
-   *   TRUE if this connection supports transactions, FALSE otherwise.
-   */
-  public function supportsTransactions() {
-    return $this->transactionSupport;
-  }
-
-  /**
-   * Determines if this driver supports transactional DDL.
-   *
-   * DDL queries are those that change the schema, such as ALTER queries.
-   *
-   * @return
-   *   TRUE if this connection supports transactions for DDL queries, FALSE
-   *   otherwise.
-   */
-  public function supportsTransactionalDDL() {
-    return $this->transactionalDDLSupport;
-  }
-
-  /**
-   * Returns the name of the PDO driver for this connection.
-   */
-  abstract public function databaseType();
-
-
-  /**
-   * Gets any special processing requirements for the condition operator.
-   *
-   * Some condition types require special processing, such as IN, because
-   * the value data they pass in is not a simple value. This is a simple
-   * overridable lookup function. Database connections should define only
-   * those operators they wish to be handled differently than the default.
-   *
-   * @param $operator
-   *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
-   *
-   * @return
-   *   The extra handling directives for the specified operator, or NULL.
-   *
-   * @see DatabaseCondition::compile()
-   */
-  abstract public function mapConditionOperator($operator);
-
-  /**
-   * Throws an exception to deny direct access to transaction commits.
-   *
-   * We do not want to allow users to commit transactions at any time, only
-   * by destroying the transaction object or allowing it to go out of scope.
-   * A direct commit bypasses all of the safety checks we've built on top of
-   * PDO's transaction routines.
-   *
-   * @throws DatabaseTransactionExplicitCommitNotAllowedException
-   *
-   * @see DatabaseTransaction
-   */
-  public function commit() {
-    throw new DatabaseTransactionExplicitCommitNotAllowedException();
-  }
-
-  /**
-   * Retrieves an unique id from a given sequence.
-   *
-   * Use this function if for some reason you can't use a serial field. For
-   * example, MySQL has no ways of reading of the current value of a sequence
-   * and PostgreSQL can not advance the sequence to be larger than a given
-   * value. Or sometimes you just need a unique integer.
-   *
-   * @param $existing_id
-   *   After a database import, it might be that the sequences table is behind,
-   *   so by passing in the maximum existing id, it can be assured that we
-   *   never issue the same id.
-   *
-   * @return
-   *   An integer number larger than any number returned by earlier calls and
-   *   also larger than the $existing_id if one was passed in.
-   */
-  abstract public function nextId($existing_id = 0);
-}
-
-/**
- * Primary front-controller for the database system.
- *
- * This class is uninstantiatable and un-extendable. It acts to encapsulate
- * all control and shepherding of database connections into a single location
- * without the use of globals.
- */
-abstract class Database {
-
-  /**
-   * Flag to indicate a query call should simply return NULL.
-   *
-   * This is used for queries that have no reasonable return value anyway, such
-   * as INSERT statements to a table without a serial primary key.
-   */
-  const RETURN_NULL = 0;
-
-  /**
-   * Flag to indicate a query call should return the prepared statement.
-   */
-  const RETURN_STATEMENT = 1;
-
-  /**
-   * Flag to indicate a query call should return the number of affected rows.
-   */
-  const RETURN_AFFECTED = 2;
-
-  /**
-   * Flag to indicate a query call should return the "last insert id".
-   */
-  const RETURN_INSERT_ID = 3;
-
-  /**
-   * An nested array of all active connections. It is keyed by database name
-   * and target.
-   *
-   * @var array
-   */
-  static protected $connections = array();
-
-  /**
-   * A processed copy of the database connection information from settings.php.
-   *
-   * @var array
-   */
-  static protected $databaseInfo = NULL;
-
-  /**
-   * A list of key/target credentials to simply ignore.
-   *
-   * @var array
-   */
-  static protected $ignoreTargets = array();
-
-  /**
-   * The key of the currently active database connection.
-   *
-   * @var string
-   */
-  static protected $activeKey = 'default';
-
-  /**
-   * An array of active query log objects.
-   *
-   * Every connection has one and only one logger object for all targets and
-   * logging keys.
-   *
-   * array(
-   *   '$db_key' => DatabaseLog object.
-   * );
-   *
-   * @var array
-   */
-  static protected $logs = array();
-
-  /**
-   * Starts logging a given logging key on the specified connection.
-   *
-   * @param $logging_key
-   *   The logging key to log.
-   * @param $key
-   *   The database connection key for which we want to log.
-   *
-   * @return DatabaseLog
-   *   The query log object. Note that the log object does support richer
-   *   methods than the few exposed through the Database class, so in some
-   *   cases it may be desirable to access it directly.
-   *
-   * @see DatabaseLog
-   */
-  final public static function startLog($logging_key, $key = 'default') {
-    if (empty(self::$logs[$key])) {
-      self::$logs[$key] = new DatabaseLog($key);
-
-      // Every target already active for this connection key needs to have the
-      // logging object associated with it.
-      if (!empty(self::$connections[$key])) {
-        foreach (self::$connections[$key] as $connection) {
-          $connection->setLogger(self::$logs[$key]);
-        }
-      }
-    }
-
-    self::$logs[$key]->start($logging_key);
-    return self::$logs[$key];
-  }
-
-  /**
-   * Retrieves the queries logged on for given logging key.
-   *
-   * This method also ends logging for the specified key. To get the query log
-   * to date without ending the logger request the logging object by starting
-   * it again (which does nothing to an open log key) and call methods on it as
-   * desired.
-   *
-   * @param $logging_key
-   *   The logging key to log.
-   * @param $key
-   *   The database connection key for which we want to log.
-   *
-   * @return array
-   *   The query log for the specified logging key and connection.
-   *
-   * @see DatabaseLog
-   */
-  final public static function getLog($logging_key, $key = 'default') {
-    if (empty(self::$logs[$key])) {
-      return NULL;
-    }
-    $queries = self::$logs[$key]->get($logging_key);
-    self::$logs[$key]->end($logging_key);
-    return $queries;
-  }
-
-  /**
-   * Gets the connection object for the specified database key and target.
-   *
-   * @param $target
-   *   The database target name.
-   * @param $key
-   *   The database connection key. Defaults to NULL which means the active key.
-   *
-   * @return DatabaseConnection
-   *   The corresponding connection object.
-   */
-  final public static function getConnection($target = 'default', $key = NULL) {
-    if (!isset($key)) {
-      // By default, we want the active connection, set in setActiveConnection.
-      $key = self::$activeKey;
-    }
-    // If the requested target does not exist, or if it is ignored, we fall back
-    // to the default target. The target is typically either "default" or
-    // "slave", indicating to use a slave SQL server if one is available. If
-    // it's not available, then the default/master server is the correct server
-    // to use.
-    if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
-      $target = 'default';
-    }
-
-    if (!isset(self::$connections[$key][$target])) {
-      // If necessary, a new connection is opened.
-      self::$connections[$key][$target] = self::openConnection($key, $target);
-    }
-    return self::$connections[$key][$target];
-  }
-
-  /**
-   * Determines if there is an active connection.
-   *
-   * Note that this method will return FALSE if no connection has been
-   * established yet, even if one could be.
-   *
-   * @return
-   *   TRUE if there is at least one database connection established, FALSE
-   *   otherwise.
-   */
-  final public static function isActiveConnection() {
-    return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]);
-  }
-
-  /**
-   * Sets the active connection to the specified key.
-   *
-   * @return
-   *   The previous database connection key.
-   */
-  final public static function setActiveConnection($key = 'default') {
-    if (empty(self::$databaseInfo)) {
-      self::parseConnectionInfo();
-    }
-
-    if (!empty(self::$databaseInfo[$key])) {
-      $old_key = self::$activeKey;
-      self::$activeKey = $key;
-      return $old_key;
-    }
-  }
-
-  /**
-   * Process the configuration file for database information.
-   */
-  final public static function parseConnectionInfo() {
-    global $databases;
-
-    $database_info = is_array($databases) ? $databases : array();
-    foreach ($database_info as $index => $info) {
-      foreach ($database_info[$index] as $target => $value) {
-        // If there is no "driver" property, then we assume it's an array of
-        // possible connections for this target. Pick one at random. That allows
-        //  us to have, for example, multiple slave servers.
-        if (empty($value['driver'])) {
-          $database_info[$index][$target] = $database_info[$index][$target][mt_rand(0, count($database_info[$index][$target]) - 1)];
-        }
-
-        // Parse the prefix information.
-        if (!isset($database_info[$index][$target]['prefix'])) {
-          // Default to an empty prefix.
-          $database_info[$index][$target]['prefix'] = array(
-            'default' => '',
-          );
-        }
-        elseif (!is_array($database_info[$index][$target]['prefix'])) {
-          // Transform the flat form into an array form.
-          $database_info[$index][$target]['prefix'] = array(
-            'default' => $database_info[$index][$target]['prefix'],
-          );
-        }
-      }
-    }
-
-    if (!is_array(self::$databaseInfo)) {
-      self::$databaseInfo = $database_info;
-    }
-
-    // Merge the new $database_info into the existing.
-    // array_merge_recursive() cannot be used, as it would make multiple
-    // database, user, and password keys in the same database array.
-    else {
-      foreach ($database_info as $database_key => $database_values) {
-        foreach ($database_values as $target => $target_values) {
-          self::$databaseInfo[$database_key][$target] = $target_values;
-        }
-      }
-    }
-  }
-
-  /**
-   * Adds database connection information for a given key/target.
-   *
-   * This method allows the addition of new connection credentials at runtime.
-   * Under normal circumstances the preferred way to specify database
-   * credentials is via settings.php. However, this method allows them to be
-   * added at arbitrary times, such as during unit tests, when connecting to
-   * admin-defined third party databases, etc.
-   *
-   * If the given key/target pair already exists, this method will be ignored.
-   *
-   * @param $key
-   *   The database key.
-   * @param $target
-   *   The database target name.
-   * @param $info
-   *   The database connection information, as it would be defined in
-   *   settings.php. Note that the structure of this array will depend on the
-   *   database driver it is connecting to.
-   */
-  public static function addConnectionInfo($key, $target, $info) {
-    if (empty(self::$databaseInfo[$key][$target])) {
-      self::$databaseInfo[$key][$target] = $info;
-    }
-  }
-
-  /**
-   * Gets information on the specified database connection.
-   *
-   * @param $connection
-   *   The connection key for which we want information.
-   */
-  final public static function getConnectionInfo($key = 'default') {
-    if (empty(self::$databaseInfo)) {
-      self::parseConnectionInfo();
-    }
-
-    if (!empty(self::$databaseInfo[$key])) {
-      return self::$databaseInfo[$key];
-    }
-  }
-
-  /**
-   * Rename a connection and its corresponding connection information.
-   *
-   * @param $old_key
-   *   The old connection key.
-   * @param $new_key
-   *   The new connection key.
-   * @return
-   *   TRUE in case of success, FALSE otherwise.
-   */
-  final public static function renameConnection($old_key, $new_key) {
-    if (empty(self::$databaseInfo)) {
-      self::parseConnectionInfo();
-    }
-
-    if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
-      // Migrate the database connection information.
-      self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
-      unset(self::$databaseInfo[$old_key]);
-
-      // Migrate over the DatabaseConnection object if it exists.
-      if (isset(self::$connections[$old_key])) {
-        self::$connections[$new_key] = self::$connections[$old_key];
-        unset(self::$connections[$old_key]);
-      }
-
-      return TRUE;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  /**
-   * Remove a connection and its corresponding connection information.
-   *
-   * @param $key
-   *   The connection key.
-   * @return
-   *   TRUE in case of success, FALSE otherwise.
-   */
-  final public static function removeConnection($key) {
-    if (isset(self::$databaseInfo[$key])) {
-      unset(self::$databaseInfo[$key]);
-      unset(self::$connections[$key]);
-      return TRUE;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  /**
-   * Opens a connection to the server specified by the given key and target.
-   *
-   * @param $key
-   *   The database connection key, as specified in settings.php. The default is
-   *   "default".
-   * @param $target
-   *   The database target to open.
-   *
-   * @throws DatabaseConnectionNotDefinedException
-   * @throws DatabaseDriverNotSpecifiedException
-   */
-  final protected static function openConnection($key, $target) {
-    if (empty(self::$databaseInfo)) {
-      self::parseConnectionInfo();
-    }
-
-    // If the requested database does not exist then it is an unrecoverable
-    // error.
-    if (!isset(self::$databaseInfo[$key])) {
-      throw new DatabaseConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
-    }
-
-    if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
-      throw new DatabaseDriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
-    }
-
-    // We cannot rely on the registry yet, because the registry requires an
-    // open database connection.
-    $driver_class = 'DatabaseConnection_' . $driver;
-    require_once DRUPAL_ROOT . '/core/includes/database/' . $driver . '/database.inc';
-    $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
-    $new_connection->setTarget($target);
-    $new_connection->setKey($key);
-
-    // If we have any active logging objects for this connection key, we need
-    // to associate them with the connection we just opened.
-    if (!empty(self::$logs[$key])) {
-      $new_connection->setLogger(self::$logs[$key]);
-    }
-
-    return $new_connection;
-  }
-
-  /**
-   * Closes a connection to the server specified by the given key and target.
-   *
-   * @param $target
-   *   The database target name.  Defaults to NULL meaning that all target
-   *   connections will be closed.
-   * @param $key
-   *   The database connection key. Defaults to NULL which means the active key.
-   */
-  public static function closeConnection($target = NULL, $key = NULL) {
-    // Gets the active connection by default.
-    if (!isset($key)) {
-      $key = self::$activeKey;
-    }
-    // To close the connection, we need to unset the static variable.
-    if (isset($target)) {
-      unset(self::$connections[$key][$target]);
-    }
-    else {
-      unset(self::$connections[$key]);
-    }
-  }
-
-  /**
-   * Instructs the system to temporarily ignore a given key/target.
-   *
-   * At times we need to temporarily disable slave queries. To do so, call this
-   * method with the database key and the target to disable. That database key
-   * will then always fall back to 'default' for that key, even if it's defined.
-   *
-   * @param $key
-   *   The database connection key.
-   * @param $target
-   *   The target of the specified key to ignore.
-   */
-  public static function ignoreTarget($key, $target) {
-    self::$ignoreTargets[$key][$target] = TRUE;
-  }
-
-  /**
-   * Load a file for the database that might hold a class.
-   *
-   * @param $driver
-   *   The name of the driver.
-   * @param array $files
-   *   The name of the files the driver specific class can be.
-   */
-  public static function loadDriverFile($driver, array $files = array()) {
-    static $base_path;
-
-    if (empty($base_path)) {
-      $base_path = dirname(realpath(__FILE__));
-    }
-
-    $driver_base_path = "$base_path/$driver";
-    foreach ($files as $file) {
-      // Load the base file first so that classes extending base classes will
-      // have the base class loaded.
-      foreach (array("$base_path/$file", "$driver_base_path/$file") as $filename) {
-        // The OS caches file_exists() and PHP caches require_once(), so
-        // we'll let both of those take care of performance here.
-        if (file_exists($filename)) {
-          require_once $filename;
-        }
-      }
-    }
-  }
-}
-
-/**
- * Exception for when popTransaction() is called with no active transaction.
- */
-class DatabaseTransactionNoActiveException extends Exception { }
-
-/**
- * Exception thrown when a savepoint or transaction name occurs twice.
- */
-class DatabaseTransactionNameNonUniqueException extends Exception { }
-
-/**
- * Exception thrown when a commit() function fails.
- */
-class DatabaseTransactionCommitFailedException extends Exception { }
-
-/**
- * Exception to deny attempts to explicitly manage transactions.
- *
- * This exception will be thrown when the PDO connection commit() is called.
- * Code should never call this method directly.
- */
-class DatabaseTransactionExplicitCommitNotAllowedException extends Exception { }
-
-/**
- * Exception thrown when a rollback() resulted in other active transactions being rolled-back.
- */
-class DatabaseTransactionOutOfOrderException extends Exception { }
-
-/**
- * Exception thrown for merge queries that do not make semantic sense.
- *
- * There are many ways that a merge query could be malformed.  They should all
- * throw this exception and set an appropriately descriptive message.
- */
-class InvalidMergeQueryException extends Exception {}
-
-/**
- * Exception thrown if an insert query specifies a field twice.
- *
- * It is not allowed to specify a field as default and insert field, this
- * exception is thrown if that is the case.
- */
-class FieldsOverlapException extends Exception {}
-
-/**
- * Exception thrown if an insert query doesn't specify insert or default fields.
- */
-class NoFieldsException extends Exception {}
-
-/**
- * Exception thrown if an undefined database connection is requested.
- */
-class DatabaseConnectionNotDefinedException extends Exception {}
-
-/**
- * Exception thrown if no driver is specified for a database connection.
- */
-class DatabaseDriverNotSpecifiedException extends Exception {}
-
-
-/**
- * A wrapper class for creating and managing database transactions.
- *
- * Not all databases or database configurations support transactions. For
- * example, MySQL MyISAM tables do not. It is also easy to begin a transaction
- * and then forget to commit it, which can lead to connection errors when
- * another transaction is started.
- *
- * This class acts as a wrapper for transactions. To begin a transaction,
- * simply instantiate it. When the object goes out of scope and is destroyed
- * it will automatically commit. It also will check to see if the specified
- * connection supports transactions. If not, it will simply skip any transaction
- * commands, allowing user-space code to proceed normally. The only difference
- * is that rollbacks won't actually do anything.
- *
- * In the vast majority of cases, you should not instantiate this class
- * directly. Instead, call ->startTransaction(), from the appropriate connection
- * object.
- */
-class DatabaseTransaction {
-
-  /**
-   * The connection object for this transaction.
-   *
-   * @var DatabaseConnection
-   */
-  protected $connection;
-
-  /**
-   * A boolean value to indicate whether this transaction has been rolled back.
-   *
-   * @var Boolean
-   */
-  protected $rolledBack = FALSE;
-
-  /**
-   * The name of the transaction.
-   *
-   * This is used to label the transaction savepoint. It will be overridden to
-   * 'drupal_transaction' if there is no transaction depth.
-   */
-  protected $name;
-
-  public function __construct(DatabaseConnection &$connection, $name = NULL) {
-    $this->connection = &$connection;
-    // If there is no transaction depth, then no transaction has started. Name
-    // the transaction 'drupal_transaction'.
-    if (!$depth = $connection->transactionDepth()) {
-      $this->name = 'drupal_transaction';
-    }
-    // Within transactions, savepoints are used. Each savepoint requires a
-    // name. So if no name is present we need to create one.
-    elseif (!$name) {
-      $this->name = 'savepoint_' . $depth;
-    }
-    else {
-      $this->name = $name;
-    }
-    $this->connection->pushTransaction($this->name);
-  }
-
-  public function __destruct() {
-    // If we rolled back then the transaction would have already been popped.
-    if (!$this->rolledBack) {
-      $this->connection->popTransaction($this->name);
-    }
-  }
-
-  /**
-   * Retrieves the name of the transaction or savepoint.
-   */
-  public function name() {
-    return $this->name;
-  }
-
-  /**
-   * Rolls back the current transaction.
-   *
-   * This is just a wrapper method to rollback whatever transaction stack we are
-   * currently in, which is managed by the connection object itself. Note that
-   * logging (preferable with watchdog_exception()) needs to happen after a
-   * transaction has been rolled back or the log messages will be rolled back
-   * too.
-   *
-   * @see DatabaseConnection::rollback()
-   * @see watchdog_exception()
-   */
-  public function rollback() {
-    $this->rolledBack = TRUE;
-    $this->connection->rollback($this->name);
-  }
-}
-
-/**
- * Represents a prepared statement.
- *
- * Some methods in that class are purposefully commented out. Due to a change in
- * how PHP defines PDOStatement, we can't define a signature for those methods
- * that will work the same way between versions older than 5.2.6 and later
- * versions.  See http://bugs.php.net/bug.php?id=42452 for more details.
- *
- * Child implementations should either extend PDOStatement:
- * @code
- * class DatabaseStatement_oracle extends PDOStatement implements DatabaseStatementInterface {}
- * @endcode
- * or define their own class. If defining their own class, they will also have
- * to implement either the Iterator or IteratorAggregate interface before
- * DatabaseStatementInterface:
- * @code
- * class DatabaseStatement_oracle implements Iterator, DatabaseStatementInterface {}
- * @endcode
- */
-interface DatabaseStatementInterface extends Traversable {
-
-  /**
-   * Executes a prepared statement
-   *
-   * @param $args
-   *   An array of values with as many elements as there are bound parameters in
-   *   the SQL statement being executed.
-   * @param $options
-   *   An array of options for this query.
-   *
-   * @return
-   *   TRUE on success, or FALSE on failure.
-   */
-  public function execute($args = array(), $options = array());
-
-  /**
-   * Gets the query string of this statement.
-   *
-   * @return
-   *   The query string, in its form with placeholders.
-   */
-  public function getQueryString();
-
-  /**
-   * Returns the number of rows affected by the last SQL statement.
-   *
-   * @return
-   *   The number of rows affected by the last DELETE, INSERT, or UPDATE
-   *   statement executed.
-   */
-  public function rowCount();
-
-  /**
-   * Sets the default fetch mode for this statement.
-   *
-   * See http://php.net/manual/en/pdo.constants.php for the definition of the
-   * constants used.
-   *
-   * @param $mode
-   *   One of the PDO::FETCH_* constants.
-   * @param $a1
-   *   An option depending of the fetch mode specified by $mode:
-   *   - for PDO::FETCH_COLUMN, the index of the column to fetch
-   *   - for PDO::FETCH_CLASS, the name of the class to create
-   *   - for PDO::FETCH_INTO, the object to add the data to
-   * @param $a2
-   *   If $mode is PDO::FETCH_CLASS, the optional arguments to pass to the
-   *   constructor.
-   */
-  // public function setFetchMode($mode, $a1 = NULL, $a2 = array());
-
-  /**
-   * Fetches the next row from a result set.
-   *
-   * See http://php.net/manual/en/pdo.constants.php for the definition of the
-   * constants used.
-   *
-   * @param $mode
-   *   One of the PDO::FETCH_* constants.
-   *   Default to what was specified by setFetchMode().
-   * @param $cursor_orientation
-   *   Not implemented in all database drivers, don't use.
-   * @param $cursor_offset
-   *   Not implemented in all database drivers, don't use.
-   *
-   * @return
-   *   A result, formatted according to $mode.
-   */
-  // public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL);
-
-  /**
-   * Returns a single field from the next record of a result set.
-   *
-   * @param $index
-   *   The numeric index of the field to return. Defaults to the first field.
-   *
-   * @return
-   *   A single field from the next record, or FALSE if there is no next record.
-   */
-  public function fetchField($index = 0);
-
-  /**
-   * Fetches the next row and returns it as an object.
-   *
-   * The object will be of the class specified by DatabaseStatementInterface::setFetchMode()
-   * or stdClass if not specified.
-   */
-  // public function fetchObject();
-
-  /**
-   * Fetches the next row and returns it as an associative array.
-   *
-   * This method corresponds to PDOStatement::fetchObject(), but for associative
-   * arrays. For some reason PDOStatement does not have a corresponding array
-   * helper method, so one is added.
-   *
-   * @return
-   *   An associative array, or FALSE if there is no next row.
-   */
-  public function fetchAssoc();
-
-  /**
-   * Returns an array containing all of the result set rows.
-   *
-   * @param $mode
-   *   One of the PDO::FETCH_* constants.
-   * @param $column_index
-   *   If $mode is PDO::FETCH_COLUMN, the index of the column to fetch.
-   * @param $constructor_arguments
-   *   If $mode is PDO::FETCH_CLASS, the arguments to pass to the constructor.
-   *
-   * @return
-   *   An array of results.
-   */
-  // function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments);
-
-  /**
-   * Returns an entire single column of a result set as an indexed array.
-   *
-   * Note that this method will run the result set to the end.
-   *
-   * @param $index
-   *   The index of the column number to fetch.
-   *
-   * @return
-   *   An indexed array, or an empty array if there is no result set.
-   */
-  public function fetchCol($index = 0);
-
-  /**
-   * Returns the entire result set as a single associative array.
-   *
-   * This method is only useful for two-column result sets. It will return an
-   * associative array where the key is one column from the result set and the
-   * value is another field. In most cases, the default of the first two columns
-   * is appropriate.
-   *
-   * Note that this method will run the result set to the end.
-   *
-   * @param $key_index
-   *   The numeric index of the field to use as the array key.
-   * @param $value_index
-   *   The numeric index of the field to use as the array value.
-   *
-   * @return
-   *   An associative array, or an empty array if there is no result set.
-   */
-  public function fetchAllKeyed($key_index = 0, $value_index = 1);
-
-  /**
-   * Returns the result set as an associative array keyed by the given field.
-   *
-   * If the given key appears multiple times, later records will overwrite
-   * earlier ones.
-   *
-   * @param $key
-   *   The name of the field on which to index the array.
-   * @param $fetch
-   *   The fetchmode to use. If set to PDO::FETCH_ASSOC, PDO::FETCH_NUM, or
-   *   PDO::FETCH_BOTH the returned value with be an array of arrays. For any
-   *   other value it will be an array of objects. By default, the fetch mode
-   *   set for the query will be used.
-   *
-   * @return
-   *   An associative array, or an empty array if there is no result set.
-   */
-  public function fetchAllAssoc($key, $fetch = NULL);
-}
-
-/**
- * Default implementation of DatabaseStatementInterface.
- *
- * PDO allows us to extend the PDOStatement class to provide additional
- * functionality beyond that offered by default. We do need extra
- * functionality. By default, this class is not driver-specific. If a given
- * driver needs to set a custom statement class, it may do so in its
- * constructor.
- *
- * @see http://us.php.net/pdostatement
- */
-class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInterface {
-
-  /**
-   * Reference to the database connection object for this statement.
-   *
-   * The name $dbh is inherited from PDOStatement.
-   *
-   * @var DatabaseConnection
-   */
-  public $dbh;
-
-  protected function __construct($dbh) {
-    $this->dbh = $dbh;
-    $this->setFetchMode(PDO::FETCH_OBJ);
-  }
-
-  public function execute($args = array(), $options = array()) {
-    if (isset($options['fetch'])) {
-      if (is_string($options['fetch'])) {
-        // Default to an object. Note: db fields will be added to the object
-        // before the constructor is run. If you need to assign fields after
-        // the constructor is run, see http://drupal.org/node/315092.
-        $this->setFetchMode(PDO::FETCH_CLASS, $options['fetch']);
-      }
-      else {
-        $this->setFetchMode($options['fetch']);
-      }
-    }
-
-    $logger = $this->dbh->getLogger();
-    if (!empty($logger)) {
-      $query_start = microtime(TRUE);
-    }
-
-    $return = parent::execute($args);
-
-    if (!empty($logger)) {
-      $query_end = microtime(TRUE);
-      $logger->log($this, $args, $query_end - $query_start);
-    }
-
-    return $return;
-  }
-
-  public function getQueryString() {
-    return $this->queryString;
-  }
-
-  public function fetchCol($index = 0) {
-    return $this->fetchAll(PDO::FETCH_COLUMN, $index);
-  }
-
-  public function fetchAllAssoc($key, $fetch = NULL) {
-    $return = array();
-    if (isset($fetch)) {
-      if (is_string($fetch)) {
-        $this->setFetchMode(PDO::FETCH_CLASS, $fetch);
-      }
-      else {
-        $this->setFetchMode($fetch);
-      }
-    }
-
-    foreach ($this as $record) {
-      $record_key = is_object($record) ? $record->$key : $record[$key];
-      $return[$record_key] = $record;
-    }
-
-    return $return;
-  }
-
-  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
-    $return = array();
-    $this->setFetchMode(PDO::FETCH_NUM);
-    foreach ($this as $record) {
-      $return[$record[$key_index]] = $record[$value_index];
-    }
-    return $return;
-  }
-
-  public function fetchField($index = 0) {
-    // Call PDOStatement::fetchColumn to fetch the field.
-    return $this->fetchColumn($index);
-  }
-
-  public function fetchAssoc() {
-    // Call PDOStatement::fetch to fetch the row.
-    return $this->fetch(PDO::FETCH_ASSOC);
-  }
-}
-
-/**
- * Empty implementation of a database statement.
- *
- * This class satisfies the requirements of being a database statement/result
- * object, but does not actually contain data.  It is useful when developers
- * need to safely return an "empty" result set without connecting to an actual
- * database.  Calling code can then treat it the same as if it were an actual
- * result set that happens to contain no records.
- *
- * @see SearchQuery
- */
-class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface {
-
-  public function execute($args = array(), $options = array()) {
-    return FALSE;
-  }
-
-  public function getQueryString() {
-    return '';
-  }
-
-  public function rowCount() {
-    return 0;
-  }
-
-  public function setFetchMode($mode, $a1 = NULL, $a2 = array()) {
-    return;
-  }
-
-  public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL) {
-    return NULL;
-  }
-
-  public function fetchField($index = 0) {
-    return NULL;
-  }
-
-  public function fetchObject() {
-    return NULL;
-  }
-
-  public function fetchAssoc() {
-    return NULL;
-  }
-
-  function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments = array()) {
-    return array();
-  }
-
-  public function fetchCol($index = 0) {
-    return array();
-  }
-
-  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
-    return array();
-  }
-
-  public function fetchAllAssoc($key, $fetch = NULL) {
-    return array();
-  }
-
-  /* Implementations of Iterator. */
-
-  public function current() {
-    return NULL;
-  }
-
-  public function key() {
-    return NULL;
-  }
-
-  public function rewind() {
-    // Nothing to do: our DatabaseStatement can't be rewound.
-  }
-
-  public function next() {
-    // Do nothing, since this is an always-empty implementation.
-  }
-
-  public function valid() {
-    return FALSE;
-  }
-}
-
 /**
  * The following utility functions are simply convenience wrappers.
  *
@@ -2630,28 +530,28 @@ function db_next_id($existing_id = 0) {
 /**
  * Returns a new DatabaseCondition, set to "OR" all conditions together.
  *
- * @return DatabaseCondition
+ * @return Condition
  */
 function db_or() {
-  return new DatabaseCondition('OR');
+  return new Condition('OR');
 }
 
 /**
  * Returns a new DatabaseCondition, set to "AND" all conditions together.
  *
- * @return DatabaseCondition
+ * @return Condition
  */
 function db_and() {
-  return new DatabaseCondition('AND');
+  return new Condition('AND');
 }
 
 /**
  * Returns a new DatabaseCondition, set to "XOR" all conditions together.
  *
- * @return DatabaseCondition
+ * @return Condition
  */
 function db_xor() {
-  return new DatabaseCondition('XOR');
+  return new Condition('XOR');
 }
 
 /**
@@ -2662,10 +562,10 @@ function db_xor() {
  *
  * @param $conjunction
  *   The conjunction to use for query conditions (AND, OR or XOR).
- * @return DatabaseCondition
+ * @return Condition
  */
 function db_condition($conjunction) {
-  return new DatabaseCondition($conjunction);
+  return new Condition($conjunction);
 }
 
 /**
diff --git a/core/includes/database/query.inc b/core/includes/database/query.inc
deleted file mode 100644
index 0effedae19cd82f367a8d61c28fc45a8734904e3..0000000000000000000000000000000000000000
--- a/core/includes/database/query.inc
+++ /dev/null
@@ -1,1956 +0,0 @@
-<?php
-
-/**
- * @ingroup database
- * @{
- */
-
-/**
- * @file
- * Non-specific Database query code. Used by all engines.
- */
-
-/**
- * Interface for a conditional clause in a query.
- */
-interface QueryConditionInterface {
-
-  /**
-   * Helper function: builds the most common conditional clauses.
-   *
-   * This method can take a variable number of parameters. If called with two
-   * parameters, they are taken as $field and $value with $operator having a
-   * value of IN if $value is an array and = otherwise.
-   *
-   * Do not use this method to test for NULL values. Instead, use
-   * QueryConditionInterface::isNull() or QueryConditionInterface::isNotNull().
-   *
-   * @param $field
-   *   The name of the field to check. If you would like to add a more complex
-   *   condition involving operators or functions, use where().
-   * @param $value
-   *   The value to test the field against. In most cases, this is a scalar.
-   *   For more complex options, it is an array. The meaning of each element in
-   *   the array is dependent on the $operator.
-   * @param $operator
-   *   The comparison operator, such as =, <, or >=. It also accepts more
-   *   complex options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is
-   *   an array, and = otherwise.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   *
-   * @see QueryConditionInterface::isNull()
-   * @see QueryConditionInterface::isNotNull()
-   */
-  public function condition($field, $value = NULL, $operator = NULL);
-
-  /**
-   * Adds an arbitrary WHERE clause to the query.
-   *
-   * @param $snippet
-   *   A portion of a WHERE clause as a prepared statement. It must use named
-   *   placeholders, not ? placeholders.
-   * @param $args
-   *   An associative array of arguments.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function where($snippet, $args = array());
-
-  /**
-   * Sets a condition that the specified field be NULL.
-   *
-   * @param $field
-   *   The name of the field to check.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function isNull($field);
-
-  /**
-   * Sets a condition that the specified field be NOT NULL.
-   *
-   * @param $field
-   *   The name of the field to check.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function isNotNull($field);
-
-  /**
-   * Sets a condition that the specified subquery returns values.
-   * 
-   * @param SelectQueryInterface $select
-   *   The subquery that must contain results.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function exists(SelectQueryInterface $select);
-  
-  /**
-   * Sets a condition that the specified subquery returns no values.
-   * 
-   * @param SelectQueryInterface $select
-   *   The subquery that must not contain results.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function notExists(SelectQueryInterface $select);
-  
-  /**
-   * Gets a complete list of all conditions in this conditional clause.
-   *
-   * This method returns by reference. That allows alter hooks to access the
-   * data structure directly and manipulate it before it gets compiled.
-   *
-   * The data structure that is returned is an indexed array of entries, where
-   * each entry looks like the following:
-   * @code
-   * array(
-   *   'field' => $field,
-   *   'value' => $value,
-   *   'operator' => $operator,
-   * );
-   * @endcode
-   *
-   * In the special case that $operator is NULL, the $field is taken as a raw
-   * SQL snippet (possibly containing a function) and $value is an associative
-   * array of placeholders for the snippet.
-   *
-   * There will also be a single array entry of #conjunction, which is the
-   * conjunction that will be applied to the array, such as AND.
-   */
-  public function &conditions();
-
-  /**
-   * Gets a complete list of all values to insert into the prepared statement.
-   *
-   * @return
-   *   An associative array of placeholders and values.
-   */
-  public function arguments();
-
-  /**
-   * Compiles the saved conditions for later retrieval.
-   *
-   * This method does not return anything, but simply prepares data to be
-   * retrieved via __toString() and arguments().
-   *
-   * @param $connection
-   *   The database connection for which to compile the conditionals.
-   * @param $queryPlaceholder
-   *   The query this condition belongs to. If not given, the current query is
-   *   used.
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder);
-
-  /**
-   * Check whether a condition has been previously compiled.
-   *
-   * @return
-   *   TRUE if the condition has been previously compiled.
-   */
-  public function compiled();
-}
-
-
-/**
- * Interface for a query that can be manipulated via an alter hook.
- */
-interface QueryAlterableInterface {
-
-  /**
-   * Adds a tag to a query.
-   *
-   * Tags are strings that identify a query. A query may have any number of
-   * tags. Tags are used to mark a query so that alter hooks may decide if they
-   * wish to take action. Tags should be all lower-case and contain only
-   * letters, numbers, and underscore, and start with a letter. That is, they
-   * should follow the same rules as PHP identifiers in general.
-   *
-   * @param $tag
-   *   The tag to add.
-   *
-   * @return QueryAlterableInterface
-   *   The called object.
-   */
-  public function addTag($tag);
-
-  /**
-   * Determines if a given query has a given tag.
-   *
-   * @param $tag
-   *   The tag to check.
-   *
-   * @return
-   *   TRUE if this query has been marked with this tag, FALSE otherwise.
-   */
-  public function hasTag($tag);
-
-  /**
-   * Determines if a given query has all specified tags.
-   *
-   * @param $tags
-   *   A variable number of arguments, one for each tag to check.
-   *
-   * @return
-   *   TRUE if this query has been marked with all specified tags, FALSE
-   *   otherwise.
-   */
-  public function hasAllTags();
-
-  /**
-   * Determines if a given query has any specified tag.
-   *
-   * @param $tags
-   *   A variable number of arguments, one for each tag to check.
-   *
-   * @return
-   *   TRUE if this query has been marked with at least one of the specified
-   *   tags, FALSE otherwise.
-   */
-  public function hasAnyTag();
-
-  /**
-   * Adds additional metadata to the query.
-   *
-   * Often, a query may need to provide additional contextual data to alter
-   * hooks. Alter hooks may then use that information to decide if and how
-   * to take action.
-   *
-   * @param $key
-   *   The unique identifier for this piece of metadata. Must be a string that
-   *   follows the same rules as any other PHP identifier.
-   * @param $object
-   *   The additional data to add to the query. May be any valid PHP variable.
-   *
-   * @return QueryAlterableInterface
-   *   The called object.
-   */
-  public function addMetaData($key, $object);
-
-  /**
-   * Retrieves a given piece of metadata.
-   *
-   * @param $key
-   *   The unique identifier for the piece of metadata to retrieve.
-   *
-   * @return
-   *   The previously attached metadata object, or NULL if one doesn't exist.
-   */
-  public function getMetaData($key);
-}
-
-/**
- * Interface for a query that accepts placeholders.
- */
-interface QueryPlaceholderInterface {
-
-  /**
-   * Returns a unique identifier for this object.
-   */
-  public function uniqueIdentifier();
-
-  /**
-   * Returns the next placeholder ID for the query.
-   *
-   * @return
-   *   The next available placeholder ID as an integer.
-   */
-  public function nextPlaceholder();
-}
-
-/**
- * Base class for query builders.
- *
- * Note that query builders use PHP's magic __toString() method to compile the
- * query object into a prepared statement.
- */
-abstract class Query implements QueryPlaceholderInterface {
-
-  /**
-   * The connection object on which to run this query.
-   *
-   * @var DatabaseConnection
-   */
-  protected $connection;
-
-  /**
-   * The target of the connection object.
-   * 
-   * @var string
-   */
-  protected $connectionTarget;
-
-  /**
-   * The key of the connection object.
-   * 
-   * @var string
-   */
-  protected $connectionKey;
-
-  /**
-   * The query options to pass on to the connection object.
-   *
-   * @var array
-   */
-  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
-   */
-  protected $comments = array();
-
-  /**
-   * Constructs a Query object.
-   *
-   * @param DatabaseConnection $connection
-   *   Database connection object.
-   * @param array $options
-   *   Array of query options.
-   */
-  public function __construct(DatabaseConnection $connection, $options) {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-
-    $this->connection = $connection;
-    $this->connectionKey = $this->connection->getKey();
-    $this->connectionTarget = $this->connection->getTarget();
-
-    $this->queryOptions = $options;
-  }
-
-  /**
-   * Implements the magic __sleep function to disconnect from the database.
-   */
-  public function __sleep() {
-    $keys = get_object_vars($this);
-    unset($keys['connection']);
-    return array_keys($keys);
-  }
-
-  /**
-   * Implements the magic __wakeup function to reconnect to the database.
-   */
-  public function __wakeup() {
-    $this->connection = Database::getConnection($this->connectionTarget, $this->connectionKey);
-  }
-
-  /**
-   * Implements the magic __clone function.
-   */
-  public function __clone() {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-  }
-
-  /**
-   * Runs the query against the database.
-   */
-  abstract protected function execute();
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * The toString operation is how we compile a query object to a prepared
-   * statement.
-   *
-   * @return
-   *   A prepared statement query string for this object.
-   */
-  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
-   * query log or the list of active queries on an SQL server. This allows
-   * for easier debugging and allows you to more easily find where a query
-   * with a performance problem is being generated.
-   *
-   * The comment string will be sanitized to remove * / and other characters
-   * that may terminate the string early so as to avoid SQL injection attacks.
-   *
-   * @param $comment
-   *   The comment string to be inserted into the query.
-   *
-   * @return Query
-   *   The called object.
-   */
-  public function comment($comment) {
-    $this->comments[] = $comment;
-    return $this;
-  }
-
-  /**
-   * Returns a reference to the comments array for the query.
-   *
-   * Because this method returns by reference, alter hooks may edit the comments
-   * array directly to make their changes. If just adding comments, however, the
-   * use of comment() is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   * @code
-   * $comments =& $query->getComments();
-   * @endcode
-   *
-   * @return
-   *   A reference to the comments array structure.
-   */
-  public function &getComments() {
-    return $this->comments;
-  }
-}
-
-/**
- * General class for an abstracted INSERT query.
- */
-class InsertQuery extends Query {
-
-  /**
-   * The table on which to insert.
-   *
-   * @var string
-   */
-  protected $table;
-
-  /**
-   * An array of fields on which to insert.
-   *
-   * @var array
-   */
-  protected $insertFields = array();
-
-  /**
-   * An array of fields that should be set to their database-defined defaults.
-   *
-   * @var array
-   */
-  protected $defaultFields = array();
-
-  /**
-   * A nested array of values to insert.
-   *
-   * $insertValues is an array of arrays. Each sub-array is either an
-   * associative array whose keys are field names and whose values are field
-   * values to insert, or a non-associative array of values in the same order
-   * as $insertFields.
-   *
-   * Whether multiple insert sets will be run in a single query or multiple
-   * queries is left to individual drivers to implement in whatever manner is
-   * most appropriate. The order of values in each sub-array must match the
-   * order of fields in $insertFields.
-   *
-   * @var array
-   */
-  protected $insertValues = array();
-
-  /**
-   * A SelectQuery object to fetch the rows that should be inserted.
-   *
-   * @var SelectQueryInterface
-   */
-  protected $fromQuery;
-
-  /**
-   * Constructs an InsertQuery object.
-   *
-   * @param DatabaseConnection $connection
-   *   A DatabaseConnection object.
-   * @param string $table
-   *   Name of the table to associate with this query.
-   * @param array $options
-   *   Array of database options.
-   */
-  public function __construct($connection, $table, array $options = array()) {
-    if (!isset($options['return'])) {
-      $options['return'] = Database::RETURN_INSERT_ID;
-    }
-    parent::__construct($connection, $options);
-    $this->table = $table;
-  }
-
-  /**
-   * Adds a set of field->value pairs to be inserted.
-   *
-   * This method may only be called once. Calling it a second time will be
-   * ignored. To queue up multiple sets of values to be inserted at once,
-   * use the values() method.
-   *
-   * @param $fields
-   *   An array of fields on which to insert. This array may be indexed or
-   *   associative. If indexed, the array is taken to be the list of fields.
-   *   If associative, the keys of the array are taken to be the fields and
-   *   the values are taken to be corresponding values to insert. If a
-   *   $values argument is provided, $fields must be indexed.
-   * @param $values
-   *   An array of fields to insert into the database. The values must be
-   *   specified in the same order as the $fields array.
-   *
-   * @return InsertQuery
-   *   The called object.
-   */
-  public function fields(array $fields, array $values = array()) {
-    if (empty($this->insertFields)) {
-      if (empty($values)) {
-        if (!is_numeric(key($fields))) {
-          $values = array_values($fields);
-          $fields = array_keys($fields);
-        }
-      }
-      $this->insertFields = $fields;
-      if (!empty($values)) {
-        $this->insertValues[] = $values;
-      }
-    }
-
-    return $this;
-  }
-
-  /**
-   * Adds another set of values to the query to be inserted.
-   *
-   * If $values is a numeric-keyed array, it will be assumed to be in the same
-   * order as the original fields() call. If it is associative, it may be
-   * in any order as long as the keys of the array match the names of the
-   * fields.
-   *
-   * @param $values
-   *   An array of values to add to the query.
-   *
-   * @return InsertQuery
-   *   The called object.
-   */
-  public function values(array $values) {
-    if (is_numeric(key($values))) {
-      $this->insertValues[] = $values;
-    }
-    else {
-      // Reorder the submitted values to match the fields array.
-      foreach ($this->insertFields as $key) {
-        $insert_values[$key] = $values[$key];
-      }
-      // For consistency, the values array is always numerically indexed.
-      $this->insertValues[] = array_values($insert_values);
-    }
-    return $this;
-  }
-
-  /**
-   * Specifies fields for which the database defaults should be used.
-   *
-   * If you want to force a given field to use the database-defined default,
-   * not NULL or undefined, use this method to instruct the database to use
-   * default values explicitly. In most cases this will not be necessary
-   * unless you are inserting a row that is all default values, as you cannot
-   * specify no values in an INSERT query.
-   *
-   * Specifying a field both in fields() and in useDefaults() is an error
-   * and will not execute.
-   *
-   * @param $fields
-   *   An array of values for which to use the default values
-   *   specified in the table definition.
-   *
-   * @return InsertQuery
-   *   The called object.
-   */
-  public function useDefaults(array $fields) {
-    $this->defaultFields = $fields;
-    return $this;
-  }
-
-  /**
-   * Sets the fromQuery on this InsertQuery object.
-   *
-   * @param SelectQueryInterface $query
-   *   The query to fetch the rows that should be inserted.
-   *
-   * @return InsertQuery
-   *   The called object.
-   */
-  public function from(SelectQueryInterface $query) {
-    $this->fromQuery = $query;
-    return $this;
-  }
-
-  /**
-   * Executes the insert query.
-   *
-   * @return
-   *   The last insert ID of the query, if one exists. If the query
-   *   was given multiple sets of values to insert, the return value is
-   *   undefined. If no fields are specified, this method will do nothing and
-   *   return NULL. That makes it safe to use in multi-insert loops.
-   */
-  public function execute() {
-    // If validation fails, simply return NULL. Note that validation routines
-    // in preExecute() may throw exceptions instead.
-    if (!$this->preExecute()) {
-      return NULL;
-    }
-
-    // If we're selecting from a SelectQuery, finish building the query and
-    // pass it back, as any remaining options are irrelevant.
-    if (!empty($this->fromQuery)) {
-      $sql = (string) $this;
-      // The SelectQuery may contain arguments, load and pass them through.
-      return $this->connection->query($sql, $this->fromQuery->getArguments(), $this->queryOptions);
-    }
-
-    $last_insert_id = 0;
-
-    // Each insert happens in its own query in the degenerate case. However,
-    // we wrap it in a transaction so that it is atomic where possible. On many
-    // databases, such as SQLite, this is also a notable performance boost.
-    $transaction = $this->connection->startTransaction();
-
-    try {
-      $sql = (string) $this;
-      foreach ($this->insertValues as $insert_values) {
-        $last_insert_id = $this->connection->query($sql, $insert_values, $this->queryOptions);
-      }
-    }
-    catch (Exception $e) {
-      // One of the INSERTs failed, rollback the whole batch.
-      $transaction->rollback();
-      // Rethrow the exception for the calling code.
-      throw $e;
-    }
-
-    // Re-initialize the values array so that we can re-use this query.
-    $this->insertValues = array();
-
-    // Transaction commits here where $transaction looses scope.
-
-    return $last_insert_id;
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * @return string
-   *   The prepared statement.
-   */
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    // Default fields are always placed first for consistency.
-    $insert_fields = array_merge($this->defaultFields, $this->insertFields);
-
-    if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
-    }
-
-    // For simplicity, we will use the $placeholders array to inject
-    // default keywords even though they are not, strictly speaking,
-    // placeholders for prepared statements.
-    $placeholders = array();
-    $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
-    $placeholders = array_pad($placeholders, count($this->insertFields), '?');
-
-    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', $placeholders) . ')';
-  }
-
-  /**
-   * Preprocesses and validates the query.
-   *
-   * @return
-   *   TRUE if the validation was successful, FALSE if not.
-   *
-   * @throws FieldsOverlapException
-   * @throws NoFieldsException
-   */
-  public function preExecute() {
-    // Confirm that the user did not try to specify an identical
-    // field and default field.
-    if (array_intersect($this->insertFields, $this->defaultFields)) {
-      throw new FieldsOverlapException('You may not specify the same field to have a value and a schema-default value.');
-    }
-
-    if (!empty($this->fromQuery)) {
-      // We have to assume that the used aliases match the insert fields.
-      // Regular fields are added to the query before expressions, maintain the
-      // same order for the insert fields.
-      // This behavior can be overridden by calling fields() manually as only the
-      // first call to fields() does have an effect.
-      $this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions())));
-    }
-
-    // Don't execute query without fields.
-    if (count($this->insertFields) + count($this->defaultFields) == 0) {
-      throw new NoFieldsException('There are no fields available to insert with.');
-    }
-
-    // If no values have been added, silently ignore this query. This can happen
-    // if values are added conditionally, so we don't want to throw an
-    // exception.
-    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->fromQuery)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-}
-
-/**
- * General class for an abstracted DELETE operation.
- */
-class DeleteQuery extends Query implements QueryConditionInterface {
-
-  /**
-   * The table from which to delete.
-   *
-   * @var string
-   */
-  protected $table;
-
-  /**
-   * The condition object for this query.
-   *
-   * Condition handling is handled via composition.
-   *
-   * @var DatabaseCondition
-   */
-  protected $condition;
-
-  /**
-   * Constructs a DeleteQuery object.
-   *
-   * @param DatabaseConnection $connection
-   *   A DatabaseConnection object.
-   * @param string $table
-   *   Name of the table to associate with this query.
-   * @param array $options
-   *   Array of database options.
-   */
-  public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
-    $options['return'] = Database::RETURN_AFFECTED;
-    parent::__construct($connection, $options);
-    $this->table = $table;
-
-    $this->condition = new DatabaseCondition('AND');
-  }
-
-  /**
-   * Implements QueryConditionInterface::condition().
-   */
-  public function condition($field, $value = NULL, $operator = NULL) {
-    $this->condition->condition($field, $value, $operator);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNull().
-   */
-  public function isNull($field) {
-    $this->condition->isNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNotNull().
-   */
-  public function isNotNull($field) {
-    $this->condition->isNotNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::exists().
-   */
-  public function exists(SelectQueryInterface $select) {
-    $this->condition->exists($select);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::notExists().
-   */
-  public function notExists(SelectQueryInterface $select) {
-    $this->condition->notExists($select);
-    return $this;
-  }
-  
-  /**
-   * Implements QueryConditionInterface::conditions().
-   */
-  public function &conditions() {
-    return $this->condition->conditions();
-  }
-
-  /**
-   * Implements QueryConditionInterface::arguments().
-   */
-  public function arguments() {
-    return $this->condition->arguments();
-  }
-
-  /**
-   * Implements QueryConditionInterface::where().
-   */
-  public function where($snippet, $args = array()) {
-    $this->condition->where($snippet, $args);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::compile().
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    return $this->condition->compile($connection, $queryPlaceholder);
-  }
-
-  /**
-   * Implements QueryConditionInterface::compiled().
-   */
-  public function compiled() {
-    return $this->condition->compiled();
-  }
-
-  /**
-   * Executes the DELETE query.
-   *
-   * @return
-   *   The return value is dependent on the database connection.
-   */
-  public function execute() {
-    $values = array();
-    if (count($this->condition)) {
-      $this->condition->compile($this->connection, $this);
-      $values = $this->condition->arguments();
-    }
-
-    return $this->connection->query((string) $this, $values, $this->queryOptions);
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * @return string
-   *   The prepared statement.
-   */
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    $query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
-
-    if (count($this->condition)) {
-
-      $this->condition->compile($this->connection, $this);
-      $query .= "\nWHERE " . $this->condition;
-    }
-
-    return $query;
-  }
-}
-
-
-/**
- * General class for an abstracted TRUNCATE operation.
- */
-class TruncateQuery extends Query {
-
-  /**
-   * The table to truncate.
-   *
-   * @var string
-   */
-  protected $table;
-
-  /**
-   * Constructs a TruncateQuery object.
-   *
-   * @param DatabaseConnection $connection
-   *   A DatabaseConnection object.
-   * @param string $table
-   *   Name of the table to associate with this query.
-   * @param array $options
-   *   Array of database options.
-   */
-  public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
-    $options['return'] = Database::RETURN_AFFECTED;
-    parent::__construct($connection, $options);
-    $this->table = $table;
-  }
-
-  /**
-   * Implements QueryConditionInterface::compile().
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    return $this->condition->compile($connection, $queryPlaceholder);
-  }
-
-  /**
-   * Implements QueryConditionInterface::compiled().
-   */
-  public function compiled() {
-    return $this->condition->compiled();
-  }
-
-  /**
-   * Executes the TRUNCATE query.
-   *
-   * @return
-   *   Return value is dependent on the database type.
-   */
-  public function execute() {
-    return $this->connection->query((string) $this, array(), $this->queryOptions);
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * @return string
-   *   The prepared statement.
-   */
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
-  }
-}
-
-/**
- * General class for an abstracted UPDATE operation.
- */
-class UpdateQuery extends Query implements QueryConditionInterface {
-
-  /**
-   * The table to update.
-   *
-   * @var string
-   */
-  protected $table;
-
-  /**
-   * An array of fields that will be updated.
-   *
-   * @var array
-   */
-  protected $fields = array();
-
-  /**
-   * An array of values to update to.
-   *
-   * @var array
-   */
-  protected $arguments = array();
-
-  /**
-   * The condition object for this query.
-   *
-   * Condition handling is handled via composition.
-   *
-   * @var DatabaseCondition
-   */
-  protected $condition;
-
-  /**
-   * Array of fields to update to an expression in case of a duplicate record.
-   *
-   * This variable is a nested array in the following format:
-   * @code
-   * <some field> => array(
-   *  'condition' => <condition to execute, as a string>,
-   *  'arguments' => <array of arguments for condition, or NULL for none>,
-   * );
-   * @endcode
-   *
-   * @var array
-   */
-  protected $expressionFields = array();
-
-  /**
-   * Constructs an UpdateQuery object.
-   *
-   * @param DatabaseConnection $connection
-   *   A DatabaseConnection object.
-   * @param string $table
-   *   Name of the table to associate with this query.
-   * @param array $options
-   *   Array of database options.
-   */
-  public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
-    $options['return'] = Database::RETURN_AFFECTED;
-    parent::__construct($connection, $options);
-    $this->table = $table;
-
-    $this->condition = new DatabaseCondition('AND');
-  }
-
-  /**
-   * Implements QueryConditionInterface::condition().
-   */
-  public function condition($field, $value = NULL, $operator = NULL) {
-    $this->condition->condition($field, $value, $operator);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNull().
-   */
-  public function isNull($field) {
-    $this->condition->isNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNotNull().
-   */
-  public function isNotNull($field) {
-    $this->condition->isNotNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::exists().
-   */
-  public function exists(SelectQueryInterface $select) {
-    $this->condition->exists($select);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::notExists().
-   */
-  public function notExists(SelectQueryInterface $select) {
-    $this->condition->notExists($select);
-    return $this;
-  }
-  
-  /**
-   * Implements QueryConditionInterface::conditions().
-   */
-  public function &conditions() {
-    return $this->condition->conditions();
-  }
-
-  /**
-   * Implements QueryConditionInterface::arguments().
-   */
-  public function arguments() {
-    return $this->condition->arguments();
-  }
-
-  /**
-   * Implements QueryConditionInterface::where().
-   */
-  public function where($snippet, $args = array()) {
-    $this->condition->where($snippet, $args);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::compile().
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    return $this->condition->compile($connection, $queryPlaceholder);
-  }
-
-  /**
-   * Implements QueryConditionInterface::compiled().
-   */
-  public function compiled() {
-    return $this->condition->compiled();
-  }
-
-  /**
-   * Adds a set of field->value pairs to be updated.
-   *
-   * @param $fields
-   *   An associative array of fields to write into the database. The array keys
-   *   are the field names and the values are the values to which to set them.
-   *
-   * @return UpdateQuery
-   *   The called object.
-   */
-  public function fields(array $fields) {
-    $this->fields = $fields;
-    return $this;
-  }
-
-  /**
-   * Specifies fields to be updated as an expression.
-   *
-   * Expression fields are cases such as counter=counter+1. This method takes
-   * precedence over fields().
-   *
-   * @param $field
-   *   The field to set.
-   * @param $expression
-   *   The field will be set to the value of this expression. This parameter
-   *   may include named placeholders.
-   * @param $arguments
-   *   If specified, this is an array of key/value pairs for named placeholders
-   *   corresponding to the expression.
-   *
-   * @return UpdateQuery
-   *   The called object.
-   */
-  public function expression($field, $expression, array $arguments = NULL) {
-    $this->expressionFields[$field] = array(
-      'expression' => $expression,
-      'arguments' => $arguments,
-    );
-
-    return $this;
-  }
-
-  /**
-   * Executes the UPDATE query.
-   *
-   * @return
-   *   The number of rows affected by the update.
-   */
-  public function execute() {
-
-    // Expressions take priority over literal fields, so we process those first
-    // and remove any literal fields that conflict.
-    $fields = $this->fields;
-    $update_values = array();
-    foreach ($this->expressionFields as $field => $data) {
-      if (!empty($data['arguments'])) {
-        $update_values += $data['arguments'];
-      }
-      unset($fields[$field]);
-    }
-
-    // Because we filter $fields the same way here and in __toString(), the
-    // placeholders will all match up properly.
-    $max_placeholder = 0;
-    foreach ($fields as $field => $value) {
-      $update_values[':db_update_placeholder_' . ($max_placeholder++)] = $value;
-    }
-
-    if (count($this->condition)) {
-      $this->condition->compile($this->connection, $this);
-      $update_values = array_merge($update_values, $this->condition->arguments());
-    }
-
-    return $this->connection->query((string) $this, $update_values, $this->queryOptions);
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * @return string
-   *   The prepared statement.
-   */
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    // Expressions take priority over literal fields, so we process those first
-    // and remove any literal fields that conflict.
-    $fields = $this->fields;
-    $update_fields = array();
-    foreach ($this->expressionFields as $field => $data) {
-      $update_fields[] = $field . '=' . $data['expression'];
-      unset($fields[$field]);
-    }
-
-    $max_placeholder = 0;
-    foreach ($fields as $field => $value) {
-      $update_fields[] = $field . '=:db_update_placeholder_' . ($max_placeholder++);
-    }
-
-    $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
-
-    if (count($this->condition)) {
-      $this->condition->compile($this->connection, $this);
-      // There is an implicit string cast on $this->condition.
-      $query .= "\nWHERE " . $this->condition;
-    }
-
-    return $query;
-  }
-
-}
-
-/**
- * General class for an abstracted MERGE query operation.
- *
- * An ANSI SQL:2003 compatible database would run the following query:
- *
- * @code
- * MERGE INTO table_name_1 USING table_name_2 ON (condition)
- *   WHEN MATCHED THEN
- *   UPDATE SET column1 = value1 [, column2 = value2 ...]
- *   WHEN NOT MATCHED THEN
- *   INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...
- * @endcode
- *
- * Other databases (most notably MySQL, PostgreSQL and SQLite) will emulate
- * this statement by running a SELECT and then INSERT or UPDATE.
- *
- * By default, the two table names are identical and they are passed into the
- * the constructor. table_name_2 can be specified by the
- * MergeQuery::conditionTable() method. It can be either a string or a
- * subquery.
- *
- * The condition is built exactly like SelectQuery or UpdateQuery conditions,
- * the UPDATE query part is built similarly like an UpdateQuery and finally the
- * INSERT query part is built similarly like an InsertQuery. However, both
- * UpdateQuery and InsertQuery has a fields method so
- * MergeQuery::updateFields() and MergeQuery::insertFields() needs to be called
- * instead. MergeQuery::fields() can also be called which calls both of these
- * methods as the common case is to use the same column-value pairs for both
- * INSERT and UPDATE. However, this is not mandatory. Another convinient
- * wrapper is MergeQuery::key() which adds the same column-value pairs to the
- * condition and the INSERT query part.
- *
- * Several methods (key(), fields(), insertFields()) can be called to set a
- * key-value pair for the INSERT query part. Subsequent calls for the same
- * fields override the earlier ones. The same is true for UPDATE and key(),
- * fields() and updateFields().
- */
-class MergeQuery extends Query implements QueryConditionInterface {
-  /**
-   * Returned by execute() if an INSERT query has been executed.
-   */
-  const STATUS_INSERT = 1;
-
-  /**
-   * Returned by execute() if an UPDATE query has been executed.
-   */
-  const STATUS_UPDATE = 2;
-
-  /**
-   * The table to be used for INSERT and UPDATE.
-   *
-   * @var string
-   */
-  protected $table;
-
-  /**
-   * The table or subquery to be used for the condition.
-   */
-  protected $conditionTable;
-
-  /**
-   * An array of fields on which to insert.
-   *
-   * @var array
-   */
-  protected $insertFields = array();
-
-  /**
-   * An array of fields which should be set to their database-defined defaults.
-   *
-   * Used on INSERT.
-   *
-   * @var array
-   */
-  protected $defaultFields = array();
-
-  /**
-   * An array of values to be inserted.
-   *
-   * @var string
-   */
-  protected $insertValues = array();
-
-  /**
-   * An array of fields that will be updated.
-   *
-   * @var array
-   */
-  protected $updateFields = array();
-
-  /**
-   * Array of fields to update to an expression in case of a duplicate record.
-   *
-   * This variable is a nested array in the following format:
-   * @code
-   * <some field> => array(
-   *  'condition' => <condition to execute, as a string>,
-   *  'arguments' => <array of arguments for condition, or NULL for none>,
-   * );
-   * @endcode
-   *
-   * @var array
-   */
-  protected $expressionFields = array();
-
-  /**
-   * Flag indicating whether an UPDATE is necessary.
-   *
-   * @var boolean
-   */
-  protected $needsUpdate = FALSE;
-
-  /**
-  * Constructs a MergeQuery object.
-  *
-  * @param DatabaseConnection $connection
-  *   A DatabaseConnection object.
-  * @param string $table
-  *   Name of the table to associate with this query.
-  * @param array $options
-  *   Array of database options.
-  */
-  public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
-    $options['return'] = Database::RETURN_AFFECTED;
-    parent::__construct($connection, $options);
-    $this->table = $table;
-    $this->conditionTable = $table;
-    $this->condition = new DatabaseCondition('AND');
-  }
-
-  /**
-   * Sets the table or subquery to be used for the condition.
-   *
-   * @param $table
-   *   The table name or the subquery to be used. Use a SelectQuery object to
-   *   pass in a subquery.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  protected function conditionTable($table) {
-    $this->conditionTable = $table;
-    return $this;
-  }
-
-  /**
-   * Adds a set of field->value pairs to be updated.
-   *
-   * @param $fields
-   *   An associative array of fields to write into the database. The array keys
-   *   are the field names and the values are the values to which to set them.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function updateFields(array $fields) {
-    $this->updateFields = $fields;
-    $this->needsUpdate = TRUE;
-    return $this;
-  }
-
-  /**
-   * Specifies fields to be updated as an expression.
-   *
-   * Expression fields are cases such as counter = counter + 1. This method
-   * takes precedence over MergeQuery::updateFields() and it's wrappers,
-   * MergeQuery::key() and MergeQuery::fields().
-   *
-   * @param $field
-   *   The field to set.
-   * @param $expression
-   *   The field will be set to the value of this expression. This parameter
-   *   may include named placeholders.
-   * @param $arguments
-   *   If specified, this is an array of key/value pairs for named placeholders
-   *   corresponding to the expression.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function expression($field, $expression, array $arguments = NULL) {
-    $this->expressionFields[$field] = array(
-      'expression' => $expression,
-      'arguments' => $arguments,
-    );
-    $this->needsUpdate = TRUE;
-    return $this;
-  }
-
-  /**
-   * Adds a set of field->value pairs to be inserted.
-   *
-   * @param $fields
-   *   An array of fields on which to insert. This array may be indexed or
-   *   associative. If indexed, the array is taken to be the list of fields.
-   *   If associative, the keys of the array are taken to be the fields and
-   *   the values are taken to be corresponding values to insert. If a
-   *   $values argument is provided, $fields must be indexed.
-   * @param $values
-   *   An array of fields to insert into the database. The values must be
-   *   specified in the same order as the $fields array.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function insertFields(array $fields, array $values = array()) {
-    if ($values) {
-      $fields = array_combine($fields, $values);
-    }
-    $this->insertFields = $fields;
-    return $this;
-  }
-
-  /**
-   * Specifies fields for which the database-defaults should be used.
-   *
-   * If you want to force a given field to use the database-defined default,
-   * not NULL or undefined, use this method to instruct the database to use
-   * default values explicitly. In most cases this will not be necessary
-   * unless you are inserting a row that is all default values, as you cannot
-   * specify no values in an INSERT query.
-   *
-   * Specifying a field both in fields() and in useDefaults() is an error
-   * and will not execute.
-   *
-   * @param $fields
-   *   An array of values for which to use the default values
-   *   specified in the table definition.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function useDefaults(array $fields) {
-    $this->defaultFields = $fields;
-    return $this;
-  }
-
-  /**
-   * Sets common field-value pairs in the INSERT and UPDATE query parts.
-   *
-   * This method should only be called once. It may be called either
-   * with a single associative array or two indexed arrays. If called
-   * with an associative array, the keys are taken to be the fields
-   * and the values are taken to be the corresponding values to set.
-   * If called with two arrays, the first array is taken as the fields
-   * and the second array is taken as the corresponding values.
-   *
-   * @param $fields
-   *   An array of fields to insert, or an associative array of fields and
-   *   values. The keys of the array are taken to be the fields and the values
-   *   are taken to be corresponding values to insert.
-   * @param $values
-   *   An array of values to set into the database. The values must be
-   *   specified in the same order as the $fields array.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function fields(array $fields, array $values = array()) {
-    if ($values) {
-      $fields = array_combine($fields, $values);
-    }
-    foreach ($fields as $key => $value) {
-      $this->insertFields[$key] = $value;
-      $this->updateFields[$key] = $value;
-    }
-    $this->needsUpdate = TRUE;
-    return $this;
-  }
-
-  /**
-   * Sets the key field(s) to be used as conditions for this query.
-   *
-   * This method should only be called once. It may be called either
-   * with a single associative array or two indexed arrays. If called
-   * with an associative array, the keys are taken to be the fields
-   * and the values are taken to be the corresponding values to set.
-   * If called with two arrays, the first array is taken as the fields
-   * and the second array is taken as the corresponding values.
-   *
-   * The fields are copied to the condition of the query and the INSERT part.
-   * If no other method is called, the UPDATE will become a no-op.
-   *
-   * @param $fields
-   *   An array of fields to set, or an associative array of fields and values.
-   * @param $values
-   *   An array of values to set into the database. The values must be
-   *   specified in the same order as the $fields array.
-   *
-   * @return MergeQuery
-   *   The called object.
-   */
-  public function key(array $fields, array $values = array()) {
-    if ($values) {
-      $fields = array_combine($fields, $values);
-    }
-    foreach ($fields as $key => $value) {
-      $this->insertFields[$key] = $value;
-      $this->condition($key, $value);
-    }
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::condition().
-   */
-  public function condition($field, $value = NULL, $operator = NULL) {
-    $this->condition->condition($field, $value, $operator);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNull().
-   */
-  public function isNull($field) {
-    $this->condition->isNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNotNull().
-   */
-  public function isNotNull($field) {
-    $this->condition->isNotNull($field);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::exists().
-   */
-  public function exists(SelectQueryInterface $select) {
-    $this->condition->exists($select);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::notExists().
-   */
-  public function notExists(SelectQueryInterface $select) {
-    $this->condition->notExists($select);
-    return $this;
-  }
-  
-  /**
-   * Implements QueryConditionInterface::conditions().
-   */
-  public function &conditions() {
-    return $this->condition->conditions();
-  }
-
-  /**
-   * Implements QueryConditionInterface::arguments().
-   */
-  public function arguments() {
-    return $this->condition->arguments();
-  }
-
-  /**
-   * Implements QueryConditionInterface::where().
-   */
-  public function where($snippet, $args = array()) {
-    $this->condition->where($snippet, $args);
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::compile().
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    return $this->condition->compile($connection, $queryPlaceholder);
-  }
-
-  /**
-   * Implements QueryConditionInterface::compiled().
-   */
-  public function compiled() {
-    return $this->condition->compiled();
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the query to a string.
-   *
-   * In the degenerate case, there is no string-able query as this operation
-   * is potentially two queries.
-   *
-   * @return string
-   *   The prepared query statement.
-   */
-  public function __toString() {
-  }
-
-  public function execute() {
-    // Wrap multiple queries in a transaction, if the database supports it.
-    $transaction = $this->connection->startTransaction();
-    try {
-      if (!count($this->condition)) {
-        throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
-      }
-      $select = $this->connection->select($this->conditionTable)
-        ->condition($this->condition)
-        ->forUpdate();
-      $select->addExpression('1');
-      if (!$select->execute()->fetchField()) {
-        try {
-          $insert = $this->connection->insert($this->table)->fields($this->insertFields);
-          if ($this->defaultFields) {
-            $insert->useDefaults($this->defaultFields);
-          }
-          $insert->execute();
-          return MergeQuery::STATUS_INSERT;
-        }
-        catch (Exception $e) {
-          // The insert query failed, maybe it's because a racing insert query
-          // beat us in inserting the same row. Retry the select query, if it
-          // returns a row, ignore the error and continue with the update
-          // query below.
-          if (!$select->execute()->fetchField()) {
-            throw $e;
-          }
-        }
-      }
-      if ($this->needsUpdate) {
-        $update = $this->connection->update($this->table)
-          ->fields($this->updateFields)
-          ->condition($this->condition);
-        if ($this->expressionFields) {
-          foreach ($this->expressionFields as $field => $data) {
-            $update->expression($field, $data['expression'], $data['arguments']);
-          }
-        }
-        $update->execute();
-        return MergeQuery::STATUS_UPDATE;
-      }
-    }
-    catch (Exception $e) {
-      // Something really wrong happened here, bubble up the exception to the
-      // caller.
-      $transaction->rollback();
-      throw $e;
-    }
-    // Transaction commits here where $transaction looses scope.
-  }
-}
-
-/**
- * Generic class for a series of conditions in a query.
- */
-class DatabaseCondition implements QueryConditionInterface, Countable {
-
-  /**
-   * Array of conditions.
-   *
-   * @var array
-   */
-  protected $conditions = array();
-
-  /**
-   * Array of arguments.
-   *
-   * @var array
-   */
-  protected $arguments = array();
-
-  /**
-   * Whether the conditions have been changed.
-   *
-   * TRUE if the condition has been changed since the last compile.
-   * FALSE if the condition has been compiled and not changed.
-   *
-   * @var bool
-   */
-  protected $changed = TRUE;
-
-  /**
-   * The identifier of the query placeholder this condition has been compiled against.
-   */
-  protected $queryPlaceholderIdentifier;
-
-  /**
-   * Constructs a DataBaseCondition object.
-   *
-   * @param string $conjunction
-   *   The operator to use to combine conditions: 'AND' or 'OR'.
-   */
-  public function __construct($conjunction) {
-    $this->conditions['#conjunction'] = $conjunction;
-  }
-
-  /**
-   * Implements Countable::count().
-   *
-   * Returns the size of this conditional. The size of the conditional is the
-   * size of its conditional array minus one, because one element is the the
-   * conjunction.
-   */
-  public function count() {
-    return count($this->conditions) - 1;
-  }
-
-  /**
-   * Implements QueryConditionInterface::condition().
-   */
-  public function condition($field, $value = NULL, $operator = NULL) {
-    if (!isset($operator)) {
-      if (is_array($value)) {
-        $operator = 'IN';
-      }
-      else {
-        $operator = '=';
-      }
-    }
-    $this->conditions[] = array(
-      'field' => $field,
-      'value' => $value,
-      'operator' => $operator,
-    );
-
-    $this->changed = TRUE;
-
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::where().
-   */
-  public function where($snippet, $args = array()) {
-    $this->conditions[] = array(
-      'field' => $snippet,
-      'value' => $args,
-      'operator' => NULL,
-    );
-    $this->changed = TRUE;
-
-    return $this;
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNull().
-   */
-  public function isNull($field) {
-    return $this->condition($field, NULL, 'IS NULL');
-  }
-
-  /**
-   * Implements QueryConditionInterface::isNotNull().
-   */
-  public function isNotNull($field) {
-    return $this->condition($field, NULL, 'IS NOT NULL');
-  }
-
-  /**
-   * Implements QueryConditionInterface::exists().
-   */
-  public function exists(SelectQueryInterface $select) {
-    return $this->condition('', $select, 'EXISTS');
-  }
-  
-  /**
-   * Implements QueryConditionInterface::notExists().
-   */
-  public function notExists(SelectQueryInterface $select) {
-    return $this->condition('', $select, 'NOT EXISTS');
-  }
-  
-  /**
-   * Implements QueryConditionInterface::conditions().
-   */
-  public function &conditions() {
-    return $this->conditions;
-  }
-
-  /**
-   * Implements QueryConditionInterface::arguments().
-   */
-  public function arguments() {
-    // If the caller forgot to call compile() first, refuse to run.
-    if ($this->changed) {
-      return NULL;
-    }
-    return $this->arguments;
-  }
-
-  /**
-   * Implements QueryConditionInterface::compile().
-   */
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    // Re-compile if this condition changed or if we are compiled against a
-    // different query placeholder object.
-    if ($this->changed || isset($this->queryPlaceholderIdentifier) && ($this->queryPlaceholderIdentifier != $queryPlaceholder->uniqueIdentifier())) {
-      $this->queryPlaceholderIdentifier = $queryPlaceholder->uniqueIdentifier();
-
-      $condition_fragments = array();
-      $arguments = array();
-
-      $conditions = $this->conditions;
-      $conjunction = $conditions['#conjunction'];
-      unset($conditions['#conjunction']);
-      foreach ($conditions as $condition) {
-        if (empty($condition['operator'])) {
-          // This condition is a literal string, so let it through as is.
-          $condition_fragments[] = ' (' . $condition['field'] . ') ';
-          $arguments += $condition['value'];
-        }
-        else {
-          // It's a structured condition, so parse it out accordingly.
-          // Note that $condition['field'] will only be an object for a dependent
-          // DatabaseCondition object, not for a dependent subquery.
-          if ($condition['field'] instanceof QueryConditionInterface) {
-            // Compile the sub-condition recursively and add it to the list.
-            $condition['field']->compile($connection, $queryPlaceholder);
-            $condition_fragments[] = '(' . (string) $condition['field'] . ')';
-            $arguments += $condition['field']->arguments();
-          }
-          else {
-            // For simplicity, we treat all operators as the same data structure.
-            // In the typical degenerate case, this won't get changed.
-            $operator_defaults = array(
-              'prefix' => '',
-              'postfix' => '',
-              'delimiter' => '',
-              'operator' => $condition['operator'],
-              'use_value' => TRUE,
-            );
-            $operator = $connection->mapConditionOperator($condition['operator']);
-            if (!isset($operator)) {
-              $operator = $this->mapConditionOperator($condition['operator']);
-            }
-            $operator += $operator_defaults;
-
-            $placeholders = array();
-            if ($condition['value'] instanceof SelectQueryInterface) {
-              $condition['value']->compile($connection, $queryPlaceholder);
-              $placeholders[] = (string) $condition['value'];
-              $arguments += $condition['value']->arguments();
-              // Subqueries are the actual value of the operator, we don't
-              // need to add another below.
-              $operator['use_value'] = FALSE;
-            }
-            // We assume that if there is a delimiter, then the value is an
-            // array. If not, it is a scalar. For simplicity, we first convert
-            // up to an array so that we can build the placeholders in the same way.
-            elseif (!$operator['delimiter']) {
-              $condition['value'] = array($condition['value']);
-            }
-            if ($operator['use_value']) {
-              foreach ($condition['value'] as $value) {
-                $placeholder = ':db_condition_placeholder_' . $queryPlaceholder->nextPlaceholder();
-                $arguments[$placeholder] = $value;
-                $placeholders[] = $placeholder;
-              }
-            }
-            $condition_fragments[] = ' (' . $connection->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
-          }
-        }
-      }
-
-      $this->changed = FALSE;
-      $this->stringVersion = implode($conjunction, $condition_fragments);
-      $this->arguments = $arguments;
-    }
-  }
-
-  /**
-   * Implements QueryConditionInterface::compiled().
-   */
-  public function compiled() {
-    return !$this->changed;
-  }
-
-  /**
-   * Implements PHP magic __toString method to convert the conditions to string.
-   *
-   * @return string
-   *   A string version of the conditions.
-   */
-  public function __toString() {
-    // If the caller forgot to call compile() first, refuse to run.
-    if ($this->changed) {
-      return NULL;
-    }
-    return $this->stringVersion;
-  }
-
-  /**
-   * PHP magic __clone() method.
-   *
-   * Only copies fields that implement QueryConditionInterface. Also sets
-   * $this->changed to TRUE.
-   */
-  function __clone() {
-    $this->changed = TRUE;
-    foreach ($this->conditions as $key => $condition) {
-      if ($condition['field'] instanceOf QueryConditionInterface) {
-        $this->conditions[$key]['field'] = clone($condition['field']);
-      }
-    }
-  }
-
-  /**
-   * Gets any special processing requirements for the condition operator.
-   *
-   * Some condition types require special processing, such as IN, because
-   * the value data they pass in is not a simple value. This is a simple
-   * overridable lookup function.
-   *
-   * @param $operator
-   *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
-   *
-   * @return
-   *   The extra handling directives for the specified operator, or NULL.
-   */
-  protected function mapConditionOperator($operator) {
-    // $specials does not use drupal_static as its value never changes.
-    static $specials = array(
-      'BETWEEN' => array('delimiter' => ' AND '),
-      'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
-      'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
-      'EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
-      'NOT EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
-      'IS NULL' => array('use_value' => FALSE),
-      'IS NOT NULL' => array('use_value' => FALSE),
-      // Use backslash for escaping wildcard characters.
-      'LIKE' => array('postfix' => " ESCAPE '\\\\'"),
-      'NOT LIKE' => array('postfix' => " ESCAPE '\\\\'"),
-      // These ones are here for performance reasons.
-      '=' => array(),
-      '<' => array(),
-      '>' => array(),
-      '>=' => array(),
-      '<=' => array(),
-    );
-    if (isset($specials[$operator])) {
-      $return = $specials[$operator];
-    }
-    else {
-      // We need to upper case because PHP index matches are case sensitive but
-      // do not need the more expensive drupal_strtoupper because SQL statements are ASCII.
-      $operator = strtoupper($operator);
-      $return = isset($specials[$operator]) ? $specials[$operator] : array();
-    }
-
-    $return += array('operator' => $operator);
-
-    return $return;
-  }
-
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/select.inc b/core/includes/database/select.inc
deleted file mode 100644
index 9bc6b92e1d908c0d97bef2976df4873867628d1f..0000000000000000000000000000000000000000
--- a/core/includes/database/select.inc
+++ /dev/null
@@ -1,1609 +0,0 @@
-<?php
-
-/**
- * @ingroup database
- * @{
- */
-
-require_once __DIR__ . '/query.inc';
-
-/**
- * Interface for extendable query objects.
- *
- * "Extenders" follow the "Decorator" OOP design pattern.  That is, they wrap
- * and "decorate" another object.  In our case, they implement the same interface
- * as select queries and wrap a select query, to which they delegate almost all
- * operations.  Subclasses of this class may implement additional methods or
- * override existing methods as appropriate.  Extenders may also wrap other
- * extender objects, allowing for arbitrarily complex "enhanced" queries.
- */
-interface QueryExtendableInterface {
-
-  /**
-   * Enhance this object by wrapping it in an extender object.
-   *
-   * @param $extender_name
-   *   The base name of the extending class.  The base name will be checked
-   *   against the current database connection to allow driver-specific subclasses
-   *   as well, using the same logic as the query objects themselves.  For example,
-   *   PagerDefault_mysql is the MySQL-specific override for PagerDefault.
-   * @return QueryExtendableInterface
-   *   The extender object, which now contains a reference to this object.
-   */
-  public function extend($extender_name);
-}
-
-/**
- * Interface definition for a Select Query object.
- */
-interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableInterface, QueryExtendableInterface, QueryPlaceholderInterface {
-
-  /* Alter accessors to expose the query data to alter hooks. */
-
-  /**
-   * Returns a reference to the fields array for this query.
-   *
-   * Because this method returns by reference, alter hooks may edit the fields
-   * array directly to make their changes. If just adding fields, however, the
-   * use of addField() is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getFields();
-   * @endcode
-   *
-   * @return
-   *   A reference to the fields array structure.
-   */
-  public function &getFields();
-
-  /**
-   * Returns a reference to the expressions array for this query.
-   *
-   * Because this method returns by reference, alter hooks may edit the expressions
-   * array directly to make their changes. If just adding expressions, however, the
-   * use of addExpression() is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getExpressions();
-   * @endcode
-   *
-   * @return
-   *   A reference to the expression array structure.
-   */
-  public function &getExpressions();
-
-  /**
-   * Returns a reference to the order by array for this query.
-   *
-   * Because this method returns by reference, alter hooks may edit the order-by
-   * array directly to make their changes. If just adding additional ordering
-   * fields, however, the use of orderBy() is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getOrderBy();
-   * @endcode
-   *
-   * @return
-   *   A reference to the expression array structure.
-   */
-  public function &getOrderBy();
-
-  /**
-   * Returns a reference to the group-by array for this query.
-   *
-   * Because this method returns by reference, alter hooks may edit the group-by
-   * array directly to make their changes. If just adding additional grouping
-   * fields, however, the use of groupBy() is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getGroupBy();
-   * @endcode
-   *
-   * @return
-   *   A reference to the group-by array structure.
-   */
-  public function &getGroupBy();
-
-  /**
-   * Returns a reference to the tables array for this query.
-   *
-   * Because this method returns by reference, alter hooks may edit the tables
-   * array directly to make their changes. If just adding tables, however, the
-   * use of the join() methods is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getTables();
-   * @endcode
-   *
-   * @return
-   *   A reference to the tables array structure.
-   */
-  public function &getTables();
-
-  /**
-   * Returns a reference to the union queries for this query. This include
-   * queries for UNION, UNION ALL, and UNION DISTINCT.
-   *
-   * Because this method returns by reference, alter hooks may edit the tables
-   * array directly to make their changes. If just adding union queries,
-   * however, the use of the union() method is preferred.
-   *
-   * Note that this method must be called by reference as well:
-   *
-   * @code
-   * $fields =& $query->getUnion();
-   * @endcode
-   *
-   * @return
-   *   A reference to the union query array structure.
-   */
-  public function &getUnion();
-
-  /**
-   * Compiles and returns an associative array of the arguments for this prepared statement.
-   *
-   * @param $queryPlaceholder
-   *   When collecting the arguments of a subquery, the main placeholder
-   *   object should be passed as this parameter.
-   *
-   * @return
-   *   An associative array of all placeholder arguments for this query.
-   */
-  public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL);
-
-  /* Query building operations */
-
-  /**
-   * Sets this query to be DISTINCT.
-   *
-   * @param $distinct
-   *   TRUE to flag this query DISTINCT, FALSE to disable it.
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function distinct($distinct = TRUE);
-
-  /**
-   * Adds a field to the list to be SELECTed.
-   *
-   * @param $table_alias
-   *   The name of the table from which the field comes, as an alias. Generally
-   *   you will want to use the return value of join() here to ensure that it is
-   *   valid.
-   * @param $field
-   *   The name of the field.
-   * @param $alias
-   *   The alias for this field. If not specified, one will be generated
-   *   automatically based on the $table_alias and $field. The alias will be
-   *   checked for uniqueness, so the requested alias may not be the alias
-   *   that is assigned in all cases.
-   * @return
-   *   The unique alias that was assigned for this field.
-   */
-  public function addField($table_alias, $field, $alias = NULL);
-
-  /**
-   * Add multiple fields from the same table to be SELECTed.
-   *
-   * This method does not return the aliases set for the passed fields. In the
-   * majority of cases that is not a problem, as the alias will be the field
-   * name. However, if you do need to know the alias you can call getFields()
-   * and examine the result to determine what alias was created. Alternatively,
-   * simply use addField() for the few fields you care about and this method for
-   * the rest.
-   *
-   * @param $table_alias
-   *   The name of the table from which the field comes, as an alias. Generally
-   *   you will want to use the return value of join() here to ensure that it is
-   *   valid.
-   * @param $fields
-   *   An indexed array of fields present in the specified table that should be
-   *   included in this query. If not specified, $table_alias.* will be generated
-   *   without any aliases.
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function fields($table_alias, array $fields = array());
-
-  /**
-   * Adds an expression to the list of "fields" to be SELECTed.
-   *
-   * An expression can be any arbitrary string that is valid SQL. That includes
-   * various functions, which may in some cases be database-dependent. This
-   * method makes no effort to correct for database-specific functions.
-   *
-   * @param $expression
-   *   The expression string. May contain placeholders.
-   * @param $alias
-   *   The alias for this expression. If not specified, one will be generated
-   *   automatically in the form "expression_#". The alias will be checked for
-   *   uniqueness, so the requested alias may not be the alias that is assigned
-   *   in all cases.
-   * @param $arguments
-   *   Any placeholder arguments needed for this expression.
-   * @return
-   *   The unique alias that was assigned for this expression.
-   */
-  public function addExpression($expression, $alias = NULL, $arguments = array());
-
-  /**
-   * Default Join against another table in the database.
-   *
-   * This method is a convenience method for innerJoin().
-   *
-   * @param $table
-   *   The table against which to join.
-   * @param $alias
-   *   The alias for the table. In most cases this should be the first letter
-   *   of the table, or the first letter of each "word" in the table.
-   * @param $condition
-   *   The condition on which to join this table. If the join requires values,
-   *   this clause should use a named placeholder and the value or values to
-   *   insert should be passed in the 4th parameter. For the first table joined
-   *   on a query, this value is ignored as the first table is taken as the base
-   *   table. The token %alias can be used in this string to be replaced with
-   *   the actual alias. This is useful when $alias is modified by the database
-   *   system, for example, when joining the same table more than once.
-   * @param $arguments
-   *   An array of arguments to replace into the $condition of this join.
-   * @return
-   *   The unique alias that was assigned for this table.
-   */
-  public function join($table, $alias = NULL, $condition = NULL, $arguments = array());
-
-  /**
-   * Inner Join against another table in the database.
-   *
-   * @param $table
-   *   The table against which to join.
-   * @param $alias
-   *   The alias for the table. In most cases this should be the first letter
-   *   of the table, or the first letter of each "word" in the table.
-   * @param $condition
-   *   The condition on which to join this table. If the join requires values,
-   *   this clause should use a named placeholder and the value or values to
-   *   insert should be passed in the 4th parameter. For the first table joined
-   *   on a query, this value is ignored as the first table is taken as the base
-   *   table. The token %alias can be used in this string to be replaced with
-   *   the actual alias. This is useful when $alias is modified by the database
-   *   system, for example, when joining the same table more than once.
-   * @param $arguments
-   *   An array of arguments to replace into the $condition of this join.
-   * @return
-   *   The unique alias that was assigned for this table.
-   */
-  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
-
-  /**
-   * Left Outer Join against another table in the database.
-   *
-   * @param $table
-   *   The table against which to join.
-   * @param $alias
-   *   The alias for the table. In most cases this should be the first letter
-   *   of the table, or the first letter of each "word" in the table.
-   * @param $condition
-   *   The condition on which to join this table. If the join requires values,
-   *   this clause should use a named placeholder and the value or values to
-   *   insert should be passed in the 4th parameter. For the first table joined
-   *   on a query, this value is ignored as the first table is taken as the base
-   *   table. The token %alias can be used in this string to be replaced with
-   *   the actual alias. This is useful when $alias is modified by the database
-   *   system, for example, when joining the same table more than once.
-   * @param $arguments
-   *   An array of arguments to replace into the $condition of this join.
-   * @return
-   *   The unique alias that was assigned for this table.
-   */
-  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
-
-  /**
-   * Right Outer Join against another table in the database.
-   *
-   * @param $table
-   *   The table against which to join.
-   * @param $alias
-   *   The alias for the table. In most cases this should be the first letter
-   *   of the table, or the first letter of each "word" in the table.
-   * @param $condition
-   *   The condition on which to join this table. If the join requires values,
-   *   this clause should use a named placeholder and the value or values to
-   *   insert should be passed in the 4th parameter. For the first table joined
-   *   on a query, this value is ignored as the first table is taken as the base
-   *   table. The token %alias can be used in this string to be replaced with
-   *   the actual alias. This is useful when $alias is modified by the database
-   *   system, for example, when joining the same table more than once.
-   * @param $arguments
-   *   An array of arguments to replace into the $condition of this join.
-   * @return
-   *   The unique alias that was assigned for this table.
-   */
-  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
-
-  /**
-   * Join against another table in the database.
-   *
-   * This method does the "hard" work of queuing up a table to be joined against.
-   * In some cases, that may include dipping into the Schema API to find the necessary
-   * fields on which to join.
-   *
-   * @param $type
-   *   The type of join. Typically one one of INNER, LEFT OUTER, and RIGHT OUTER.
-   * @param $table
-   *   The table against which to join. May be a string or another SelectQuery
-   *   object. If a query object is passed, it will be used as a subselect.
-   * @param $alias
-   *   The alias for the table. In most cases this should be the first letter
-   *   of the table, or the first letter of each "word" in the table. If omitted,
-   *   one will be dynamically generated.
-   * @param $condition
-   *   The condition on which to join this table. If the join requires values,
-   *   this clause should use a named placeholder and the value or values to
-   *   insert should be passed in the 4th parameter. For the first table joined
-   *   on a query, this value is ignored as the first table is taken as the base
-   *   table. The token %alias can be used in this string to be replaced with
-   *   the actual alias. This is useful when $alias is modified by the database
-   *   system, for example, when joining the same table more than once.
-   * @param $arguments
-   *   An array of arguments to replace into the $condition of this join.
-   * @return
-   *   The unique alias that was assigned for this table.
-   */
-  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array());
-
-  /**
-   * Orders the result set by a given field.
-   *
-   * If called multiple times, the query will order by each specified field in the
-   * order this method is called.
-   *
-   * If the query uses DISTINCT or GROUP BY conditions, fields or expressions
-   * that are used for the order must be selected to be compatible with some
-   * databases like PostgreSQL. The PostgreSQL driver can handle simple cases
-   * automatically but it is suggested to explicitly specify them. Additionally,
-   * when ordering on an alias, the alias must be added before orderBy() is
-   * called.
-   *
-   * @param $field
-   *   The field on which to order.
-   * @param $direction
-   *   The direction to sort. Legal values are "ASC" and "DESC".
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function orderBy($field, $direction = 'ASC');
-
-  /**
-   * Orders the result set by a random value.
-   *
-   * This may be stacked with other orderBy() calls. If so, the query will order
-   * by each specified field, including this one, in the order called. Although
-   * this method may be called multiple times on the same query, doing so
-   * is not particularly useful.
-   *
-   * Note: The method used by most drivers may not scale to very large result
-   * sets. If you need to work with extremely large data sets, you may create
-   * your own database driver by subclassing off of an existing driver and
-   * implementing your own randomization mechanism. See
-   *
-   * http://jan.kneschke.de/projects/mysql/order-by-rand/
-   *
-   * for an example of such an alternate sorting mechanism.
-   *
-   * @return SelectQueryInterface
-   *   The called object
-   */
-  public function orderRandom();
-
-  /**
-   * Restricts a query to a given range in the result set.
-   *
-   * If this method is called with no parameters, will remove any range
-   * directives that have been set.
-   *
-   * @param $start
-   *   The first record from the result set to return. If NULL, removes any
-   *   range directives that are set.
-   * @param $length
-   *   The number of records to return from the result set.
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function range($start = NULL, $length = NULL);
-
-  /**
-   * Add another Select query to UNION to this one.
-   *
-   * Union queries consist of two or more queries whose
-   * results are effectively concatenated together. Queries
-   * will be UNIONed in the order they are specified, with
-   * this object's query coming first. Duplicate columns will
-   * be discarded. All forms of UNION are supported, using
-   * the second '$type' argument.
-   *
-   * Note: All queries UNIONed together must have the same
-   * field structure, in the same order. It is up to the
-   * caller to ensure that they match properly. If they do
-   * not, an SQL syntax error will result.
-   *
-   * @param $query
-   *   The query to UNION to this query.
-   * @param $type
-   *   The type of UNION to add to the query. Defaults to plain
-   *   UNION.
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function union(SelectQueryInterface $query, $type = '');
-
-  /**
-   * Groups the result set by the specified field.
-   *
-   * @param $field
-   *   The field on which to group. This should be the field as aliased.
-   * @return SelectQueryInterface
-   *   The called object.
-   */
-  public function groupBy($field);
-
-  /**
-   * Get the equivalent COUNT query of this query as a new query object.
-   *
-   * @return SelectQueryInterface
-   *   A new SelectQuery object with no fields or expressions besides COUNT(*).
-   */
-  public function countQuery();
-
-  /**
-   * Indicates if preExecute() has already been called on that object.
-   *
-   * @return
-   *   TRUE is this query has already been prepared, FALSE otherwise.
-   */
-  public function isPrepared();
-
-  /**
-   * Generic preparation and validation for a SELECT query.
-   *
-   * @return
-   *   TRUE if the validation was successful, FALSE if not.
-   */
-  public function preExecute(SelectQueryInterface $query = NULL);
-
-  /**
-   * Helper function to build most common HAVING conditional clauses.
-   *
-   * This method can take a variable number of parameters. If called with two
-   * parameters, they are taken as $field and $value with $operator having a value
-   * of IN if $value is an array and = otherwise.
-   *
-   * @param $field
-   *   The name of the field to check. If you would like to add a more complex
-   *   condition involving operators or functions, use having().
-   * @param $value
-   *   The value to test the field against. In most cases, this is a scalar. For more
-   *   complex options, it is an array. The meaning of each element in the array is
-   *   dependent on the $operator.
-   * @param $operator
-   *   The comparison operator, such as =, <, or >=. It also accepts more complex
-   *   options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
-   *   = otherwise.
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function havingCondition($field, $value = NULL, $operator = NULL);
-
-  /**
-   * Clone magic method.
-   *
-   * Select queries have dependent objects that must be deep-cloned.  The
-   * connection object itself, however, should not be cloned as that would
-   * duplicate the connection itself.
-   */
-  public function __clone();
-
-  /**
-   * Add FOR UPDATE to the query.
-   *
-   * FOR UPDATE prevents the rows retrieved by the SELECT statement from being
-   * modified or deleted by other transactions until the current transaction
-   * ends. Other transactions that attempt UPDATE, DELETE, or SELECT FOR UPDATE
-   * of these rows will be blocked until the current transaction ends.
-   *
-   * @param $set
-   *   IF TRUE, FOR UPDATE will be added to the query, if FALSE then it won't.
-   *
-   * @return QueryConditionInterface
-   *   The called object.
-   */
-  public function forUpdate($set = TRUE);
-}
-
-/**
- * The base extender class for Select queries.
- */
-class SelectQueryExtender implements SelectQueryInterface {
-
-  /**
-   * The SelectQuery object we are extending/decorating.
-   *
-   * @var SelectQueryInterface
-   */
-  protected $query;
-
-  /**
-   * The connection object on which to run this query.
-   *
-   * @var DatabaseConnection
-   */
-  protected $connection;
-
-  /**
-   * A unique identifier for this query object.
-   */
-  protected $uniqueIdentifier;
-
-  /**
-   * The placeholder counter.
-   */
-  protected $placeholder = 0;
-
-  public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-    $this->query = $query;
-    $this->connection = $connection;
-  }
-
-  /**
-   * Implements QueryPlaceholderInterface::uniqueIdentifier().
-   */
-  public function uniqueIdentifier() {
-    return $this->uniqueIdentifier;
-  }
-
-  /**
-   * Implements QueryPlaceholderInterface::nextPlaceholder().
-   */
-  public function nextPlaceholder() {
-    return $this->placeholder++;
-  }
-
-  /* Implementations of QueryAlterableInterface. */
-
-  public function addTag($tag) {
-    $this->query->addTag($tag);
-    return $this;
-  }
-
-  public function hasTag($tag) {
-    return $this->query->hasTag($tag);
-  }
-
-  public function hasAllTags() {
-    return call_user_func_array(array($this->query, 'hasAllTags'), func_get_args());
-  }
-
-  public function hasAnyTag() {
-    return call_user_func_array(array($this->query, 'hasAnyTags'), func_get_args());
-  }
-
-  public function addMetaData($key, $object) {
-    $this->query->addMetaData($key, $object);
-    return $this;
-  }
-
-  public function getMetaData($key) {
-    return $this->query->getMetaData($key);
-  }
-
-  /* Implementations of QueryConditionInterface for the WHERE clause. */
-
-  public function condition($field, $value = NULL, $operator = NULL) {
-    $this->query->condition($field, $value, $operator);
-    return $this;
-  }
-
-  public function &conditions() {
-    return $this->query->conditions();
-  }
-
-  public function arguments() {
-    return $this->query->arguments();
-  }
-
-  public function where($snippet, $args = array()) {
-    $this->query->where($snippet, $args);
-    return $this;
-  }
-
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    return $this->query->compile($connection, $queryPlaceholder);
-  }
-
-  public function compiled() {
-    return $this->query->compiled();
-  }
-
-  /* Implementations of QueryConditionInterface for the HAVING clause. */
-
-  public function havingCondition($field, $value = NULL, $operator = '=') {
-    $this->query->havingCondition($field, $value, $operator);
-    return $this;
-  }
-
-  public function &havingConditions() {
-    return $this->query->havingConditions();
-  }
-
-  public function havingArguments() {
-    return $this->query->havingArguments();
-  }
-
-  public function having($snippet, $args = array()) {
-    $this->query->having($snippet, $args);
-    return $this;
-  }
-
-  public function havingCompile(DatabaseConnection $connection) {
-    return $this->query->havingCompile($connection);
-  }
-
-  /* Implementations of QueryExtendableInterface. */
-
-  public function extend($extender_name) {
-    // The extender can be anywhere so this needs to go to the registry, which
-    // is surely loaded by now.
-    $class = $this->connection->getDriverClass($extender_name, array(), TRUE);
-    return new $class($this, $this->connection);
-  }
-
-  /* Alter accessors to expose the query data to alter hooks. */
-
-  public function &getFields() {
-    return $this->query->getFields();
-  }
-
-  public function &getExpressions() {
-    return $this->query->getExpressions();
-  }
-
-  public function &getOrderBy() {
-    return $this->query->getOrderBy();
-  }
-
-  public function &getGroupBy() {
-    return $this->query->getGroupBy();
-  }
-
-  public function &getTables() {
-    return $this->query->getTables();
-  }
-
-  public function &getUnion() {
-    return $this->query->getUnion();
-  }
-
-  public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
-    return $this->query->getArguments($queryPlaceholder);
-  }
-
-  public function isPrepared() {
-    return $this->query->isPrepared();
-  }
-
-  public function preExecute(SelectQueryInterface $query = NULL) {
-    // If no query object is passed in, use $this.
-    if (!isset($query)) {
-      $query = $this;
-    }
-
-    return $this->query->preExecute($query);
-  }
-
-  public function execute() {
-    // By calling preExecute() here, we force it to preprocess the extender
-    // object rather than just the base query object.  That means
-    // hook_query_alter() gets access to the extended object.
-    if (!$this->preExecute($this)) {
-      return NULL;
-    }
-
-    return $this->query->execute();
-  }
-
-  public function distinct($distinct = TRUE) {
-    $this->query->distinct($distinct);
-    return $this;
-  }
-
-  public function addField($table_alias, $field, $alias = NULL) {
-    return $this->query->addField($table_alias, $field, $alias);
-  }
-
-  public function fields($table_alias, array $fields = array()) {
-    $this->query->fields($table_alias, $fields);
-    return $this;
-  }
-
-  public function addExpression($expression, $alias = NULL, $arguments = array()) {
-    return $this->query->addExpression($expression, $alias, $arguments);
-  }
-
-  public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->query->join($table, $alias, $condition, $arguments);
-  }
-
-  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->query->innerJoin($table, $alias, $condition, $arguments);
-  }
-
-  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->query->leftJoin($table, $alias, $condition, $arguments);
-  }
-
-  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->query->rightJoin($table, $alias, $condition, $arguments);
-  }
-
-  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->query->addJoin($type, $table, $alias, $condition, $arguments);
-  }
-
-  public function orderBy($field, $direction = 'ASC') {
-    $this->query->orderBy($field, $direction);
-    return $this;
-  }
-
-  public function orderRandom() {
-    $this->query->orderRandom();
-    return $this;
-  }
-
-  public function range($start = NULL, $length = NULL) {
-    $this->query->range($start, $length);
-    return $this;
-  }
-
-  public function union(SelectQueryInterface $query, $type = '') {
-    $this->query->union($query, $type);
-    return $this;
-  }
-
-  public function groupBy($field) {
-    $this->query->groupBy($field);
-    return $this;
-  }
-
-  public function forUpdate($set = TRUE) {
-    $this->query->forUpdate($set);
-    return $this;
-  }
-
-  public function countQuery() {
-    return $this->query->countQuery();
-  }
-
-  function isNull($field) {
-    $this->query->isNull($field);
-    return $this;
-  }
-
-  function isNotNull($field) {
-    $this->query->isNotNull($field);
-    return $this;
-  }
-
-  public function exists(SelectQueryInterface $select) {
-    $this->query->exists($select);
-    return $this;
-  }
-
-  public function notExists(SelectQueryInterface $select) {
-    $this->query->notExists($select);
-    return $this;
-  }
-
-  public function __toString() {
-    return (string) $this->query;
-  }
-
-  public function __clone() {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-
-    // We need to deep-clone the query we're wrapping, which in turn may
-    // deep-clone other objects.  Exciting!
-    $this->query = clone($this->query);
-  }
-
-  /**
-   * Magic override for undefined methods.
-   *
-   * If one extender extends another extender, then methods in the inner extender
-   * will not be exposed on the outer extender.  That's because we cannot know
-   * in advance what those methods will be, so we cannot provide wrapping
-   * implementations as we do above.  Instead, we use this slower catch-all method
-   * to handle any additional methods.
-   */
-  public function __call($method, $args) {
-    $return = call_user_func_array(array($this->query, $method), $args);
-
-    // Some methods will return the called object as part of a fluent interface.
-    // Others will return some useful value.  If it's a value, then the caller
-    // probably wants that value.  If it's the called object, then we instead
-    // return this object.  That way we don't "lose" an extender layer when
-    // chaining methods together.
-    if ($return instanceof SelectQueryInterface) {
-      return $this;
-    }
-    else {
-      return $return;
-    }
-  }
-}
-
-/**
- * Query builder for SELECT statements.
- */
-class SelectQuery extends Query implements SelectQueryInterface {
-
-  /**
-   * The fields to SELECT.
-   *
-   * @var array
-   */
-  protected $fields = array();
-
-  /**
-   * The expressions to SELECT as virtual fields.
-   *
-   * @var array
-   */
-  protected $expressions = array();
-
-  /**
-   * The tables against which to JOIN.
-   *
-   * This property is a nested array. Each entry is an array representing
-   * a single table against which to join. The structure of each entry is:
-   *
-   * array(
-   *   'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER),
-   *   'table' => $table,
-   *   'alias' => $alias_of_the_table,
-   *   'condition' => $condition_clause_on_which_to_join,
-   *   'arguments' => $array_of_arguments_for_placeholders_in_the condition.
-   *   'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise.
-   * )
-   *
-   * If $table is a string, it is taken as the name of a table. If it is
-   * a SelectQuery object, it is taken as a subquery.
-   *
-   * @var array
-   */
-  protected $tables = array();
-
-  /**
-   * The fields by which to order this query.
-   *
-   * This is an associative array. The keys are the fields to order, and the value
-   * is the direction to order, either ASC or DESC.
-   *
-   * @var array
-   */
-  protected $order = array();
-
-  /**
-   * The fields by which to group.
-   *
-   * @var array
-   */
-  protected $group = array();
-
-  /**
-   * The conditional object for the WHERE clause.
-   *
-   * @var DatabaseCondition
-   */
-  protected $where;
-
-  /**
-   * The conditional object for the HAVING clause.
-   *
-   * @var DatabaseCondition
-   */
-  protected $having;
-
-  /**
-   * Whether or not this query should be DISTINCT
-   *
-   * @var boolean
-   */
-  protected $distinct = FALSE;
-
-  /**
-   * The range limiters for this query.
-   *
-   * @var array
-   */
-  protected $range;
-
-  /**
-   * An array whose elements specify a query to UNION, and the UNION type. The
-   * 'type' key may be '', 'ALL', or 'DISTINCT' to represent a 'UNION',
-   * 'UNION ALL', or 'UNION DISTINCT' statement, respectively.
-   *
-   * All entries in this array will be applied from front to back, with the
-   * first query to union on the right of the original query, the second union
-   * to the right of the first, etc.
-   *
-   * @var array
-   */
-  protected $union = array();
-
-  /**
-   * Indicates if preExecute() has already been called.
-   * @var boolean
-   */
-  protected $prepared = FALSE;
-
-  /**
-   * The FOR UPDATE status
-   */
-  protected $forUpdate = FALSE;
-
-  public function __construct($table, $alias = NULL, DatabaseConnection $connection, $options = array()) {
-    $options['return'] = Database::RETURN_STATEMENT;
-    parent::__construct($connection, $options);
-    $this->where = new DatabaseCondition('AND');
-    $this->having = new DatabaseCondition('AND');
-    $this->addJoin(NULL, $table, $alias);
-  }
-
-  /* Implementations of QueryAlterableInterface. */
-
-  public function addTag($tag) {
-    $this->alterTags[$tag] = 1;
-    return $this;
-  }
-
-  public function hasTag($tag) {
-    return isset($this->alterTags[$tag]);
-  }
-
-  public function hasAllTags() {
-    return !(boolean)array_diff(func_get_args(), array_keys($this->alterTags));
-  }
-
-  public function hasAnyTag() {
-    return (boolean)array_intersect(func_get_args(), array_keys($this->alterTags));
-  }
-
-  public function addMetaData($key, $object) {
-    $this->alterMetaData[$key] = $object;
-    return $this;
-  }
-
-  public function getMetaData($key) {
-    return isset($this->alterMetaData[$key]) ? $this->alterMetaData[$key] : NULL;
-  }
-
-  /* Implementations of QueryConditionInterface for the WHERE clause. */
-
-  public function condition($field, $value = NULL, $operator = NULL) {
-    $this->where->condition($field, $value, $operator);
-    return $this;
-  }
-
-  public function &conditions() {
-    return $this->where->conditions();
-  }
-
-  public function arguments() {
-    if (!$this->compiled()) {
-      return NULL;
-    }
-
-    $args = $this->where->arguments() + $this->having->arguments();
-
-    foreach ($this->tables as $table) {
-      if ($table['arguments']) {
-        $args += $table['arguments'];
-      }
-      // If this table is a subquery, grab its arguments recursively.
-      if ($table['table'] instanceof SelectQueryInterface) {
-        $args += $table['table']->arguments();
-      }
-    }
-
-    foreach ($this->expressions as $expression) {
-      if ($expression['arguments']) {
-        $args += $expression['arguments'];
-      }
-    }
-
-    // If there are any dependent queries to UNION,
-    // incorporate their arguments recursively.
-    foreach ($this->union as $union) {
-      $args += $union['query']->arguments();
-    }
-
-    return $args;
-  }
-
-  public function where($snippet, $args = array()) {
-    $this->where->where($snippet, $args);
-    return $this;
-  }
-
-  public function isNull($field) {
-    $this->where->isNull($field);
-    return $this;
-  }
-
-  public function isNotNull($field) {
-    $this->where->isNotNull($field);
-    return $this;
-  }
-
-  public function exists(SelectQueryInterface $select) {
-    $this->where->exists($select);
-    return $this;
-  }
-
-  public function notExists(SelectQueryInterface $select) {
-    $this->where->notExists($select);
-    return $this;
-  }
-
-  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
-    $this->where->compile($connection, $queryPlaceholder);
-    $this->having->compile($connection, $queryPlaceholder);
-
-    foreach ($this->tables as $table) {
-      // If this table is a subquery, compile it recursively.
-      if ($table['table'] instanceof SelectQueryInterface) {
-        $table['table']->compile($connection, $queryPlaceholder);
-      }
-    }
-
-    // If there are any dependent queries to UNION, compile it recursively.
-    foreach ($this->union as $union) {
-      $union['query']->compile($connection, $queryPlaceholder);
-    }
-  }
-
-  public function compiled() {
-    if (!$this->where->compiled() || !$this->having->compiled()) {
-      return FALSE;
-    }
-
-    foreach ($this->tables as $table) {
-      // If this table is a subquery, check its status recursively.
-      if ($table['table'] instanceof SelectQueryInterface) {
-        if (!$table['table']->compiled()) {
-          return FALSE;
-        }
-      }
-    }
-
-    foreach ($this->union as $union) {
-      if (!$union['query']->compiled()) {
-        return FALSE;
-      }
-    }
-
-    return TRUE;
-  }
-
-  /* Implementations of QueryConditionInterface for the HAVING clause. */
-
-  public function havingCondition($field, $value = NULL, $operator = NULL) {
-    $this->having->condition($field, $value, $operator);
-    return $this;
-  }
-
-  public function &havingConditions() {
-    return $this->having->conditions();
-  }
-
-  public function havingArguments() {
-    return $this->having->arguments();
-  }
-
-  public function having($snippet, $args = array()) {
-    $this->having->where($snippet, $args);
-    return $this;
-  }
-
-  public function havingCompile(DatabaseConnection $connection) {
-    return $this->having->compile($connection, $this);
-  }
-
-  /* Implementations of QueryExtendableInterface. */
-
-  public function extend($extender_name) {
-    $override_class = $extender_name . '_' . $this->connection->driver();
-    if (class_exists($override_class)) {
-      $extender_name = $override_class;
-    }
-    return new $extender_name($this, $this->connection);
-  }
-
-  public function havingIsNull($field) {
-    $this->having->isNull($field);
-    return $this;
-  }
-
-  public function havingIsNotNull($field) {
-    $this->having->isNotNull($field);
-    return $this;
-  }
-
-  public function havingExists(SelectQueryInterface $select) {
-    $this->having->exists($select);
-    return $this;
-  }
-
-  public function havingNotExists(SelectQueryInterface $select) {
-    $this->having->notExists($select);
-    return $this;
-  }
-
-  public function forUpdate($set = TRUE) {
-    if (isset($set)) {
-      $this->forUpdate = $set;
-    }
-    return $this;
-  }
-
-  /* Alter accessors to expose the query data to alter hooks. */
-
-  public function &getFields() {
-    return $this->fields;
-  }
-
-  public function &getExpressions() {
-    return $this->expressions;
-  }
-
-  public function &getOrderBy() {
-    return $this->order;
-  }
-
-  public function &getGroupBy() {
-    return $this->group;
-  }
-
-  public function &getTables() {
-    return $this->tables;
-  }
-
-  public function &getUnion() {
-    return $this->union;
-  }
-
-  public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
-    if (!isset($queryPlaceholder)) {
-      $queryPlaceholder = $this;
-    }
-    $this->compile($this->connection, $queryPlaceholder);
-    return $this->arguments();
-  }
-
-  /**
-   * Indicates if preExecute() has already been called on that object.
-   */
-  public function isPrepared() {
-    return $this->prepared;
-  }
-
-  /**
-   * Generic preparation and validation for a SELECT query.
-   *
-   * @return
-   *   TRUE if the validation was successful, FALSE if not.
-   */
-  public function preExecute(SelectQueryInterface $query = NULL) {
-    // If no query object is passed in, use $this.
-    if (!isset($query)) {
-      $query = $this;
-    }
-
-    // Only execute this once.
-    if ($query->isPrepared()) {
-      return TRUE;
-    }
-
-    // Modules may alter all queries or only those having a particular tag.
-    if (isset($this->alterTags)) {
-      $hooks = array('query');
-      foreach ($this->alterTags as $tag => $value) {
-        $hooks[] = 'query_' . $tag;
-      }
-      drupal_alter($hooks, $query);
-    }
-
-    $this->prepared = TRUE;
-
-    // Now also prepare any sub-queries.
-    foreach ($this->tables as $table) {
-      if ($table['table'] instanceof SelectQueryInterface) {
-        $table['table']->preExecute();
-      }
-    }
-
-    foreach ($this->union as $union) {
-      $union['query']->preExecute();
-    }
-
-    return $this->prepared;
-  }
-
-  public function execute() {
-    // If validation fails, simply return NULL.
-    // Note that validation routines in preExecute() may throw exceptions instead.
-    if (!$this->preExecute()) {
-      return NULL;
-    }
-
-    $args = $this->getArguments();
-    return $this->connection->query((string) $this, $args, $this->queryOptions);
-  }
-
-  public function distinct($distinct = TRUE) {
-    $this->distinct = $distinct;
-    return $this;
-  }
-
-  public function addField($table_alias, $field, $alias = NULL) {
-    // If no alias is specified, first try the field name itself.
-    if (empty($alias)) {
-      $alias = $field;
-    }
-
-    // If that's already in use, try the table name and field name.
-    if (!empty($this->fields[$alias])) {
-      $alias = $table_alias . '_' . $field;
-    }
-
-    // If that is already used, just add a counter until we find an unused alias.
-    $alias_candidate = $alias;
-    $count = 2;
-    while (!empty($this->fields[$alias_candidate])) {
-      $alias_candidate = $alias . '_' . $count++;
-    }
-    $alias = $alias_candidate;
-
-    $this->fields[$alias] = array(
-      'field' => $field,
-      'table' => $table_alias,
-      'alias' => $alias,
-    );
-
-    return $alias;
-  }
-
-  public function fields($table_alias, array $fields = array()) {
-
-    if ($fields) {
-      foreach ($fields as $field) {
-        // We don't care what alias was assigned.
-        $this->addField($table_alias, $field);
-      }
-    }
-    else {
-      // We want all fields from this table.
-      $this->tables[$table_alias]['all_fields'] = TRUE;
-    }
-
-    return $this;
-  }
-
-  public function addExpression($expression, $alias = NULL, $arguments = array()) {
-    if (empty($alias)) {
-      $alias = 'expression';
-    }
-
-    $alias_candidate = $alias;
-    $count = 2;
-    while (!empty($this->expressions[$alias_candidate])) {
-      $alias_candidate = $alias . '_' . $count++;
-    }
-    $alias = $alias_candidate;
-
-    $this->expressions[$alias] = array(
-      'expression' => $expression,
-      'alias' => $alias,
-      'arguments' => $arguments,
-    );
-
-    return $alias;
-  }
-
-  public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
-  }
-
-  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
-  }
-
-  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->addJoin('LEFT OUTER', $table, $alias, $condition, $arguments);
-  }
-
-  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
-    return $this->addJoin('RIGHT OUTER', $table, $alias, $condition, $arguments);
-  }
-
-  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
-
-    if (empty($alias)) {
-      if ($table instanceof SelectQueryInterface) {
-        $alias = 'subquery';
-      }
-      else {
-        $alias = $table;
-      }
-    }
-
-    $alias_candidate = $alias;
-    $count = 2;
-    while (!empty($this->tables[$alias_candidate])) {
-      $alias_candidate = $alias . '_' . $count++;
-    }
-    $alias = $alias_candidate;
-
-    if (is_string($condition)) {
-      $condition = str_replace('%alias', $alias, $condition);
-    }
-
-    $this->tables[$alias] = array(
-      'join type' => $type,
-      'table' => $table,
-      'alias' => $alias,
-      'condition' => $condition,
-      'arguments' => $arguments,
-    );
-
-    return $alias;
-  }
-
-  public function orderBy($field, $direction = 'ASC') {
-    $this->order[$field] = $direction;
-    return $this;
-  }
-
-  public function orderRandom() {
-    $alias = $this->addExpression('RAND()', 'random_field');
-    $this->orderBy($alias);
-    return $this;
-  }
-
-  public function range($start = NULL, $length = NULL) {
-    $this->range = func_num_args() ? array('start' => $start, 'length' => $length) : array();
-    return $this;
-  }
-
-  public function union(SelectQueryInterface $query, $type = '') {
-    // Handle UNION aliasing.
-    switch ($type) {
-      // Fold UNION DISTINCT to UNION for better cross database support.
-      case 'DISTINCT':
-      case '':
-        $type = 'UNION';
-        break;
-
-      case 'ALL':
-        $type = 'UNION ALL';
-      default:
-    }
-
-    $this->union[] = array(
-      'type' => $type,
-      'query' => $query,
-    );
-
-    return $this;
-  }
-
-  public function groupBy($field) {
-    $this->group[$field] = $field;
-    return $this;
-  }
-
-  public function countQuery() {
-    // Create our new query object that we will mutate into a count query.
-    $count = clone($this);
-
-    $group_by = $count->getGroupBy();
-    $having = $count->havingConditions();
-
-    if (!$count->distinct && !isset($having[0])) {
-      // When not executing a distinct query, we can zero-out existing fields
-      // and expressions that are not used by a GROUP BY or HAVING. Fields
-      // listed in a GROUP BY or HAVING clause need to be present in the
-      // query.
-      $fields =& $count->getFields();
-      foreach (array_keys($fields) as $field) {
-        if (empty($group_by[$field])) {
-          unset($fields[$field]);
-        }
-      }
-
-      $expressions =& $count->getExpressions();
-      foreach (array_keys($expressions) as $field) {
-        if (empty($group_by[$field])) {
-          unset($expressions[$field]);
-        }
-      }
-
-      // Also remove 'all_fields' statements, which are expanded into tablename.*
-      // when the query is executed.
-      foreach ($count->tables as $alias => &$table) {
-        unset($table['all_fields']);
-      }
-    }
-
-    // If we've just removed all fields from the query, make sure there is at
-    // least one so that the query still runs.
-    $count->addExpression('1');
-
-    // Ordering a count query is a waste of cycles, and breaks on some
-    // databases anyway.
-    $orders = &$count->getOrderBy();
-    $orders = array();
-
-    if ($count->distinct && !empty($group_by)) {
-      // If the query is distinct and contains a GROUP BY, we need to remove the
-      // distinct because SQL99 does not support counting on distinct multiple fields.
-      $count->distinct = FALSE;
-    }
-
-    $query = $this->connection->select($count);
-    $query->addExpression('COUNT(*)');
-
-    return $query;
-  }
-
-  public function __toString() {
-    // For convenience, we compile the query ourselves if the caller forgot
-    // to do it. This allows constructs like "(string) $query" to work. When
-    // the query will be executed, it will be recompiled using the proper
-    // placeholder generator anyway.
-    if (!$this->compiled()) {
-      $this->compile($this->connection, $this);
-    }
-
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    // SELECT
-    $query = $comments . 'SELECT ';
-    if ($this->distinct) {
-      $query .= 'DISTINCT ';
-    }
-
-    // FIELDS and EXPRESSIONS
-    $fields = array();
-    foreach ($this->tables as $alias => $table) {
-      if (!empty($table['all_fields'])) {
-        $fields[] = $this->connection->escapeTable($alias) . '.*';
-      }
-    }
-    foreach ($this->fields as $alias => $field) {
-      // Always use the AS keyword for field aliases, as some
-      // databases require it (e.g., PostgreSQL).
-      $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
-    }
-    foreach ($this->expressions as $alias => $expression) {
-      $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
-    }
-    $query .= implode(', ', $fields);
-
-
-    // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
-    $query .= "\nFROM ";
-    foreach ($this->tables as $alias => $table) {
-      $query .= "\n";
-      if (isset($table['join type'])) {
-        $query .= $table['join type'] . ' JOIN ';
-      }
-
-      // If the table is a subquery, compile it and integrate it into this query.
-      if ($table['table'] instanceof SelectQueryInterface) {
-        // Run preparation steps on this sub-query before converting to string.
-        $subquery = $table['table'];
-        $subquery->preExecute();
-        $table_string = '(' . (string) $subquery . ')';
-      }
-      else {
-        $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
-      }
-
-      // Don't use the AS keyword for table aliases, as some
-      // databases don't support it (e.g., Oracle).
-      $query .=  $table_string . ' ' . $this->connection->escapeTable($table['alias']);
-
-      if (!empty($table['condition'])) {
-        $query .= ' ON ' . $table['condition'];
-      }
-    }
-
-    // WHERE
-    if (count($this->where)) {
-      // There is an implicit string cast on $this->condition.
-      $query .= "\nWHERE " . $this->where;
-    }
-
-    // GROUP BY
-    if ($this->group) {
-      $query .= "\nGROUP BY " . implode(', ', $this->group);
-    }
-
-    // HAVING
-    if (count($this->having)) {
-      // There is an implicit string cast on $this->having.
-      $query .= "\nHAVING " . $this->having;
-    }
-
-    // ORDER BY
-    if ($this->order) {
-      $query .= "\nORDER BY ";
-      $fields = array();
-      foreach ($this->order as $field => $direction) {
-        $fields[] = $field . ' ' . $direction;
-      }
-      $query .= implode(', ', $fields);
-    }
-
-    // RANGE
-    // There is no universal SQL standard for handling range or limit clauses.
-    // Fortunately, all core-supported databases use the same range syntax.
-    // Databases that need a different syntax can override this method and
-    // do whatever alternate logic they need to.
-    if (!empty($this->range)) {
-      $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
-    }
-
-    // UNION is a little odd, as the select queries to combine are passed into
-    // this query, but syntactically they all end up on the same level.
-    if ($this->union) {
-      foreach ($this->union as $union) {
-        $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
-      }
-    }
-
-    if ($this->forUpdate) {
-      $query .= ' FOR UPDATE';
-    }
-
-    return $query;
-  }
-
-  public function __clone() {
-    // On cloning, also clone the dependent objects. However, we do not
-    // want to clone the database connection object as that would duplicate the
-    // connection itself.
-
-    $this->where = clone($this->where);
-    $this->having = clone($this->having);
-    foreach ($this->union as $key => $aggregate) {
-      $this->union[$key]['query'] = clone($aggregate['query']);
-    }
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/sqlite/query.inc b/core/includes/database/sqlite/query.inc
deleted file mode 100644
index 6b8a72f2ab46aed8da9f908a7f66f4f71d27b11a..0000000000000000000000000000000000000000
--- a/core/includes/database/sqlite/query.inc
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-/**
- * @file
- * Query code for SQLite embedded database engine.
- */
-
-/**
- * @ingroup database
- * @{
- */
-
-/**
- * SQLite specific implementation of InsertQuery.
- *
- * We ignore all the default fields and use the clever SQLite syntax:
- *   INSERT INTO table DEFAULT VALUES
- * for degenerated "default only" queries.
- */
-class InsertQuery_sqlite extends InsertQuery {
-
-  public function execute() {
-    if (!$this->preExecute()) {
-      return NULL;
-    }
-    if (count($this->insertFields)) {
-      return parent::execute();
-    }
-    else {
-      return $this->connection->query('INSERT INTO {' . $this->table . '} DEFAULT VALUES', array(), $this->queryOptions);
-    }
-  }
-
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    // Produce as many generic placeholders as necessary.
-    $placeholders = array_fill(0, count($this->insertFields), '?');
-
-    // If we're selecting from a SelectQuery, finish building the query and
-    // pass it back, as any remaining options are irrelevant.
-    if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
-    }
-
-    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
-  }
-
-}
-
-/**
- * SQLite specific implementation of UpdateQuery.
- *
- * SQLite counts all the rows that match the conditions as modified, even if they
- * will not be affected by the query. We workaround this by ensuring that
- * we don't select those rows.
- *
- * A query like this one:
- *   UPDATE test SET name = 'newname' WHERE tid = 1
- * will become:
- *   UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
- */
-class UpdateQuery_sqlite extends UpdateQuery {
-  /**
-   * Helper function that removes the fields that are already in a condition.
-   *
-   * @param $fields
-   *   The fields.
-   * @param QueryConditionInterface $condition
-   *   A database condition.
-   */
-  protected function removeFieldsInCondition(&$fields, QueryConditionInterface $condition) {
-    foreach ($condition->conditions() as $child_condition) {
-      if ($child_condition['field'] instanceof QueryConditionInterface) {
-        $this->removeFieldsInCondition($fields, $child_condition['field']);
-      }
-      else {
-        unset($fields[$child_condition['field']]);
-      }
-    }
-  }
-
-  public function execute() {
-    if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
-      return parent::execute();
-    }
-
-    // Get the fields used in the update query, and remove those that are already
-    // in the condition.
-    $fields = $this->expressionFields + $this->fields;
-    $this->removeFieldsInCondition($fields, $this->condition);
-
-    // Add the inverse of the fields to the condition.
-    $condition = new DatabaseCondition('OR');
-    foreach ($fields as $field => $data) {
-      if (is_array($data)) {
-        // The field is an expression.
-        $condition->where($field . ' <> ' . $data['expression']);
-        $condition->isNull($field);
-      }
-      elseif (!isset($data)) {
-        // The field will be set to NULL.
-        $condition->isNotNull($field);
-      }
-      else {
-        $condition->condition($field, $data, '<>');
-        $condition->isNull($field);
-      }
-    }
-    if (count($condition)) {
-      $condition->compile($this->connection, $this);
-      $this->condition->where((string) $condition, $condition->arguments());
-    }
-    return parent::execute();
-  }
-
-}
-
-/**
- * SQLite specific implementation of DeleteQuery.
- *
- * When the WHERE is omitted from a DELETE statement and the table being deleted
- * has no triggers, SQLite uses an optimization to erase the entire table content
- * without having to visit each row of the table individually.
- *
- * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
- * by that optimized "truncate" optimization.
- */
-class DeleteQuery_sqlite extends DeleteQuery {
-  public function execute() {
-    if (!count($this->condition)) {
-      $total_rows = $this->connection->query('SELECT COUNT(*) FROM {' . $this->connection->escapeTable($this->table) . '}')->fetchField();
-      parent::execute();
-      return $total_rows;
-    }
-    else {
-      return parent::execute();
-    }
-  }
-}
-
-/**
- * SQLite specific implementation of TruncateQuery.
- *
- * SQLite doesn't support TRUNCATE, but a DELETE query with no condition has
- * exactly the effect (it is implemented by DROPing the table).
- */
-class TruncateQuery_sqlite extends TruncateQuery {
-  public function __toString() {
-    // Create a sanitized comment string to prepend to the query.
-    $comments = $this->connection->makeComment($this->comments);
-
-    return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/sqlite/select.inc b/core/includes/database/sqlite/select.inc
deleted file mode 100644
index fb926ef04d3124d7cb8efe35a7e51a0e81301f6c..0000000000000000000000000000000000000000
--- a/core/includes/database/sqlite/select.inc
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Select builder for SQLite embedded database engine.
- */
-
-/**
- * @ingroup database
- * @{
- */
-
-/**
- * SQLite specific query builder for SELECT statements.
- */
-class SelectQuery_sqlite extends SelectQuery {
-  public function forUpdate($set = TRUE) {
-    // SQLite does not support FOR UPDATE so nothing to do.
-    return $this;
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
-
-
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index ef7eafe4f917d7364c80ba5b5a17499dd5826962..f16e094d8e6bf7c57301b82c8c7136a5978ebe84 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Install\TaskException;
+
 /**
  * @file
  * API functions for installing Drupal.
@@ -223,6 +226,27 @@ function install_begin_request(&$install_state) {
 
   // Allow command line scripts to override server variables used by Drupal.
   require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
+
+  // Ensure that the class loader is available so that we can leverage classes
+  // as part of the install routine.
+  $loader = drupal_classloader();
+
+  // Register explicit vendor namespaces.
+  $loader->registerNamespaces(array(
+    // All Symfony-borrowed code lives in /core/includes/Symfony.
+    'Symfony' => DRUPAL_ROOT . '/core/vendor',
+  ));
+  // Register the Drupal namespace for classes in core as a fallback.
+  // This allows to register additional namespaces within the Drupal namespace
+  // (e.g., for modules) and avoids an additional file_exists() on the Drupal
+  // core namespace, since the class loader can already determine the best
+  // namespace match based on a string comparison. It further allows modules to
+  // register/overload namespaces in Drupal core.
+  $loader->registerNamespaceFallbacks(array(
+    // All Drupal-namespaced code in core lives in /core/includes/Drupal.
+    'Drupal' => DRUPAL_ROOT . '/core/lib',
+  ));
+
   if (!$install_state['interactive']) {
     drupal_override_server_variables($install_state['server']);
   }
@@ -961,7 +985,7 @@ function install_database_errors($database, $settings_file) {
     try {
       db_run_tasks($driver);
     }
-    catch (DatabaseTaskException $e) {
+    catch (TaskException $e) {
       // These are generic errors, so we do not have any specific key of the
       // database connection array to attach them to; therefore, we just put
       // them in the error array with standard numeric keys.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 533678f0f2ff770915c6021d947a069fb4889e4c..8a25693a1c2a0dce3c827f9d17827912b19d5967 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * Indicates that a module has not been installed yet.
  */
@@ -246,6 +248,7 @@ function drupal_detect_database_types() {
  */
 function drupal_get_database_types() {
   $databases = array();
+  $drivers = array();
 
   // We define a driver as a directory in /core/includes/database that in turn
   // contains a database.inc file. That allows us to drop in additional drivers
@@ -253,8 +256,8 @@ function drupal_get_database_types() {
   // Because we have no registry yet, we need to also include the install.inc
   // file for the driver explicitly.
   require_once DRUPAL_ROOT . '/core/includes/database/database.inc';
-  foreach (file_scan_directory(DRUPAL_ROOT . '/core/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
-    if (file_exists($file->uri . '/database.inc') && file_exists($file->uri . '/install.inc')) {
+  foreach (file_scan_directory(DRUPAL_ROOT . '/core/lib/Drupal/Core/Database/Driver', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
+    if (file_exists($file->uri . '/Install/Tasks.php')) {
       $drivers[$file->filename] = $file->uri;
     }
   }
@@ -276,305 +279,6 @@ function drupal_get_database_types() {
   return $databases;
 }
 
-/**
- * Database installer structure.
- *
- * Defines basic Drupal requirements for databases.
- */
-abstract class DatabaseTasks {
-
-  /**
-   * Structure that describes each task to run.
-   *
-   * @var array
-   *
-   * Each value of the tasks array is an associative array defining the function
-   * to call (optional) and any arguments to be passed to the function.
-   */
-  protected $tasks = array(
-    array(
-      'function'    => 'checkEngineVersion',
-      'arguments'   => array(),
-    ),
-    array(
-      'arguments'   => array(
-        'CREATE TABLE {drupal_install_test} (id int NULL)',
-        'Drupal can use CREATE TABLE database commands.',
-        'Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>',
-        TRUE,
-      ),
-    ),
-    array(
-      'arguments'   => array(
-        'INSERT INTO {drupal_install_test} (id) VALUES (1)',
-        'Drupal can use INSERT database commands.',
-        'Failed to <strong>INSERT</strong> a value into a test table on your database server. We tried inserting a value with the command %query and the server reported the following error: %error.',
-      ),
-    ),
-    array(
-      'arguments'   => array(
-        'UPDATE {drupal_install_test} SET id = 2',
-        'Drupal can use UPDATE database commands.',
-        'Failed to <strong>UPDATE</strong> a value in a test table on your database server. We tried updating a value with the command %query and the server reported the following error: %error.',
-      ),
-    ),
-    array(
-      'arguments'   => array(
-        'DELETE FROM {drupal_install_test}',
-        'Drupal can use DELETE database commands.',
-        'Failed to <strong>DELETE</strong> a value from a test table on your database server. We tried deleting a value with the command %query and the server reported the following error: %error.',
-      ),
-    ),
-    array(
-      'arguments'   => array(
-        'DROP TABLE {drupal_install_test}',
-        'Drupal can use DROP TABLE database commands.',
-        'Failed to <strong>DROP</strong> a test table from your database server. We tried dropping a table with the command %query and the server reported the following error %error.',
-      ),
-    ),
-  );
-
-  /**
-   * Results from tasks.
-   *
-   * @var array
-   */
-  protected $results = array();
-
-  /**
-   * Ensure the PDO driver is supported by the version of PHP in use.
-   */
-  protected function hasPdoDriver() {
-    return in_array($this->pdoDriver, PDO::getAvailableDrivers());
-  }
-
-  /**
-   * Assert test as failed.
-   */
-  protected function fail($message) {
-    $this->results[$message] = FALSE;
-  }
-
-  /**
-   * Assert test as a pass.
-   */
-  protected function pass($message) {
-    $this->results[$message] = TRUE;
-  }
-
-  /**
-   * Check whether Drupal is installable on the database.
-   */
-  public function installable() {
-    return $this->hasPdoDriver() && empty($this->error);
-  }
-
-  /**
-   * Return the human-readable name of the driver.
-   */
-  abstract public function name();
-
-  /**
-   * Return the minimum required version of the engine.
-   *
-   * @return
-   *   A version string. If not NULL, it will be checked against the version
-   *   reported by the Database engine using version_compare().
-   */
-  public function minimumVersion() {
-    return NULL;
-  }
-
-  /**
-   * Run database tasks and tests to see if Drupal can run on the database.
-   */
-  public function runTasks() {
-    // We need to establish a connection before we can run tests.
-    if ($this->connect()) {
-      foreach ($this->tasks as $task) {
-        if (!isset($task['function'])) {
-          $task['function'] = 'runTestQuery';
-        }
-        if (method_exists($this, $task['function'])) {
-          // Returning false is fatal. No other tasks can run.
-          if (FALSE === call_user_func_array(array($this, $task['function']), $task['arguments'])) {
-            break;
-          }
-        }
-        else {
-          throw new DatabaseTaskException(st("Failed to run all tasks against the database server. The task %task wasn't found.", array('%task' => $task['function'])));
-        }
-      }
-    }
-    // Check for failed results and compile message
-    $message = '';
-    foreach ($this->results as $result => $success) {
-      if (!$success) {
-        $message .= '<p class="error">' . $result  . '</p>';
-      }
-    }
-    if (!empty($message)) {
-      $message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
-      throw new DatabaseTaskException($message);
-    }
-  }
-
-  /**
-   * Check if we can connect to the database.
-   */
-  protected function connect() {
-    try {
-      // This doesn't actually test the connection.
-      db_set_active();
-      // Now actually do a check.
-      Database::getConnection();
-      $this->pass('Drupal can CONNECT to the database ok.');
-    }
-    catch (Exception $e) {
-      $this->fail(st('Failed to connect to your database server. The server reports the following message: %error.<ul><li>Is the database server running?</li><li>Does the database exist, and have you entered the correct database name?</li><li>Have you entered the correct username and password?</li><li>Have you entered the correct database hostname?</li></ul>', array('%error' => $e->getMessage())));
-      return FALSE;
-    }
-    return TRUE;
-  }
-
-  /**
-   * Run SQL tests to ensure the database can execute commands with the current user.
-   */
-  protected function runTestQuery($query, $pass, $fail, $fatal = FALSE) {
-    try {
-      db_query($query);
-      $this->pass(st($pass));
-    }
-    catch (Exception $e) {
-      $this->fail(st($fail, array('%query' => $query, '%error' => $e->getMessage(), '%name' => $this->name())));
-      return !$fatal;
-    }
-  }
-
-  /**
-   * Check the engine version.
-   */
-  protected function checkEngineVersion() {
-    if ($this->minimumVersion() && version_compare(Database::getConnection()->version(), $this->minimumVersion(), '<')) {
-      $this->fail(st("The database version %version is less than the minimum required version %minimum_version.", array('%version' => Database::getConnection()->version(), '%minimum_version' => $this->minimumVersion())));
-    }
-  }
-
-  /**
-   * Return driver specific configuration options.
-   *
-   * @param $database
-   *  An array of driver specific configuration options.
-   *
-   * @return
-   *   The options form array.
-   */
-  public function getFormOptions($database) {
-    $form['database'] = array(
-      '#type' => 'textfield',
-      '#title' => st('Database name'),
-      '#default_value' => empty($database['database']) ? '' : $database['database'],
-      '#size' => 45,
-      '#required' => TRUE,
-      '#description' => st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_distribution_name())),
-    );
-
-    $form['username'] = array(
-      '#type' => 'textfield',
-      '#title' => st('Database username'),
-      '#default_value' => empty($database['username']) ? '' : $database['username'],
-      '#required' => TRUE,
-      '#size' => 45,
-    );
-
-    $form['password'] = array(
-      '#type' => 'password',
-      '#title' => st('Database password'),
-      '#default_value' => empty($database['password']) ? '' : $database['password'],
-      '#required' => FALSE,
-      '#size' => 45,
-    );
-
-    $form['advanced_options'] = array(
-      '#type' => 'fieldset',
-      '#title' => st('Advanced options'),
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE,
-      '#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider."),
-      '#weight' => 10,
-    );
-
-    $profile = drupal_get_profile();
-    $db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
-    $form['advanced_options']['db_prefix'] = array(
-      '#type' => 'textfield',
-      '#title' => st('Table prefix'),
-      '#default_value' => '',
-      '#size' => 45,
-      '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_distribution_name(), '%prefix' => $db_prefix)),
-      '#weight' => 10,
-    );
-
-    $form['advanced_options']['host'] = array(
-      '#type' => 'textfield',
-      '#title' => st('Database host'),
-      '#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
-      '#size' => 45,
-      // Hostnames can be 255 characters long.
-      '#maxlength' => 255,
-      '#required' => TRUE,
-      '#description' => st('If your database is located on a different server, change this.'),
-    );
-
-    $form['advanced_options']['port'] = array(
-      '#type' => 'textfield',
-      '#title' => st('Database port'),
-      '#default_value' => empty($database['port']) ? '' : $database['port'],
-      '#size' => 45,
-      // The maximum port number is 65536, 5 digits.
-      '#maxlength' => 5,
-      '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
-    );
-
-    return $form;
-  }
-
-  /**
-   * Validates driver specific configuration settings.
-   *
-   * Checks to ensure correct basic database settings and that a proper
-   * connection to the database can be established.
-   *
-   * @param $database
-   *   An array of driver specific configuration options.
-   *
-   * @return
-   *   An array of driver configuration errors, keyed by form element name.
-   */
-  public function validateDatabaseSettings($database) {
-    $errors = array();
-
-    // Verify the table prefix.
-    if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
-      $errors[$database['driver'] . '][advanced_options][db_prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
-    }
-
-    // Verify the database port.
-    if (!empty($database['port']) && !is_numeric($database['port'])) {
-      $errors[$database['driver'] . '][advanced_options][port'] =  st('Database port must be a number.');
-    }
-
-    return $errors;
-  }
-
-}
-
-/**
- * Exception thrown if the database installer fails.
- */
-class DatabaseTaskException extends Exception {
-}
-
 /**
  * Replace values in settings.php with values in the submitted array.
  *
@@ -1300,7 +1004,8 @@ function db_run_tasks($driver) {
  *   The name of the driver.
  */
 function db_installer_object($driver) {
-  Database::loadDriverFile($driver, array('install.inc'));
-  $task_class = 'DatabaseTasks_' . $driver;
+  // We cannot use Database::getConnection->getDriverClass() here, because
+  // the connection object is not yet functional.
+  $task_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Install\\Tasks";
   return new $task_class();
 }
diff --git a/core/includes/pager.inc b/core/includes/pager.inc
index c060d0e7cda526b514e3ac999a01e789151ca412..c579e7e64809c81f9df08dfbbef9424a291a15a5 100644
--- a/core/includes/pager.inc
+++ b/core/includes/pager.inc
@@ -1,18 +1,21 @@
 <?php
 
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\Query\SelectExtender;
+use Drupal\Core\Database\Query\SelectInterface;
+
 /**
  * @file
  * Functions to aid in presenting database results as a set of pages.
  */
 
-
 /**
  * Query extender for pager queries.
  *
  * This is the "default" pager mechanism.  It creates a paged query with a fixed
  * number of entries per page.
  */
-class PagerDefault extends SelectQueryExtender {
+class PagerDefault extends SelectExtender {
 
   /**
    * The highest element we've autogenerated so far.
@@ -42,7 +45,7 @@ class PagerDefault extends SelectQueryExtender {
    */
   protected $customCountQuery = FALSE;
 
-  public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
+  public function __construct(SelectInterface $query, Connection $connection) {
     parent::__construct($query, $connection);
 
     // Add pager tag. Do this here to ensure that it is always added before
@@ -103,7 +106,7 @@ protected function ensureElement() {
    *   The count query object.  It must return a single row with a single column,
    *   which is the total number of records.
    */
-  public function setCountQuery(SelectQueryInterface $query) {
+  public function setCountQuery(SelectInterface $query) {
     $this->customCountQuery = $query;
   }
 
diff --git a/core/includes/registry.inc b/core/includes/registry.inc
index 2ddd1f7f70a8d90333911d10a20f91d49a12420f..7ac296017942aca8c1d0245829dfda4333399681 100644
--- a/core/includes/registry.inc
+++ b/core/includes/registry.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * This file contains the code registry parser engine.
@@ -20,18 +22,12 @@
  */
 function _registry_update() {
 
-  // The registry serves as a central autoloader for all classes, including
-  // the database query builders. However, the registry rebuild process
-  // requires write ability to the database, which means having access to the
-  // query builders that require the registry in order to be loaded. That
-  // causes a fatal race condition. Therefore we manually include the
-  // appropriate query builders for the currently active database before the
-  // registry rebuild process runs.
+  // The registry serves as a central autoloader for all non-namespaced classes.
+  // It is backed by the database, but the database system is autoloaded using
+  // a PSR-0 class loader.  That avoids a fata circular dependency here, since
+  // the other class loader will be able to load the database for us.
   $connection_info = Database::getConnectionInfo();
   $driver = $connection_info['default']['driver'];
-  require_once DRUPAL_ROOT . '/core/includes/database/query.inc';
-  require_once DRUPAL_ROOT . '/core/includes/database/select.inc';
-  require_once DRUPAL_ROOT . '/core/includes/database/' . $driver . '/query.inc';
 
   // Get current list of modules and their files.
   $modules = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAll();
diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc
index 7873cdb2db42f2aba2a6f0ae876f7ffb7c02def2..3c70b965c30a0df9757022dd3cb2dfa2d79d0d29 100644
--- a/core/includes/tablesort.inc
+++ b/core/includes/tablesort.inc
@@ -1,5 +1,9 @@
 <?php
 
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\Query\SelectExtender;
+use Drupal\Core\Database\Query\SelectInterface;
+
 /**
  * @file
  * Functions to aid in the creation of sortable tables.
@@ -8,11 +12,10 @@
  * column headers that the user can click on to sort the table by that column.
  */
 
-
 /**
  * Query extender class for tablesort queries.
  */
-class TableSort extends SelectQueryExtender {
+class TableSort extends SelectExtender {
 
   /**
    * The array of fields that can be sorted by.
@@ -21,7 +24,7 @@ class TableSort extends SelectQueryExtender {
    */
   protected $header = array();
 
-  public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
+  public function __construct(SelectInterface $query, Connection $connection) {
     parent::__construct($query, $connection);
 
     // Add convenience tag to mark that this is an extended query. We have to
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e9e44aec14605fc8b6f902a49e2937ef0b03126
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -0,0 +1,1126 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Connection
+ */
+
+namespace Drupal\Core\Database;
+
+use Drupal\Core\Database\TransactionNoActiveException;
+use Drupal\Core\Database\TransactionOutOfOrderException;
+
+use PDO;
+use PDOException;
+
+/**
+ * Base Database API class.
+ *
+ * This class provides a Drupal-specific extension of the PDO database
+ * abstraction class in PHP. Every database driver implementation must provide a
+ * concrete implementation of it to support special handling required by that
+ * database.
+ *
+ * @see http://php.net/manual/en/book.pdo.php
+ */
+abstract class Connection extends PDO {
+
+  /**
+   * The database target this connection is for.
+   *
+   * We need this information for later auditing and logging.
+   *
+   * @var string
+   */
+  protected $target = NULL;
+
+  /**
+   * The key representing this connection.
+   *
+   * The key is a unique string which identifies a database connection. A
+   * connection can be a single server or a cluster of master and slaves (use
+   * target to pick between master and slave).
+   *
+   * @var string
+   */
+  protected $key = NULL;
+
+  /**
+   * The current database logging object for this connection.
+   *
+   * @var Log
+   */
+  protected $logger = NULL;
+
+  /**
+   * Tracks the number of "layers" of transactions currently active.
+   *
+   * On many databases transactions cannot nest.  Instead, we track
+   * nested calls to transactions and collapse them into a single
+   * transaction.
+   *
+   * @var array
+   */
+  protected $transactionLayers = array();
+
+  /**
+   * Index of what driver-specific class to use for various operations.
+   *
+   * @var array
+   */
+  protected $driverClasses = array();
+
+  /**
+   * The name of the Statement class for this connection.
+   *
+   * @var string
+   */
+  protected $statementClass = 'Drupal\Core\Database\Statement';
+
+  /**
+   * Whether this database connection supports transactions.
+   *
+   * @var bool
+   */
+  protected $transactionSupport = TRUE;
+
+  /**
+   * Whether this database connection supports transactional DDL.
+   *
+   * Set to FALSE by default because few databases support this feature.
+   *
+   * @var bool
+   */
+  protected $transactionalDDLSupport = FALSE;
+
+  /**
+   * An index used to generate unique temporary table names.
+   *
+   * @var integer
+   */
+  protected $temporaryNameIndex = 0;
+
+  /**
+   * The connection information for this connection object.
+   *
+   * @var array
+   */
+  protected $connectionOptions = array();
+
+  /**
+   * The schema object for this connection.
+   *
+   * @var object
+   */
+  protected $schema = NULL;
+
+  /**
+   * The prefixes used by this database connection.
+   *
+   * @var array
+   */
+  protected $prefixes = array();
+
+  /**
+   * List of search values for use in prefixTables().
+   *
+   * @var array
+   */
+  protected $prefixSearch = array();
+
+  /**
+   * List of replacement values for use in prefixTables().
+   *
+   * @var array
+   */
+  protected $prefixReplace = array();
+
+  function __construct($dsn, $username, $password, $driver_options = array()) {
+    // Initialize and prepare the connection prefix.
+    $this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
+
+    // Because the other methods don't seem to work right.
+    $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
+
+    // Call PDO::__construct and PDO::setAttribute.
+    parent::__construct($dsn, $username, $password, $driver_options);
+
+    // Set a specific PDOStatement class if the driver requires that.
+    if (!empty($this->statementClass)) {
+      $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this)));
+    }
+  }
+
+  /**
+   * Returns the default query options for any given query.
+   *
+   * A given query can be customized with a number of option flags in an
+   * associative array:
+   * - target: The database "target" against which to execute a query. Valid
+   *   values are "default" or "slave". The system will first try to open a
+   *   connection to a database specified with the user-supplied key. If one
+   *   is not available, it will silently fall back to the "default" target.
+   *   If multiple databases connections are specified with the same target,
+   *   one will be selected at random for the duration of the request.
+   * - fetch: This element controls how rows from a result set will be
+   *   returned. Legal values include PDO::FETCH_ASSOC, PDO::FETCH_BOTH,
+   *   PDO::FETCH_OBJ, PDO::FETCH_NUM, or a string representing the name of a
+   *   class. If a string is specified, each record will be fetched into a new
+   *   object of that class. The behavior of all other values is defined by PDO.
+   *   See http://php.net/manual/pdostatement.fetch.php
+   * - return: Depending on the type of query, different return values may be
+   *   meaningful. This directive instructs the system which type of return
+   *   value is desired. The system will generally set the correct value
+   *   automatically, so it is extremely rare that a module developer will ever
+   *   need to specify this value. Setting it incorrectly will likely lead to
+   *   unpredictable results or fatal errors. Legal values include:
+   *   - Database::RETURN_STATEMENT: Return the prepared statement object for
+   *     the query. This is usually only meaningful for SELECT queries, where
+   *     the statement object is how one accesses the result set returned by the
+   *     query.
+   *   - Database::RETURN_AFFECTED: Return the number of rows affected by an
+   *     UPDATE or DELETE query. Be aware that means the number of rows actually
+   *     changed, not the number of rows matched by the WHERE clause.
+   *   - Database::RETURN_INSERT_ID: Return the sequence ID (primary key)
+   *     created by an INSERT statement on a table that contains a serial
+   *     column.
+   *   - Database::RETURN_NULL: Do not return anything, as there is no
+   *     meaningful value to return. That is the case for INSERT queries on
+   *     tables that do not contain a serial column.
+   * - throw_exception: By default, the database system will catch any errors
+   *   on a query as an Exception, log it, and then rethrow it so that code
+   *   further up the call chain can take an appropriate action. To suppress
+   *   that behavior and simply return NULL on failure, set this option to
+   *   FALSE.
+   *
+   * @return
+   *   An array of default query options.
+   */
+  protected function defaultOptions() {
+    return array(
+      'target' => 'default',
+      'fetch' => PDO::FETCH_OBJ,
+      'return' => Database::RETURN_STATEMENT,
+      'throw_exception' => TRUE,
+    );
+  }
+
+  /**
+   * Returns the connection information for this connection object.
+   *
+   * Note that Database::getConnectionInfo() is for requesting information
+   * about an arbitrary database connection that is defined. This method
+   * is for requesting the connection information of this specific
+   * open connection object.
+   *
+   * @return
+   *   An array of the connection information. The exact list of
+   *   properties is driver-dependent.
+   */
+  public function getConnectionOptions() {
+    return $this->connectionOptions;
+  }
+
+  /**
+   * Set the list of prefixes used by this database connection.
+   *
+   * @param $prefix
+   *   The prefixes, in any of the multiple forms documented in
+   *   default.settings.php.
+   */
+  protected function setPrefix($prefix) {
+    if (is_array($prefix)) {
+      $this->prefixes = $prefix + array('default' => '');
+    }
+    else {
+      $this->prefixes = array('default' => $prefix);
+    }
+
+    // Set up variables for use in prefixTables(). Replace table-specific
+    // prefixes first.
+    $this->prefixSearch = array();
+    $this->prefixReplace = array();
+    foreach ($this->prefixes as $key => $val) {
+      if ($key != 'default') {
+        $this->prefixSearch[] = '{' . $key . '}';
+        $this->prefixReplace[] = $val . $key;
+      }
+    }
+    // Then replace remaining tables with the default prefix.
+    $this->prefixSearch[] = '{';
+    $this->prefixReplace[] = $this->prefixes['default'];
+    $this->prefixSearch[] = '}';
+    $this->prefixReplace[] = '';
+  }
+
+  /**
+   * Appends a database prefix to all tables in a query.
+   *
+   * Queries sent to Drupal should wrap all table names in curly brackets. This
+   * function searches for this syntax and adds Drupal's table prefix to all
+   * tables, allowing Drupal to coexist with other systems in the same database
+   * and/or schema if necessary.
+   *
+   * @param $sql
+   *   A string containing a partial or entire SQL query.
+   *
+   * @return
+   *   The properly-prefixed string.
+   */
+  public function prefixTables($sql) {
+    return str_replace($this->prefixSearch, $this->prefixReplace, $sql);
+  }
+
+  /**
+   * Find the prefix for a table.
+   *
+   * This function is for when you want to know the prefix of a table. This
+   * is not used in prefixTables due to performance reasons.
+   */
+  public function tablePrefix($table = 'default') {
+    if (isset($this->prefixes[$table])) {
+      return $this->prefixes[$table];
+    }
+    else {
+      return $this->prefixes['default'];
+    }
+  }
+
+  /**
+   * Prepares a query string and returns the prepared statement.
+   *
+   * This method caches prepared statements, reusing them when
+   * possible. It also prefixes tables names enclosed in curly-braces.
+   *
+   * @param $query
+   *   The query string as SQL, with curly-braces surrounding the
+   *   table names.
+   *
+   * @return Drupal\Core\Database\StatementInterface
+   *   A PDO prepared statement ready for its execute() method.
+   */
+  public function prepareQuery($query) {
+    $query = $this->prefixTables($query);
+
+    // Call PDO::prepare.
+    return parent::prepare($query);
+  }
+
+  /**
+   * Tells this connection object what its target value is.
+   *
+   * This is needed for logging and auditing. It's sloppy to do in the
+   * constructor because the constructor for child classes has a different
+   * signature. We therefore also ensure that this function is only ever
+   * called once.
+   *
+   * @param $target
+   *   The target this connection is for. Set to NULL (default) to disable
+   *   logging entirely.
+   */
+  public function setTarget($target = NULL) {
+    if (!isset($this->target)) {
+      $this->target = $target;
+    }
+  }
+
+  /**
+   * Returns the target this connection is associated with.
+   *
+   * @return
+   *   The target string of this connection.
+   */
+  public function getTarget() {
+    return $this->target;
+  }
+
+  /**
+   * Tells this connection object what its key is.
+   *
+   * @param $target
+   *   The key this connection is for.
+   */
+  public function setKey($key) {
+    if (!isset($this->key)) {
+      $this->key = $key;
+    }
+  }
+
+  /**
+   * Returns the key this connection is associated with.
+   *
+   * @return
+   *   The key of this connection.
+   */
+  public function getKey() {
+    return $this->key;
+  }
+
+  /**
+   * Associates a logging object with this connection.
+   *
+   * @param $logger
+   *   The logging object we want to use.
+   */
+  public function setLogger(Log $logger) {
+    $this->logger = $logger;
+  }
+
+  /**
+   * Gets the current logging object for this connection.
+   *
+   * @return DatabaseLog
+   *   The current logging object for this connection. If there isn't one,
+   *   NULL is returned.
+   */
+  public function getLogger() {
+    return $this->logger;
+  }
+
+  /**
+   * Creates the appropriate sequence name for a given table and serial field.
+   *
+   * This information is exposed to all database drivers, although it is only
+   * useful on some of them. This method is table prefix-aware.
+   *
+   * @param $table
+   *   The table name to use for the sequence.
+   * @param $field
+   *   The field name to use for the sequence.
+   *
+   * @return
+   *   A table prefix-parsed string for the sequence name.
+   */
+  public function makeSequenceName($table, $field) {
+    return $this->prefixTables('{' . $table . '}_' . $field . '_seq');
+  }
+
+  /**
+   * Flatten an array of query comments into a single comment string.
+   *
+   * The comment string will be sanitized to avoid SQL injection attacks.
+   *
+   * @param $comments
+   *   An array of query comment strings.
+   *
+   * @return
+   *   A sanitized comment string.
+   */
+  public function makeComment($comments) {
+    if (empty($comments))
+      return '';
+
+    // Flatten the array of comments.
+    $comment = implode('; ', $comments);
+
+    // Sanitize the comment string so as to avoid SQL injection attacks.
+    return '/* ' . $this->filterComment($comment) . ' */ ';
+  }
+
+  /**
+   * Sanitize a query comment string.
+   *
+   * Ensure a query comment does not include strings such as "* /" that might
+   * terminate the comment early. This avoids SQL injection attacks via the
+   * query comment. The comment strings in this example are separated by a
+   * space to avoid PHP parse errors.
+   *
+   * For example, the comment:
+   * @code
+   * db_update('example')
+   *  ->condition('id', $id)
+   *  ->fields(array('field2' => 10))
+   *  ->comment('Exploit * / DROP TABLE node; --')
+   *  ->execute()
+   * @endcode
+   *
+   * Would result in the following SQL statement being generated:
+   * @code
+   * "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..."
+   * @endcode
+   *
+   * Unless the comment is sanitised first, the SQL server would drop the
+   * node table and ignore the rest of the SQL statement.
+   *
+   * @param $comment
+   *   A query comment string.
+   *
+   * @return
+   *   A sanitized version of the query comment string.
+   */
+  protected function filterComment($comment = '') {
+    return preg_replace('/(\/\*\s*)|(\s*\*\/)/', '', $comment);
+  }
+
+  /**
+   * Executes a query string against the database.
+   *
+   * This method provides a central handler for the actual execution of every
+   * query. All queries executed by Drupal are executed as PDO prepared
+   * statements.
+   *
+   * @param $query
+   *   The query to execute. In most cases this will be a string containing
+   *   an SQL query with placeholders. An already-prepared instance of
+   *   DatabaseStatementInterface may also be passed in order to allow calling
+   *   code to manually bind variables to a query. If a
+   *   DatabaseStatementInterface is passed, the $args array will be ignored.
+   *   It is extremely rare that module code will need to pass a statement
+   *   object to this method. It is used primarily for database drivers for
+   *   databases that require special LOB field handling.
+   * @param $args
+   *   An array of arguments for the prepared statement. If the prepared
+   *   statement uses ? placeholders, this array must be an indexed array.
+   *   If it contains named placeholders, it must be an associative array.
+   * @param $options
+   *   An associative array of options to control how the query is run. See
+   *   the documentation for DatabaseConnection::defaultOptions() for details.
+   *
+   * @return Drupal\Core\Database\StatementInterface
+   *   This method will return one of: the executed statement, the number of
+   *   rows affected by the query (not the number matched), or the generated
+   *   insert IT of the last query, depending on the value of
+   *   $options['return']. Typically that value will be set by default or a
+   *   query builder and should not be set by a user. If there is an error,
+   *   this method will return NULL and may throw an exception if
+   *   $options['throw_exception'] is TRUE.
+   *
+   * @throws PDOException
+   */
+  public function query($query, array $args = array(), $options = array()) {
+
+    // Use default values if not already set.
+    $options += $this->defaultOptions();
+
+    try {
+      // We allow either a pre-bound statement object or a literal string.
+      // In either case, we want to end up with an executed statement object,
+      // which we pass to PDOStatement::execute.
+      if ($query instanceof DatabaseStatementInterface) {
+        $stmt = $query;
+        $stmt->execute(NULL, $options);
+      }
+      else {
+        $this->expandArguments($query, $args);
+        $stmt = $this->prepareQuery($query);
+        $stmt->execute($args, $options);
+      }
+
+      // Depending on the type of query we may need to return a different value.
+      // See DatabaseConnection::defaultOptions() for a description of each
+      // value.
+      switch ($options['return']) {
+        case Database::RETURN_STATEMENT:
+          return $stmt;
+        case Database::RETURN_AFFECTED:
+          return $stmt->rowCount();
+        case Database::RETURN_INSERT_ID:
+          return $this->lastInsertId();
+        case Database::RETURN_NULL:
+          return;
+        default:
+          throw new PDOException('Invalid return directive: ' . $options['return']);
+      }
+    }
+    catch (PDOException $e) {
+      if ($options['throw_exception']) {
+        // Add additional debug information.
+        if ($query instanceof DatabaseStatementInterface) {
+          $e->query_string = $stmt->getQueryString();
+        }
+        else {
+          $e->query_string = $query;
+        }
+        $e->args = $args;
+        throw $e;
+      }
+      return NULL;
+    }
+  }
+
+  /**
+   * Expands out shorthand placeholders.
+   *
+   * Drupal supports an alternate syntax for doing arrays of values. We
+   * therefore need to expand them out into a full, executable query string.
+   *
+   * @param $query
+   *   The query string to modify.
+   * @param $args
+   *   The arguments for the query.
+   *
+   * @return
+   *   TRUE if the query was modified, FALSE otherwise.
+   */
+  protected function expandArguments(&$query, &$args) {
+    $modified = FALSE;
+
+    // If the placeholder value to insert is an array, assume that we need
+    // to expand it out into a comma-delimited set of placeholders.
+    foreach (array_filter($args, 'is_array') as $key => $data) {
+      $new_keys = array();
+      foreach ($data as $i => $value) {
+        // This assumes that there are no other placeholders that use the same
+        // name.  For example, if the array placeholder is defined as :example
+        // and there is already an :example_2 placeholder, this will generate
+        // a duplicate key.  We do not account for that as the calling code
+        // is already broken if that happens.
+        $new_keys[$key . '_' . $i] = $value;
+      }
+
+      // Update the query with the new placeholders.
+      // preg_replace is necessary to ensure the replacement does not affect
+      // placeholders that start with the same exact text. For example, if the
+      // query contains the placeholders :foo and :foobar, and :foo has an
+      // array of values, using str_replace would affect both placeholders,
+      // but using the following preg_replace would only affect :foo because
+      // it is followed by a non-word character.
+      $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
+
+      // Update the args array with the new placeholders.
+      unset($args[$key]);
+      $args += $new_keys;
+
+      $modified = TRUE;
+    }
+
+    return $modified;
+  }
+
+  /**
+   * Gets the driver-specific override class if any for the specified class.
+   *
+   * @param string $class
+   *   The class for which we want the potentially driver-specific class.
+   * @return string
+   *   The name of the class that should be used for this driver.
+   */
+  public function getDriverClass($class) {
+    if (empty($this->driverClasses[$class])) {
+      $driver = $this->driver();
+      $driver_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\{$class}";
+      $this->driverClasses[$class] = class_exists($driver_class) ? $driver_class : $class;
+    }
+    return $this->driverClasses[$class];
+  }
+
+  /**
+   * Prepares and returns a SELECT query object.
+   *
+   * @param $table
+   *   The base table for this query, that is, the first table in the FROM
+   *   clause. This table will also be used as the "base" table for query_alter
+   *   hook implementations.
+   * @param $alias
+   *   The alias of the base table of this query.
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   An appropriate SelectQuery object for this database connection. Note that
+   *   it may be a driver-specific subclass of SelectQuery, depending on the
+   *   driver.
+   *
+   * @see Drupal\Core\Database\Query\Select
+   */
+  public function select($table, $alias = NULL, array $options = array()) {
+    $class = $this->getDriverClass('Select');
+    return new $class($table, $alias, $this, $options);
+  }
+
+  /**
+   * Prepares and returns an INSERT query object.
+   *
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\Insert
+   *   A new Insert query object.
+   *
+   * @see Drupal\Core\Database\Query\Insert
+   */
+  public function insert($table, array $options = array()) {
+    $class = $this->getDriverClass('Insert');
+    return new $class($this, $table, $options);
+  }
+
+  /**
+   * Prepares and returns a MERGE query object.
+   *
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   A new Merge query object.
+   *
+   * @see Drupal\Core\Database\Query\Merge
+   */
+  public function merge($table, array $options = array()) {
+    $class = $this->getDriverClass('Merge');
+    return new $class($this, $table, $options);
+  }
+
+
+  /**
+   * Prepares and returns an UPDATE query object.
+   *
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\Update
+   *   A new Update query object.
+   *
+   * @see Drupal\Core\Database\Query\Update
+   */
+  public function update($table, array $options = array()) {
+    $class = $this->getDriverClass('Update');
+    return new $class($this, $table, $options);
+  }
+
+  /**
+   * Prepares and returns a DELETE query object.
+   *
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\Delete
+   *   A new Delete query object.
+   *
+   * @see Drupal\Core\Database\Query\Delete
+   */
+  public function delete($table, array $options = array()) {
+    $class = $this->getDriverClass('Delete');
+    return new $class($this, $table, $options);
+  }
+
+  /**
+   * Prepares and returns a TRUNCATE query object.
+   *
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\Query\Truncate
+   *   A new Truncate query object.
+   *
+   * @see Drupal\Core\Database\Query\Truncate
+   */
+  public function truncate($table, array $options = array()) {
+    $class = $this->getDriverClass('Truncate');
+    return new $class($this, $table, $options);
+  }
+
+  /**
+   * Returns a DatabaseSchema object for manipulating the schema.
+   *
+   * This method will lazy-load the appropriate schema library file.
+   *
+   * @return Drupal\Core\Database\Schema
+   *   The database Schema object for this connection.
+   */
+  public function schema() {
+    if (empty($this->schema)) {
+      $class = $this->getDriverClass('Schema');
+      $this->schema = new $class($this);
+    }
+    return $this->schema;
+  }
+
+  /**
+   * Escapes a table name string.
+   *
+   * Force all table names to be strictly alphanumeric-plus-underscore.
+   * For some database drivers, it may also wrap the table name in
+   * database-specific escape characters.
+   *
+   * @return
+   *   The sanitized table name string.
+   */
+  public function escapeTable($table) {
+    return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
+  }
+
+  /**
+   * Escapes a field name string.
+   *
+   * Force all field names to be strictly alphanumeric-plus-underscore.
+   * For some database drivers, it may also wrap the field name in
+   * database-specific escape characters.
+   *
+   * @return
+   *   The sanitized field name string.
+   */
+  public function escapeField($field) {
+    return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+  }
+
+  /**
+   * Escapes an alias name string.
+   *
+   * Force all alias names to be strictly alphanumeric-plus-underscore. In
+   * contrast to DatabaseConnection::escapeField() /
+   * DatabaseConnection::escapeTable(), this doesn't allow the period (".")
+   * because that is not allowed in aliases.
+   *
+   * @return
+   *   The sanitized field name string.
+   */
+  public function escapeAlias($field) {
+    return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
+  }
+
+  /**
+   * Escapes characters that work as wildcard characters in a LIKE pattern.
+   *
+   * The wildcard characters "%" and "_" as well as backslash are prefixed with
+   * a backslash. Use this to do a search for a verbatim string without any
+   * wildcard behavior.
+   *
+   * For example, the following does a case-insensitive query for all rows whose
+   * name starts with $prefix:
+   * @code
+   * $result = db_query(
+   *   'SELECT * FROM person WHERE name LIKE :pattern',
+   *   array(':pattern' => db_like($prefix) . '%')
+   * );
+   * @endcode
+   *
+   * Backslash is defined as escape character for LIKE patterns in
+   * Drupal\Core\Database\Query\Condition::mapConditionOperator().
+   *
+   * @param $string
+   *   The string to escape.
+   *
+   * @return
+   *   The escaped string.
+   */
+  public function escapeLike($string) {
+    return addcslashes($string, '\%_');
+  }
+
+  /**
+   * Determines if there is an active transaction open.
+   *
+   * @return
+   *   TRUE if we're currently in a transaction, FALSE otherwise.
+   */
+  public function inTransaction() {
+    return ($this->transactionDepth() > 0);
+  }
+
+  /**
+   * Determines current transaction depth.
+   */
+  public function transactionDepth() {
+    return count($this->transactionLayers);
+  }
+
+  /**
+   * Returns a new DatabaseTransaction object on this connection.
+   *
+   * @param $name
+   *   Optional name of the savepoint.
+   *
+   * @see Drupal\Core\Database\Transaction
+   */
+  public function startTransaction($name = '') {
+    $class = $this->getDriverClass('Transaction');
+    return new $class($this, $name);
+  }
+
+  /**
+   * Rolls back the transaction entirely or to a named savepoint.
+   *
+   * This method throws an exception if no transaction is active.
+   *
+   * @param $savepoint_name
+   *   The name of the savepoint. The default, 'drupal_transaction', will roll
+   *   the entire transaction back.
+   *
+   * @throws Drupal\Core\Database\TransactionNoActiveException
+   *
+   * @see DatabaseTransaction::rollback()
+   */
+  public function rollback($savepoint_name = 'drupal_transaction') {
+    if (!$this->supportsTransactions()) {
+      return;
+    }
+    if (!$this->inTransaction()) {
+      throw new TransactionNoActiveException();
+    }
+    // A previous rollback to an earlier savepoint may mean that the savepoint
+    // in question has already been accidentally committed.
+    if (!isset($this->transactionLayers[$savepoint_name])) {
+      throw new TransactionNoActiveException();
+     }
+
+    // We need to find the point we're rolling back to, all other savepoints
+    // before are no longer needed. If we rolled back other active savepoints,
+    // we need to throw an exception.
+    $rolled_back_other_active_savepoints = FALSE;
+    while ($savepoint = array_pop($this->transactionLayers)) {
+      if ($savepoint == $savepoint_name) {
+        // If it is the last the transaction in the stack, then it is not a
+        // savepoint, it is the transaction itself so we will need to roll back
+        // the transaction rather than a savepoint.
+        if (empty($this->transactionLayers)) {
+          break;
+        }
+        $this->query('ROLLBACK TO SAVEPOINT ' . $savepoint);
+        $this->popCommittableTransactions();
+        if ($rolled_back_other_active_savepoints) {
+          throw new TransactionOutOfOrderException();
+        }
+        return;
+      }
+      else {
+        $rolled_back_other_active_savepoints = TRUE;
+      }
+    }
+    parent::rollBack();
+    if ($rolled_back_other_active_savepoints) {
+      throw new TransactionOutOfOrderException();
+    }
+  }
+
+  /**
+   * Increases the depth of transaction nesting.
+   *
+   * If no transaction is already active, we begin a new transaction.
+   *
+   * @throws Drupal\Core\Database\TransactionNameNonUniqueException
+   *
+   * @see Drupal\Core\Database\Transaction
+   */
+  public function pushTransaction($name) {
+    if (!$this->supportsTransactions()) {
+      return;
+    }
+    if (isset($this->transactionLayers[$name])) {
+      throw new TransactionNameNonUniqueException($name . " is already in use.");
+    }
+    // If we're already in a transaction then we want to create a savepoint
+    // rather than try to create another transaction.
+    if ($this->inTransaction()) {
+      $this->query('SAVEPOINT ' . $name);
+    }
+    else {
+      parent::beginTransaction();
+    }
+    $this->transactionLayers[$name] = $name;
+  }
+
+  /**
+   * Decreases the depth of transaction nesting.
+   *
+   * If we pop off the last transaction layer, then we either commit or roll
+   * back the transaction as necessary. If no transaction is active, we return
+   * because the transaction may have manually been rolled back.
+   *
+   * @param $name
+   *   The name of the savepoint
+   *
+   * @throws Drupal\Core\Database\TransactionNoActiveException
+   * @throws Drupal\Core\Database\TransactionCommitFailedException
+   *
+   * @see DatabaseTransaction
+   */
+  public function popTransaction($name) {
+    if (!$this->supportsTransactions()) {
+      return;
+    }
+    // The transaction has already been committed earlier. There is nothing we
+    // need to do. If this transaction was part of an earlier out-of-order
+    // rollback, an exception would already have been thrown by
+    // Database::rollback().
+    if (!isset($this->transactionLayers[$name])) {
+      return;
+    }
+
+    // Mark this layer as committable.
+    $this->transactionLayers[$name] = FALSE;
+    $this->popCommittableTransactions();
+  }
+
+  /**
+   * Internal function: commit all the transaction layers that can commit.
+   */
+  protected function popCommittableTransactions() {
+    // Commit all the committable layers.
+    foreach (array_reverse($this->transactionLayers) as $name => $active) {
+      // Stop once we found an active transaction.
+      if ($active) {
+        break;
+      }
+
+      // If there are no more layers left then we should commit.
+      unset($this->transactionLayers[$name]);
+      if (empty($this->transactionLayers)) {
+        if (!parent::commit()) {
+          throw new TransactionCommitFailedException();
+        }
+      }
+      else {
+        $this->query('RELEASE SAVEPOINT ' . $name);
+      }
+    }
+  }
+
+  /**
+   * Runs a limited-range query on this database object.
+   *
+   * Use this as a substitute for ->query() when a subset of the query is to be
+   * returned. User-supplied arguments to the query should be passed in as
+   * separate parameters so that they can be properly escaped to avoid SQL
+   * injection attacks.
+   *
+   * @param $query
+   *   A string containing an SQL query.
+   * @param $args
+   *   An array of values to substitute into the query at placeholder markers.
+   * @param $from
+   *   The first result row to return.
+   * @param $count
+   *   The maximum number of result rows to return.
+   * @param $options
+   *   An array of options on the query.
+   *
+   * @return Drupal\Core\Database\StatementInterface
+   *   A database query result resource, or NULL if the query was not executed
+   *   correctly.
+   */
+  abstract public function queryRange($query, $from, $count, array $args = array(), array $options = array());
+
+  /**
+   * Generates a temporary table name.
+   *
+   * @return
+   *   A table name.
+   */
+  protected function generateTemporaryTableName() {
+    return "db_temporary_" . $this->temporaryNameIndex++;
+  }
+
+  /**
+   * Runs a SELECT query and stores its results in a temporary table.
+   *
+   * Use this as a substitute for ->query() when the results need to stored
+   * in a temporary table. Temporary tables exist for the duration of the page
+   * request. User-supplied arguments to the query should be passed in as
+   * separate parameters so that they can be properly escaped to avoid SQL
+   * injection attacks.
+   *
+   * Note that if you need to know how many results were returned, you should do
+   * a SELECT COUNT(*) on the temporary table afterwards.
+   *
+   * @param $query
+   *   A string containing a normal SELECT SQL query.
+   * @param $args
+   *   An array of values to substitute into the query at placeholder markers.
+   * @param $options
+   *   An associative array of options to control how the query is run. See
+   *   the documentation for DatabaseConnection::defaultOptions() for details.
+   *
+   * @return
+   *   The name of the temporary table.
+   */
+  abstract function queryTemporary($query, array $args = array(), array $options = array());
+
+  /**
+   * Returns the type of database driver.
+   *
+   * This is not necessarily the same as the type of the database itself. For
+   * instance, there could be two MySQL drivers, mysql and mysql_mock. This
+   * function would return different values for each, but both would return
+   * "mysql" for databaseType().
+   */
+  abstract public function driver();
+
+  /**
+   * Returns the version of the database server.
+   */
+  public function version() {
+    return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
+  }
+
+  /**
+   * Determines if this driver supports transactions.
+   *
+   * @return
+   *   TRUE if this connection supports transactions, FALSE otherwise.
+   */
+  public function supportsTransactions() {
+    return $this->transactionSupport;
+  }
+
+  /**
+   * Determines if this driver supports transactional DDL.
+   *
+   * DDL queries are those that change the schema, such as ALTER queries.
+   *
+   * @return
+   *   TRUE if this connection supports transactions for DDL queries, FALSE
+   *   otherwise.
+   */
+  public function supportsTransactionalDDL() {
+    return $this->transactionalDDLSupport;
+  }
+
+  /**
+   * Returns the name of the PDO driver for this connection.
+   */
+  abstract public function databaseType();
+
+
+  /**
+   * Gets any special processing requirements for the condition operator.
+   *
+   * Some condition types require special processing, such as IN, because
+   * the value data they pass in is not a simple value. This is a simple
+   * overridable lookup function. Database connections should define only
+   * those operators they wish to be handled differently than the default.
+   *
+   * @param $operator
+   *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
+   *
+   * @return
+   *   The extra handling directives for the specified operator, or NULL.
+   *
+   * @see Drupal\Core\Database\Query\Condition::compile()
+   */
+  abstract public function mapConditionOperator($operator);
+
+  /**
+   * Throws an exception to deny direct access to transaction commits.
+   *
+   * We do not want to allow users to commit transactions at any time, only
+   * by destroying the transaction object or allowing it to go out of scope.
+   * A direct commit bypasses all of the safety checks we've built on top of
+   * PDO's transaction routines.
+   *
+   * @throws Drupal\Core\Database\TransactionExplicitCommitNotAllowedException
+   *
+   * @see Drupal\Core\Database\Transaction
+   */
+  public function commit() {
+    throw new TransactionExplicitCommitNotAllowedException();
+  }
+
+  /**
+   * Retrieves an unique id from a given sequence.
+   *
+   * Use this function if for some reason you can't use a serial field. For
+   * example, MySQL has no ways of reading of the current value of a sequence
+   * and PostgreSQL can not advance the sequence to be larger than a given
+   * value. Or sometimes you just need a unique integer.
+   *
+   * @param $existing_id
+   *   After a database import, it might be that the sequences table is behind,
+   *   so by passing in the maximum existing id, it can be assured that we
+   *   never issue the same id.
+   *
+   * @return
+   *   An integer number larger than any number returned by earlier calls and
+   *   also larger than the $existing_id if one was passed in.
+   */
+  abstract public function nextId($existing_id = 0);
+}
diff --git a/core/lib/Drupal/Core/Database/ConnectionNotDefinedException.php b/core/lib/Drupal/Core/Database/ConnectionNotDefinedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..d14535822fe3c0f4a033612c428ecdf8285eab63
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/ConnectionNotDefinedException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\ConnectionNotDefinedException
+ */
+
+namespace Drupal\Core\Database;
+
+use RuntimeException;
+
+/**
+ * Exception thrown if an undefined database connection is requested.
+ */
+class ConnectionNotDefinedException extends RuntimeException {}
diff --git a/core/lib/Drupal/Core/Database/Database.php b/core/lib/Drupal/Core/Database/Database.php
new file mode 100644
index 0000000000000000000000000000000000000000..298c0115ab6a7699ba1eb687dc65238cedf71aa3
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -0,0 +1,431 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Database
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Primary front-controller for the database system.
+ *
+ * This class is uninstantiatable and un-extendable. It acts to encapsulate
+ * all control and shepherding of database connections into a single location
+ * without the use of globals.
+ */
+abstract class Database {
+
+  /**
+   * Flag to indicate a query call should simply return NULL.
+   *
+   * This is used for queries that have no reasonable return value anyway, such
+   * as INSERT statements to a table without a serial primary key.
+   */
+  const RETURN_NULL = 0;
+
+  /**
+   * Flag to indicate a query call should return the prepared statement.
+   */
+  const RETURN_STATEMENT = 1;
+
+  /**
+   * Flag to indicate a query call should return the number of affected rows.
+   */
+  const RETURN_AFFECTED = 2;
+
+  /**
+   * Flag to indicate a query call should return the "last insert id".
+   */
+  const RETURN_INSERT_ID = 3;
+
+  /**
+   * An nested array of all active connections. It is keyed by database name
+   * and target.
+   *
+   * @var array
+   */
+  static protected $connections = array();
+
+  /**
+   * A processed copy of the database connection information from settings.php.
+   *
+   * @var array
+   */
+  static protected $databaseInfo = NULL;
+
+  /**
+   * A list of key/target credentials to simply ignore.
+   *
+   * @var array
+   */
+  static protected $ignoreTargets = array();
+
+  /**
+   * The key of the currently active database connection.
+   *
+   * @var string
+   */
+  static protected $activeKey = 'default';
+
+  /**
+   * An array of active query log objects.
+   *
+   * Every connection has one and only one logger object for all targets and
+   * logging keys.
+   *
+   * array(
+   *   '$db_key' => DatabaseLog object.
+   * );
+   *
+   * @var array
+   */
+  static protected $logs = array();
+
+  /**
+   * Starts logging a given logging key on the specified connection.
+   *
+   * @param $logging_key
+   *   The logging key to log.
+   * @param $key
+   *   The database connection key for which we want to log.
+   *
+   * @return Drupal\Core\Database\Log
+   *   The query log object. Note that the log object does support richer
+   *   methods than the few exposed through the Database class, so in some
+   *   cases it may be desirable to access it directly.
+   *
+   * @see Drupal\Core\Database\Log
+   */
+  final public static function startLog($logging_key, $key = 'default') {
+    if (empty(self::$logs[$key])) {
+      self::$logs[$key] = new Log($key);
+
+      // Every target already active for this connection key needs to have the
+      // logging object associated with it.
+      if (!empty(self::$connections[$key])) {
+        foreach (self::$connections[$key] as $connection) {
+          $connection->setLogger(self::$logs[$key]);
+        }
+      }
+    }
+
+    self::$logs[$key]->start($logging_key);
+    return self::$logs[$key];
+  }
+
+  /**
+   * Retrieves the queries logged on for given logging key.
+   *
+   * This method also ends logging for the specified key. To get the query log
+   * to date without ending the logger request the logging object by starting
+   * it again (which does nothing to an open log key) and call methods on it as
+   * desired.
+   *
+   * @param $logging_key
+   *   The logging key to log.
+   * @param $key
+   *   The database connection key for which we want to log.
+   *
+   * @return array
+   *   The query log for the specified logging key and connection.
+   *
+   * @see Drupal\Core\Database\Log
+   */
+  final public static function getLog($logging_key, $key = 'default') {
+    if (empty(self::$logs[$key])) {
+      return NULL;
+    }
+    $queries = self::$logs[$key]->get($logging_key);
+    self::$logs[$key]->end($logging_key);
+    return $queries;
+  }
+
+  /**
+   * Gets the connection object for the specified database key and target.
+   *
+   * @param $target
+   *   The database target name.
+   * @param $key
+   *   The database connection key. Defaults to NULL which means the active key.
+   *
+   * @return Drupal\Core\Database\Connection
+   *   The corresponding connection object.
+   */
+  final public static function getConnection($target = 'default', $key = NULL) {
+    if (!isset($key)) {
+      // By default, we want the active connection, set in setActiveConnection.
+      $key = self::$activeKey;
+    }
+    // If the requested target does not exist, or if it is ignored, we fall back
+    // to the default target. The target is typically either "default" or
+    // "slave", indicating to use a slave SQL server if one is available. If
+    // it's not available, then the default/master server is the correct server
+    // to use.
+    if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
+      $target = 'default';
+    }
+
+    if (!isset(self::$connections[$key][$target])) {
+      // If necessary, a new connection is opened.
+      self::$connections[$key][$target] = self::openConnection($key, $target);
+    }
+    return self::$connections[$key][$target];
+  }
+
+  /**
+   * Determines if there is an active connection.
+   *
+   * Note that this method will return FALSE if no connection has been
+   * established yet, even if one could be.
+   *
+   * @return
+   *   TRUE if there is at least one database connection established, FALSE
+   *   otherwise.
+   */
+  final public static function isActiveConnection() {
+    return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]);
+  }
+
+  /**
+   * Sets the active connection to the specified key.
+   *
+   * @return
+   *   The previous database connection key.
+   */
+  final public static function setActiveConnection($key = 'default') {
+    if (empty(self::$databaseInfo)) {
+      self::parseConnectionInfo();
+    }
+
+    if (!empty(self::$databaseInfo[$key])) {
+      $old_key = self::$activeKey;
+      self::$activeKey = $key;
+      return $old_key;
+    }
+  }
+
+  /**
+   * Process the configuration file for database information.
+   */
+  final public static function parseConnectionInfo() {
+    global $databases;
+
+    $database_info = is_array($databases) ? $databases : array();
+    foreach ($database_info as $index => $info) {
+      foreach ($database_info[$index] as $target => $value) {
+        // If there is no "driver" property, then we assume it's an array of
+        // possible connections for this target. Pick one at random. That allows
+        //  us to have, for example, multiple slave servers.
+        if (empty($value['driver'])) {
+          $database_info[$index][$target] = $database_info[$index][$target][mt_rand(0, count($database_info[$index][$target]) - 1)];
+        }
+
+        // Parse the prefix information.
+        if (!isset($database_info[$index][$target]['prefix'])) {
+          // Default to an empty prefix.
+          $database_info[$index][$target]['prefix'] = array(
+            'default' => '',
+          );
+        }
+        elseif (!is_array($database_info[$index][$target]['prefix'])) {
+          // Transform the flat form into an array form.
+          $database_info[$index][$target]['prefix'] = array(
+            'default' => $database_info[$index][$target]['prefix'],
+          );
+        }
+      }
+    }
+
+    if (!is_array(self::$databaseInfo)) {
+      self::$databaseInfo = $database_info;
+    }
+
+    // Merge the new $database_info into the existing.
+    // array_merge_recursive() cannot be used, as it would make multiple
+    // database, user, and password keys in the same database array.
+    else {
+      foreach ($database_info as $database_key => $database_values) {
+        foreach ($database_values as $target => $target_values) {
+          self::$databaseInfo[$database_key][$target] = $target_values;
+        }
+      }
+    }
+  }
+
+  /**
+   * Adds database connection information for a given key/target.
+   *
+   * This method allows the addition of new connection credentials at runtime.
+   * Under normal circumstances the preferred way to specify database
+   * credentials is via settings.php. However, this method allows them to be
+   * added at arbitrary times, such as during unit tests, when connecting to
+   * admin-defined third party databases, etc.
+   *
+   * If the given key/target pair already exists, this method will be ignored.
+   *
+   * @param $key
+   *   The database key.
+   * @param $target
+   *   The database target name.
+   * @param $info
+   *   The database connection information, as it would be defined in
+   *   settings.php. Note that the structure of this array will depend on the
+   *   database driver it is connecting to.
+   */
+  public static function addConnectionInfo($key, $target, $info) {
+    if (empty(self::$databaseInfo[$key][$target])) {
+      self::$databaseInfo[$key][$target] = $info;
+    }
+  }
+
+  /**
+   * Gets information on the specified database connection.
+   *
+   * @param $connection
+   *   The connection key for which we want information.
+   */
+  final public static function getConnectionInfo($key = 'default') {
+    if (empty(self::$databaseInfo)) {
+      self::parseConnectionInfo();
+    }
+
+    if (!empty(self::$databaseInfo[$key])) {
+      return self::$databaseInfo[$key];
+    }
+  }
+
+  /**
+   * Rename a connection and its corresponding connection information.
+   *
+   * @param $old_key
+   *   The old connection key.
+   * @param $new_key
+   *   The new connection key.
+   * @return
+   *   TRUE in case of success, FALSE otherwise.
+   */
+  final public static function renameConnection($old_key, $new_key) {
+    if (empty(self::$databaseInfo)) {
+      self::parseConnectionInfo();
+    }
+
+    if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
+      // Migrate the database connection information.
+      self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
+      unset(self::$databaseInfo[$old_key]);
+
+      // Migrate over the DatabaseConnection object if it exists.
+      if (isset(self::$connections[$old_key])) {
+        self::$connections[$new_key] = self::$connections[$old_key];
+        unset(self::$connections[$old_key]);
+      }
+
+      return TRUE;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Remove a connection and its corresponding connection information.
+   *
+   * @param $key
+   *   The connection key.
+   * @return
+   *   TRUE in case of success, FALSE otherwise.
+   */
+  final public static function removeConnection($key) {
+    if (isset(self::$databaseInfo[$key])) {
+      unset(self::$databaseInfo[$key]);
+      unset(self::$connections[$key]);
+      return TRUE;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Opens a connection to the server specified by the given key and target.
+   *
+   * @param $key
+   *   The database connection key, as specified in settings.php. The default is
+   *   "default".
+   * @param $target
+   *   The database target to open.
+   *
+   * @throws Drupal\Core\Database\ConnectionNotDefinedException
+   * @throws Drupal\Core\Database\DriverNotSpecifiedException
+   */
+  final protected static function openConnection($key, $target) {
+    if (empty(self::$databaseInfo)) {
+      self::parseConnectionInfo();
+    }
+
+    // If the requested database does not exist then it is an unrecoverable
+    // error.
+    if (!isset(self::$databaseInfo[$key])) {
+      throw new ConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
+    }
+
+    if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
+      throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
+    }
+
+    // We cannot rely on the registry yet, because the registry requires an
+    // open database connection.
+    $driver_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection";
+    $new_connection = new $driver_class(self::$databaseInfo[$key][$target]);
+    $new_connection->setTarget($target);
+    $new_connection->setKey($key);
+
+    // If we have any active logging objects for this connection key, we need
+    // to associate them with the connection we just opened.
+    if (!empty(self::$logs[$key])) {
+      $new_connection->setLogger(self::$logs[$key]);
+    }
+
+    return $new_connection;
+  }
+
+  /**
+   * Closes a connection to the server specified by the given key and target.
+   *
+   * @param $target
+   *   The database target name.  Defaults to NULL meaning that all target
+   *   connections will be closed.
+   * @param $key
+   *   The database connection key. Defaults to NULL which means the active key.
+   */
+  public static function closeConnection($target = NULL, $key = NULL) {
+    // Gets the active connection by default.
+    if (!isset($key)) {
+      $key = self::$activeKey;
+    }
+    // To close the connection, we need to unset the static variable.
+    if (isset($target)) {
+      unset(self::$connections[$key][$target]);
+    }
+    else {
+      unset(self::$connections[$key]);
+    }
+  }
+
+  /**
+   * Instructs the system to temporarily ignore a given key/target.
+   *
+   * At times we need to temporarily disable slave queries. To do so, call this
+   * method with the database key and the target to disable. That database key
+   * will then always fall back to 'default' for that key, even if it's defined.
+   *
+   * @param $key
+   *   The database connection key.
+   * @param $target
+   *   The target of the specified key to ignore.
+   */
+  public static function ignoreTarget($key, $target) {
+    self::$ignoreTargets[$key][$target] = TRUE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/DatabaseException.php b/core/lib/Drupal/Core/Database/DatabaseException.php
new file mode 100644
index 0000000000000000000000000000000000000000..019d656166664d5731f735e16f346a8a6c500b64
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/DatabaseException.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\DatabaseException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Interface for a database exception.
+ *
+ * All Database exceptions should implement this interface so that they can be
+ * caught collectively.  Note that this applies only to Drupal-spawned
+ * exceptions.  PDOException will not implement this interface and module
+ * developers should account for it separately.
+ */
+interface DatabaseException { }
+
diff --git a/core/includes/database/mysql/database.inc b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
similarity index 95%
rename from core/includes/database/mysql/database.inc
rename to core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
index e024a7f396829a5a63e68deeeeae526ecf76725b..3b62fa703a09b99f94f8bf510ebea33cbe9bbfe8 100644
--- a/core/includes/database/mysql/database.inc
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php
@@ -2,15 +2,24 @@
 
 /**
  * @file
- * Database interface code for MySQL database servers.
+ * Definition of Drupal\Core\Database\Driver\mysql\Connection
  */
 
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\TransactionCommitFailedException;
+use Drupal\Core\Database\Connection as DatabaseConnection;
+
+use PDO;
+use PDOException;
+
 /**
  * @ingroup database
  * @{
  */
 
-class DatabaseConnection_mysql extends DatabaseConnection {
+class Connection extends DatabaseConnection {
 
   /**
    * Flag to indicate if we have registered the nextID cleanup function.
@@ -165,7 +174,7 @@ protected function popCommittableTransactions() {
       unset($this->transactionLayers[$name]);
       if (empty($this->transactionLayers)) {
         if (!PDO::commit()) {
-          throw new DatabaseTransactionCommitFailedException();
+          throw new TransactionCommitFailedException();
         }
       }
       else {
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Delete.php b/core/lib/Drupal/Core/Database/Driver/mysql/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..de0db11ae586767b302769eba5969d5094baffb7
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Delete.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Delete
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Delete as QueryDelete;
+
+class Delete extends QueryDelete { }
diff --git a/core/includes/database/mysql/query.inc b/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
similarity index 76%
rename from core/includes/database/mysql/query.inc
rename to core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
index 888b6a5a450e613b172814e53b0f53f27e76cf69..233118c5aa28931d3ba351502d492f58b7ac701b 100644
--- a/core/includes/database/mysql/query.inc
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
@@ -1,17 +1,15 @@
 <?php
 
-/**
- * @ingroup database
- * @{
- */
-
 /**
  * @file
- * Query code for MySQL embedded database engine.
+ * Definition of Drupal\Core\Database\Driver\mysql\Insert
  */
 
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Insert as QueryInsert;
 
-class InsertQuery_mysql extends InsertQuery {
+class Insert extends QueryInsert {
 
   public function execute() {
     if (!$this->preExecute()) {
@@ -85,23 +83,3 @@ public function __toString() {
     return $query;
   }
 }
-
-class TruncateQuery_mysql extends TruncateQuery {
-  public function __toString() {
-    // TRUNCATE is actually a DDL statement on MySQL, and DDL statements are
-    // not transactional, and result in an implicit COMMIT. When we are in a
-    // transaction, fallback to the slower, but transactional, DELETE.
-    if ($this->connection->inTransaction()) {
-      // Create a comment string to prepend to the query.
-      $comments = $this->connection->makeComment($this->comments);
-      return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
-    }
-    else {
-      return parent::__toString();
-    }
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/mysql/install.inc b/core/lib/Drupal/Core/Database/Driver/mysql/Install/Tasks.php
similarity index 71%
rename from core/includes/database/mysql/install.inc
rename to core/lib/Drupal/Core/Database/Driver/mysql/Install/Tasks.php
index 75f2ae390504361204acf9bc9c8c4ceb476327b4..4835103de489adca72df34830f525ada49a1da11 100644
--- a/core/includes/database/mysql/install.inc
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Install/Tasks.php
@@ -2,13 +2,17 @@
 
 /**
  * @file
- * Installation code for MySQL embedded database engine.
+ * Definition of Drupal\Core\Database\Driver\mysql\Install\Tasks
  */
 
+namespace Drupal\Core\Database\Driver\mysql\Install;
+
+use Drupal\Core\Database\Install\Tasks as InstallTasks;
+
 /**
  * Specifies installation tasks for MySQL and equivalent databases.
  */
-class DatabaseTasks_mysql extends DatabaseTasks {
+class Tasks extends InstallTasks {
   /**
    * The PDO driver name for MySQL and equivalent databases.
    *
@@ -30,4 +34,3 @@ public function minimumVersion() {
     return '5.0.15';
   }
 }
-
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php b/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..c48b830a566592a6bc4f5e2898a13d18630d5616
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Merge
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Merge as QueryMerge;
+
+class Merge extends QueryMerge { }
diff --git a/core/includes/database/mysql/schema.inc b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
similarity index 85%
rename from core/includes/database/mysql/schema.inc
rename to core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
index 4e88fa169ebeb6dca90fdf66a55f6ffe10f3bc06..24c3b4a6b11ac9125df1e8c1dab57df603773b41 100644
--- a/core/includes/database/mysql/schema.inc
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -2,16 +2,25 @@
 
 /**
  * @file
- * Database schema code for MySQL database servers.
+ * Definition of Drupal\Core\Database\Driver\mysql\Schema
  */
 
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\SchemaObjectDoesNotExistException;
+use Drupal\Core\Database\Schema as DatabaseSchema;
+
+use Exception;
 
 /**
  * @ingroup schemaapi
  * @{
  */
 
-class DatabaseSchema_mysql extends DatabaseSchema {
+class Schema extends DatabaseSchema {
 
   /**
    * Maximum length of a table comment in MySQL.
@@ -59,7 +68,7 @@ protected function buildTableNameCondition($table_name, $operator = '=', $add_pr
 
     $table_info = $this->getPrefixInfo($table_name, $add_prefix);
 
-    $condition = new DatabaseCondition('AND');
+    $condition = new Condition('AND');
     $condition->condition('table_schema', $table_info['database']);
     $condition->condition('table_name', $table_info['table'], $operator);
     return $condition;
@@ -296,10 +305,10 @@ protected function createKeysSqlHelper($fields) {
 
   public function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
     }
 
     $info = $this->getPrefixInfo($new_name);
@@ -317,10 +326,10 @@ public function dropTable($table) {
 
   public function addField($table, $field, $spec, $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)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
     }
 
     $fixnull = FALSE;
@@ -356,7 +365,7 @@ public function dropField($table, $field) {
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     if (!isset($default)) {
@@ -371,7 +380,7 @@ public function fieldSetDefault($table, $field, $default) {
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
@@ -386,10 +395,10 @@ public function indexExists($table, $name) {
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
     }
     if ($this->indexExists($table, 'PRIMARY')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
@@ -406,10 +415,10 @@ public function dropPrimaryKey($table) {
 
   public function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
@@ -426,10 +435,10 @@ public function dropUniqueKey($table, $name) {
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
@@ -446,10 +455,10 @@ public function dropIndex($table, $name) {
 
   public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
+      throw new SchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
     }
 
     $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec));
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Select.php b/core/lib/Drupal/Core/Database/Driver/mysql/Select.php
new file mode 100644
index 0000000000000000000000000000000000000000..aecae55a2fbaa017be7289c1c328af52c1c3a0aa
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Select.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Select
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Select as QuerySelect;
+
+class Select extends QuerySelect { }
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Transaction.php b/core/lib/Drupal/Core/Database/Driver/mysql/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..570a1300f3b0a9ef096124b488eedcdda0e70f9f
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Transaction.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Transaction
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Transaction as DatabaseTransaction;
+
+class Transaction extends DatabaseTransaction { }
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Truncate.php b/core/lib/Drupal/Core/Database/Driver/mysql/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..d0adfad10f2b4f26dcb17fc96ef3d87fe784b3da
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Truncate.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Truncate
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Truncate as QueryTruncate;
+
+class Truncate extends QueryTruncate {
+  public function __toString() {
+    // TRUNCATE is actually a DDL statement on MySQL, and DDL statements are
+    // not transactional, and result in an implicit COMMIT. When we are in a
+    // transaction, fallback to the slower, but transactional, DELETE.
+    if ($this->connection->inTransaction()) {
+      // Create a comment string to prepend to the query.
+      $comments = $this->connection->makeComment($this->comments);
+      return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
+    }
+    else {
+      return parent::__toString();
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Update.php b/core/lib/Drupal/Core/Database/Driver/mysql/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b3bda68b74e3d46c5050d4c2e4412b5a2e037ae
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Update.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\mysql\Update
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Query\Update as QueryUpdate;
+
+class Update extends QueryUpdate { }
diff --git a/core/includes/database/pgsql/database.inc b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
similarity index 89%
rename from core/includes/database/pgsql/database.inc
rename to core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
index 68300e55368e4bfd742e397f8fa3311df4bc19fb..6903a141991d02d143e89f6589a60c73ed8ea731 100644
--- a/core/includes/database/pgsql/database.inc
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
@@ -2,20 +2,29 @@
 
 /**
  * @file
- * Database interface code for PostgreSQL database servers.
+ * Definition of Drupal\Core\Database\Driver\pgsql\Connection
  */
 
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection as DatabaseConnection;
+use Drupal\Core\Database\StatementInterface;
+
+use PDO;
+use PDOException;
+
 /**
  * @ingroup database
  * @{
  */
 
-/**
- * The name by which to obtain a lock for retrive the next insert id.
- */
-const POSTGRESQL_NEXTID_LOCK = 1000;
+class Connection extends DatabaseConnection {
 
-class DatabaseConnection_pgsql extends DatabaseConnection {
+  /**
+   * The name by which to obtain a lock for retrive the next insert id.
+   */
+  const POSTGRESQL_NEXTID_LOCK = 1000;
 
   public function __construct(array $connection_options = array()) {
     // This driver defaults to transaction support, except if explicitly passed FALSE.
@@ -92,7 +101,7 @@ public function query($query, array $args = array(), $options = array()) {
     }
 
     try {
-      if ($query instanceof DatabaseStatementInterface) {
+      if ($query instanceof StatementInterface) {
         $stmt = $query;
         $stmt->execute(NULL, $options);
       }
@@ -118,7 +127,7 @@ public function query($query, array $args = array(), $options = array()) {
     catch (PDOException $e) {
       if ($options['throw_exception']) {
         // Add additional debug information.
-        if ($query instanceof DatabaseStatementInterface) {
+        if ($query instanceof StatementInterface) {
           $e->query_string = $stmt->getQueryString();
         }
         else {
@@ -187,13 +196,13 @@ public function nextId($existing = 0) {
     // PostgreSQL advisory locks are simply locks to be used by an
     // application such as Drupal. This will prevent other Drupal proccesses
     // from altering the sequence while we are.
-    $this->query("SELECT pg_advisory_lock(" . POSTGRESQL_NEXTID_LOCK . ")");
+    $this->query("SELECT pg_advisory_lock(" . self::POSTGRESQL_NEXTID_LOCK . ")");
 
     // While waiting to obtain the lock, the sequence may have been altered
     // so lets try again to obtain an adequate value.
     $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
     if ($id > $existing) {
-      $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")");
+      $this->query("SELECT pg_advisory_unlock(" . self::POSTGRESQL_NEXTID_LOCK . ")");
       return $id;
     }
 
@@ -203,7 +212,7 @@ public function nextId($existing = 0) {
     // Retrive the next id. We know this will be as high as we want it.
     $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
 
-    $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")");
+    $this->query("SELECT pg_advisory_unlock(" . self::POSTGRESQL_NEXTID_LOCK . ")");
 
     return $id;
   }
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Delete.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..e9914ca97d9b94a6105368bb13f48f709d4838f0
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Delete.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Delete
+ */
+
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Query\Delete as QueryDelete;
+
+class Delete extends QueryDelete { }
diff --git a/core/includes/database/pgsql/query.inc b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
similarity index 71%
rename from core/includes/database/pgsql/query.inc
rename to core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
index f3783a9ca8f9ceb4f745c650fa826ee3271e1df4..dffa1fdcbacd8d24a0039adca0372d7b2a092b86 100644
--- a/core/includes/database/pgsql/query.inc
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
@@ -1,17 +1,23 @@
 <?php
 
 /**
- * @ingroup database
- * @{
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Insert
  */
 
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Insert as QueryInsert;
+
+use PDO;
+
 /**
- * @file
- * Query code for PostgreSQL embedded database engine.
+ * @ingroup database
+ * @{
  */
 
-
-class InsertQuery_pgsql extends InsertQuery {
+class Insert extends QueryInsert {
 
   public function execute() {
     if (!$this->preExecute()) {
@@ -146,64 +152,3 @@ public function __toString() {
     return $query;
   }
 }
-
-class UpdateQuery_pgsql extends UpdateQuery {
-  public function execute() {
-    $max_placeholder = 0;
-    $blobs = array();
-    $blob_count = 0;
-
-    // Because we filter $fields the same way here and in __toString(), the
-    // placeholders will all match up properly.
-    $stmt = $this->connection->prepareQuery((string) $this);
-
-    // Fetch the list of blobs and sequences used on that table.
-    $table_information = $this->connection->schema()->queryTableInformation($this->table);
-
-    // Expressions take priority over literal fields, so we process those first
-    // and remove any literal fields that conflict.
-    $fields = $this->fields;
-    $expression_fields = array();
-    foreach ($this->expressionFields as $field => $data) {
-      if (!empty($data['arguments'])) {
-        foreach ($data['arguments'] as $placeholder => $argument) {
-          // We assume that an expression will never happen on a BLOB field,
-          // which is a fairly safe assumption to make since in most cases
-          // it would be an invalid query anyway.
-          $stmt->bindParam($placeholder, $data['arguments'][$placeholder]);
-        }
-      }
-      unset($fields[$field]);
-    }
-
-    foreach ($fields as $field => $value) {
-      $placeholder = ':db_update_placeholder_' . ($max_placeholder++);
-
-      if (isset($table_information->blob_fields[$field])) {
-        $blobs[$blob_count] = fopen('php://memory', 'a');
-        fwrite($blobs[$blob_count], $value);
-        rewind($blobs[$blob_count]);
-        $stmt->bindParam($placeholder, $blobs[$blob_count], PDO::PARAM_LOB);
-        ++$blob_count;
-      }
-      else {
-        $stmt->bindParam($placeholder, $fields[$field]);
-      }
-    }
-
-    if (count($this->condition)) {
-      $this->condition->compile($this->connection, $this);
-
-      $arguments = $this->condition->arguments();
-      foreach ($arguments as $placeholder => $value) {
-        $stmt->bindParam($placeholder, $arguments[$placeholder]);
-      }
-    }
-
-    $options = $this->queryOptions;
-    $options['already_prepared'] = TRUE;
-    $this->connection->query($stmt, $options);
-
-    return $stmt->rowCount();
-  }
-}
diff --git a/core/includes/database/pgsql/install.inc b/core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
similarity index 95%
rename from core/includes/database/pgsql/install.inc
rename to core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
index c350634ec40058a19c7ae470f2d5c8a03bc71c4c..c3ddffb4b78a31e5cec9c6a997d675ae8ccd20d5 100644
--- a/core/includes/database/pgsql/install.inc
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Install/Tasks.php
@@ -2,13 +2,17 @@
 
 /**
  * @file
- * Install functions for PostgreSQL embedded database engine.
+ * Definition of Drupal\Core\Database\Driver\pgsql\Install\Tasks
  */
 
+namespace Drupal\Core\Database\Driver\pgsql\Install;
 
-// PostgreSQL specific install functions
+use Drupal\Core\Database\Install\Tasks as InstallTasks;
 
-class DatabaseTasks_pgsql extends DatabaseTasks {
+/**
+ * PostgreSQL specific install functions
+ */
+class Tasks extends InstallTasks {
   protected $pdoDriver = 'pgsql';
 
   public function __construct() {
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Merge.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..c3a2ae0938b837400df9f3e123ea9aa5a12f3593
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Merge.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Merge
+ */
+
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Query\Merge as QueryMerge;
+
+class Merge extends QueryMerge { }
diff --git a/core/includes/database/pgsql/schema.inc b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
similarity index 88%
rename from core/includes/database/pgsql/schema.inc
rename to core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
index 49adbf9077627e33fa354b7521cd642c4db9c8ef..7206e178dba0a37da6b061eb94064c6e84d79484 100644
--- a/core/includes/database/pgsql/schema.inc
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
@@ -2,15 +2,25 @@
 
 /**
  * @file
- * Database schema code for PostgreSQL database servers.
+ * Definition of Drupal\Core\Database\Driver\pgsql\Schema
  */
 
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\SchemaObjectDoesNotExistException;
+use Drupal\Core\Database\Schema as DatabaseSchema;
+
+use Exception;
+
 /**
  * @ingroup schemaapi
  * @{
  */
 
-class DatabaseSchema_pgsql extends DatabaseSchema {
+class Schema extends DatabaseSchema {
 
   /**
    * A cache of information about blob columns and sequences of tables.
@@ -314,10 +324,10 @@ protected function _createKeySql($fields) {
 
   function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
     }
 
     // Get the schema and tablename for the old table.
@@ -351,10 +361,10 @@ public function dropTable($table) {
 
   public function addField($table, $field, $spec, $new_keys = array()) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
     }
 
     $fixnull = FALSE;
@@ -393,7 +403,7 @@ public function dropField($table, $field) {
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     if (!isset($default)) {
@@ -408,7 +418,7 @@ public function fieldSetDefault($table, $field, $default) {
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
@@ -435,10 +445,10 @@ protected function constraintExists($table, $name) {
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
     }
     if ($this->constraintExists($table, 'pkey')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')');
@@ -455,10 +465,10 @@ public function dropPrimaryKey($table) {
 
   function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->constraintExists($table, $name . '_key')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
@@ -475,10 +485,10 @@ public function dropUniqueKey($table, $name) {
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $this->connection->query($this->_createIndexSql($table, $name, $fields));
@@ -495,10 +505,10 @@ public function dropIndex($table, $name) {
 
   public function changeField($table, $field, $field_new, $spec, $new_keys = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
+      throw new SchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
     }
 
     $spec = $this->processField($spec);
@@ -615,3 +625,7 @@ public function getComment($table, $column = NULL) {
     }
   }
 }
+
+/**
+ * @} End of "ingroup database".
+ */
diff --git a/core/includes/database/pgsql/select.inc b/core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
similarity index 94%
rename from core/includes/database/pgsql/select.inc
rename to core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
index d1d83828118d9bbbd3de7cfedd506a8b862fedd8..a9226b26dbcfb7416546685c221c402e9a297a39 100644
--- a/core/includes/database/pgsql/select.inc
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
@@ -2,15 +2,19 @@
 
 /**
  * @file
- * Select builder for PostgreSQL database engine.
+ * Definition of Drupal\Core\Database\Driver\pgsql\Select
  */
 
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Query\Select as QuerySelect;
+
 /**
  * @ingroup database
  * @{
  */
 
-class SelectQuery_pgsql extends SelectQuery {
+class Select extends QuerySelect {
 
   public function orderRandom() {
     $alias = $this->addExpression('RANDOM()', 'random_field');
@@ -105,4 +109,3 @@ public function orderBy($field, $direction = 'ASC') {
 /**
  * @} End of "ingroup database".
  */
-
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Transaction.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..028672243569869a610df096e9d0a7b6da1a1f15
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Transaction.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Transaction
+ */
+
+namespace Drupal\Core\Database\Driver\mysql;
+
+use Drupal\Core\Database\Transaction as DatabaseTransaction;
+
+class Transaction extends DatabaseTransaction { }
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Truncate.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..e2fa83dac7c40f2ec6de932847de8301e78ab3fd
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Truncate.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Truncate
+ */
+
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Query\Truncate as QueryTruncate;
+
+class Truncate extends QueryTruncate { }
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..de738bfda996cf0a1db53f8e2e99d7e8488ecdc1
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Update.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\pgsql\Update
+ */
+
+namespace Drupal\Core\Database\Driver\pgsql;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Update as QueryUpdate;
+
+use PDO;
+
+class Update extends QueryUpdate {
+
+  public function execute() {
+    $max_placeholder = 0;
+    $blobs = array();
+    $blob_count = 0;
+
+    // Because we filter $fields the same way here and in __toString(), the
+    // placeholders will all match up properly.
+    $stmt = $this->connection->prepareQuery((string) $this);
+
+    // Fetch the list of blobs and sequences used on that table.
+    $table_information = $this->connection->schema()->queryTableInformation($this->table);
+
+    // Expressions take priority over literal fields, so we process those first
+    // and remove any literal fields that conflict.
+    $fields = $this->fields;
+    $expression_fields = array();
+    foreach ($this->expressionFields as $field => $data) {
+      if (!empty($data['arguments'])) {
+        foreach ($data['arguments'] as $placeholder => $argument) {
+          // We assume that an expression will never happen on a BLOB field,
+          // which is a fairly safe assumption to make since in most cases
+          // it would be an invalid query anyway.
+          $stmt->bindParam($placeholder, $data['arguments'][$placeholder]);
+        }
+      }
+      unset($fields[$field]);
+    }
+
+    foreach ($fields as $field => $value) {
+      $placeholder = ':db_update_placeholder_' . ($max_placeholder++);
+
+      if (isset($table_information->blob_fields[$field])) {
+        $blobs[$blob_count] = fopen('php://memory', 'a');
+        fwrite($blobs[$blob_count], $value);
+        rewind($blobs[$blob_count]);
+        $stmt->bindParam($placeholder, $blobs[$blob_count], PDO::PARAM_LOB);
+        ++$blob_count;
+      }
+      else {
+        $stmt->bindParam($placeholder, $fields[$field]);
+      }
+    }
+
+    if (count($this->condition)) {
+      $this->condition->compile($this->connection, $this);
+
+      $arguments = $this->condition->arguments();
+      foreach ($arguments as $placeholder => $value) {
+        $stmt->bindParam($placeholder, $arguments[$placeholder]);
+      }
+    }
+
+    $options = $this->queryOptions;
+    $options['already_prepared'] = TRUE;
+    $this->connection->query($stmt, $options);
+
+    return $stmt->rowCount();
+  }
+}
diff --git a/core/includes/database/sqlite/database.inc b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
similarity index 67%
rename from core/includes/database/sqlite/database.inc
rename to core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
index 5de219e8d79841d5a359316542645d5f0fffa28a..1587a632dd0812e27e694a503ae9956ffaff3cd4 100644
--- a/core/includes/database/sqlite/database.inc
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
@@ -2,20 +2,25 @@
 
 /**
  * @file
- * Database interface code for SQLite embedded database engine.
+ * Definition of Drupal\Core\Database\Driver\sqlite\Connection
  */
 
-/**
- * @ingroup database
- * @{
- */
+namespace Drupal\Core\Database\Driver\sqlite;
 
-include_once DRUPAL_ROOT . '/core/includes/database/prefetch.inc';
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\TransactionNoActiveException;
+use Drupal\Core\Database\TransactionNameNonUniqueException;
+use Drupal\Core\Database\TransactionCommitFailedException;
+use Drupal\Core\Database\Driver\sqlite\Statement;
+use Drupal\Core\Database\Connection as DatabaseConnection;
+
+use PDO;
+use Exception;
 
 /**
  * Specific SQLite implementation of DatabaseConnection.
  */
-class DatabaseConnection_sqlite extends DatabaseConnection {
+class Connection extends DatabaseConnection {
 
   /**
    * Whether this database connection supports savepoints.
@@ -37,7 +42,7 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
   /**
    * All databases attached to the current database. This is used to allow
    * prefixes to be safely handled without locking the table
-   * 
+   *
    * @var array
    */
   protected $attachedDatabases = array();
@@ -46,10 +51,10 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
    * Whether or not a table has been dropped this request: the destructor will
    * only try to get rid of unnecessary databases if there is potential of them
    * being empty.
-   * 
-   * This variable is set to public because DatabaseSchema_sqlite needs to
+   *
+   * This variable is set to public because Schema needs to
    * access it. However, it should not be manually set.
-   * 
+   *
    * @var boolean
    */
   var $tableDropped = FALSE;
@@ -217,11 +222,11 @@ public function sqlFunctionRand($seed = NULL) {
    * SQLite-specific implementation of DatabaseConnection::prepare().
    *
    * We don't use prepared statements at all at this stage. We just create
-   * a DatabaseStatement_sqlite object, that will create a PDOStatement
+   * a Statement object, that will create a PDOStatement
    * using the semi-private PDOPrepare() method below.
    */
   public function prepare($query, $options = array()) {
-    return new DatabaseStatement_sqlite($this, $query, $options);
+    return new Statement($this, $query, $options);
   }
 
   /**
@@ -232,9 +237,9 @@ public function prepare($query, $options = array()) {
    * destructor is called and SQLite does not allow data change (INSERT,
    * UPDATE etc) on a table which has open SELECT statements, you should never
    * call this function and keep a PDOStatement object alive as that can lead
-   * to a deadlock. This really, really should be private, but as
-   * DatabaseStatement_sqlite needs to call it, we have no other choice but to
-   * expose this function to the world.
+   * to a deadlock. This really, really should be private, but as Statement
+   * needs to call it, we have no other choice but to expose this function to
+   * the world.
    */
   public function PDOPrepare($query, array $options = array()) {
     return parent::prepare($query, $options);
@@ -304,7 +309,7 @@ public function rollback($savepoint_name = 'drupal_transaction') {
     }
 
     if (!$this->inTransaction()) {
-      throw new DatabaseTransactionNoActiveException();
+      throw new TransactionNoActiveException();
     }
     // A previous rollback to an earlier savepoint may mean that the savepoint
     // in question has already been rolled back.
@@ -340,7 +345,7 @@ public function pushTransaction($name) {
       return;
     }
     if (isset($this->transactionLayers[$name])) {
-      throw new DatabaseTransactionNameNonUniqueException($name . " is already in use.");
+      throw new TransactionNameNonUniqueException($name . " is already in use.");
     }
     if (!$this->inTransaction()) {
       PDO::beginTransaction();
@@ -356,7 +361,7 @@ public function popTransaction($name) {
       return;
     }
     if (!$this->inTransaction()) {
-      throw new DatabaseTransactionNoActiveException();
+      throw new TransactionNoActiveException();
     }
 
     // Commit everything since SAVEPOINT $name.
@@ -371,7 +376,7 @@ public function popTransaction($name) {
           PDO::rollBack();
         }
         elseif (!PDO::commit()) {
-          throw new DatabaseTransactionCommitFailedException();
+          throw new TransactionCommitFailedException();
         }
       }
       else {
@@ -381,141 +386,3 @@ public function popTransaction($name) {
   }
 
 }
-
-/**
- * Specific SQLite implementation of DatabaseConnection.
- *
- * See DatabaseConnection_sqlite::PDOPrepare() for reasons why we must prefetch
- * the data instead of using PDOStatement.
- *
- * @see DatabaseConnection_sqlite::PDOPrepare()
- */
-class DatabaseStatement_sqlite extends DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface {
-
-  /**
-   * SQLite specific implementation of getStatement().
-   *
-   * The PDO SQLite layer doesn't replace numeric placeholders in queries
-   * correctly, and this makes numeric expressions (such as COUNT(*) >= :count)
-   * fail. We replace numeric placeholders in the query ourselves to work
-   * around this bug.
-   *
-   * See http://bugs.php.net/bug.php?id=45259 for more details.
-   */
-  protected function getStatement($query, &$args = array()) {
-    if (count($args)) {
-      // Check if $args is a simple numeric array.
-      if (range(0, count($args) - 1) === array_keys($args)) {
-        // In that case, we have unnamed placeholders.
-        $count = 0;
-        $new_args = array();
-        foreach ($args as $value) {
-          if (is_float($value) || is_int($value)) {
-            if (is_float($value)) {
-              // Force the conversion to float so as not to loose precision
-              // in the automatic cast.
-              $value = sprintf('%F', $value);
-            }
-            $query = substr_replace($query, $value, strpos($query, '?'), 1);
-          }
-          else {
-            $placeholder = ':db_statement_placeholder_' . $count++;
-            $query = substr_replace($query, $placeholder, strpos($query, '?'), 1);
-            $new_args[$placeholder] = $value;
-          }
-        }
-        $args = $new_args;
-      }
-      else {
-        // Else, this is using named placeholders.
-        foreach ($args as $placeholder => $value) {
-          if (is_float($value) || is_int($value)) {
-            if (is_float($value)) {
-              // Force the conversion to float so as not to loose precision
-              // in the automatic cast.
-              $value = sprintf('%F', $value);
-            }
-
-            // We will remove this placeholder from the query as PDO throws an
-            // exception if the number of placeholders in the query and the
-            // arguments does not match.
-            unset($args[$placeholder]);
-            // PDO allows placeholders to not be prefixed by a colon. See
-            // http://marc.info/?l=php-internals&m=111234321827149&w=2 for
-            // more.
-            if ($placeholder[0] != ':') {
-              $placeholder = ":$placeholder";
-            }
-            // When replacing the placeholders, make sure we search for the
-            // exact placeholder. For example, if searching for
-            // ':db_placeholder_1', do not replace ':db_placeholder_11'.
-            $query = preg_replace('/' . preg_quote($placeholder) . '\b/', $value, $query);
-          }
-        }
-      }
-    }
-
-    return $this->dbh->PDOPrepare($query);
-  }
-
-  public function execute($args = array(), $options = array()) {
-    try {
-      $return = parent::execute($args, $options);
-    }
-    catch (PDOException $e) {
-      if (!empty($e->errorInfo[1]) && $e->errorInfo[1] === 17) {
-        // The schema has changed. SQLite specifies that we must resend the query.
-        $return = parent::execute($args, $options);
-      }
-      else {
-        // Rethrow the exception.
-        throw $e;
-      }
-    }
-
-    // In some weird cases, SQLite will prefix some column names by the name
-    // of the table. We post-process the data, by renaming the column names
-    // using the same convention as MySQL and PostgreSQL.
-    $rename_columns = array();
-    foreach ($this->columnNames as $k => $column) {
-      // In some SQLite versions, SELECT DISTINCT(field) will return "(field)"
-      // instead of "field".
-      if (preg_match("/^\((.*)\)$/", $column, $matches)) {
-        $rename_columns[$column] = $matches[1];
-        $this->columnNames[$k] = $matches[1];
-        $column = $matches[1];
-      }
-
-      // Remove "table." prefixes.
-      if (preg_match("/^.*\.(.*)$/", $column, $matches)) {
-        $rename_columns[$column] = $matches[1];
-        $this->columnNames[$k] = $matches[1];
-      }
-    }
-    if ($rename_columns) {
-      // DatabaseStatementPrefetch already extracted the first row,
-      // put it back into the result set.
-      if (isset($this->currentRow)) {
-        $this->data[0] = &$this->currentRow;
-      }
-
-      // Then rename all the columns across the result set.
-      foreach ($this->data as $k => $row) {
-        foreach ($rename_columns as $old_column => $new_column) {
-          $this->data[$k][$new_column] = $this->data[$k][$old_column];
-          unset($this->data[$k][$old_column]);
-        }
-      }
-
-      // Finally, extract the first row again.
-      $this->currentRow = $this->data[0];
-      unset($this->data[0]);
-    }
-
-    return $return;
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Delete.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..c0056cbe3816a78843c491c1ac04cabf0796566e
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Delete.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Delete
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Delete as QueryDelete;
+
+/**
+ * SQLite specific implementation of DeleteQuery.
+ *
+ * When the WHERE is omitted from a DELETE statement and the table being deleted
+ * has no triggers, SQLite uses an optimization to erase the entire table content
+ * without having to visit each row of the table individually.
+ *
+ * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
+ * by that optimized "truncate" optimization.
+ */
+class Delete extends QueryDelete {
+  public function execute() {
+    if (!count($this->condition)) {
+      $total_rows = $this->connection->query('SELECT COUNT(*) FROM {' . $this->connection->escapeTable($this->table) . '}')->fetchField();
+      parent::execute();
+      return $total_rows;
+    }
+    else {
+      return parent::execute();
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php
new file mode 100644
index 0000000000000000000000000000000000000000..e584943430bcd65e70dafb954f4322781869c058
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Insert
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Insert as QueryInsert;
+
+/**
+ * SQLite specific implementation of InsertQuery.
+ *
+ * We ignore all the default fields and use the clever SQLite syntax:
+ *   INSERT INTO table DEFAULT VALUES
+ * for degenerated "default only" queries.
+ */
+class Insert extends QueryInsert {
+
+  public function execute() {
+    if (!$this->preExecute()) {
+      return NULL;
+    }
+    if (count($this->insertFields)) {
+      return parent::execute();
+    }
+    else {
+      return $this->connection->query('INSERT INTO {' . $this->table . '} DEFAULT VALUES', array(), $this->queryOptions);
+    }
+  }
+
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    // Produce as many generic placeholders as necessary.
+    $placeholders = array_fill(0, count($this->insertFields), '?');
+
+    // If we're selecting from a SelectQuery, finish building the query and
+    // pass it back, as any remaining options are irrelevant.
+    if (!empty($this->fromQuery)) {
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
+    }
+
+    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
+  }
+
+}
\ No newline at end of file
diff --git a/core/includes/database/sqlite/install.inc b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
similarity index 87%
rename from core/includes/database/sqlite/install.inc
rename to core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
index 62cbac381f17c5cad67688540e0ff9a58905caf2..8866ef22a53d1c38ce6b0c7241b0784e1d69aae4 100644
--- a/core/includes/database/sqlite/install.inc
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Install/Tasks.php
@@ -2,10 +2,16 @@
 
 /**
  * @file
- * SQLite specific install functions
+ * Definition of Drupal\Core\Database\Driver\sqlite\Install\Tasks
  */
 
-class DatabaseTasks_sqlite extends DatabaseTasks {
+namespace Drupal\Core\Database\Driver\sqlite\Install;
+
+use Drupal\Core\Database\Install\Tasks as InstallTasks;
+
+use SplFileInfo;
+
+class Tasks extends InstallTasks {
   protected $pdoDriver = 'sqlite';
 
   public function name() {
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Merge.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..3bbc3de8c176ac1d11dd43dfcfccb3f10a9aa266
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Merge.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Merge
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Merge as QueryMerge;
+
+class Merge extends QueryMerge { }
diff --git a/core/includes/database/sqlite/schema.inc b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
similarity index 88%
rename from core/includes/database/sqlite/schema.inc
rename to core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
index c5882f12715d9c31933961c94b4f009ed773cccd..823cd137a166ef298786a083b817db8fd3290795 100644
--- a/core/includes/database/sqlite/schema.inc
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php
@@ -2,16 +2,24 @@
 
 /**
  * @file
- * Database schema code for SQLite databases.
+ * Definition of Drupal\Core\Database\Driver\sqlite\Schema
  */
 
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\SchemaObjectDoesNotExistException;
+use Drupal\Core\Database\Schema as DatabaseSchema;
+
+use Exception;
+
 
 /**
  * @ingroup schemaapi
  * @{
  */
 
-class DatabaseSchema_sqlite extends DatabaseSchema {
+class Schema extends DatabaseSchema {
 
   /**
    * Override DatabaseSchema::$defaultSchema
@@ -232,10 +240,10 @@ public function getFieldTypeMap() {
 
   public function renameTable($table, $new_name) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
     }
     if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+      throw new SchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
     }
 
     $schema = $this->introspectSchema($table);
@@ -278,10 +286,10 @@ public function dropTable($table) {
 
   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)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
     }
     if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
     }
 
     // SQLite doesn't have a full-featured ALTER TABLE statement. It only
@@ -494,10 +502,10 @@ public function dropField($table, $field) {
 
   public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
     }
     if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
+      throw new SchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
     }
 
     $old_schema = $this->introspectSchema($table);
@@ -559,10 +567,10 @@ protected function mapKeyDefinition(array $key_definition, array $mapping) {
 
   public function addIndex($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $schema['indexes'][$name] = $fields;
@@ -591,10 +599,10 @@ public function dropIndex($table, $name) {
 
   public function addUniqueKey($table, $name, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
     }
     if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+      throw new SchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
     }
 
     $schema['unique keys'][$name] = $fields;
@@ -617,14 +625,14 @@ public function dropUniqueKey($table, $name) {
 
   public function addPrimaryKey($table, $fields) {
     if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
     }
 
     $old_schema = $this->introspectSchema($table);
     $new_schema = $old_schema;
 
     if (!empty($new_schema['primary key'])) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+      throw new SchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
     }
 
     $new_schema['primary key'] = $fields;
@@ -646,7 +654,7 @@ public function dropPrimaryKey($table) {
 
   public function fieldSetDefault($table, $field, $default) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     $old_schema = $this->introspectSchema($table);
@@ -658,7 +666,7 @@ public function fieldSetDefault($table, $field, $default) {
 
   public function fieldSetNoDefault($table, $field) {
     if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+      throw new SchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
     $old_schema = $this->introspectSchema($table);
@@ -680,4 +688,4 @@ public function findTables($table_expression) {
     ));
     return $result->fetchAllKeyed(0, 0);
   }
-}
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Select.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
new file mode 100644
index 0000000000000000000000000000000000000000..5403611003c94908fd8d866717b0caea9e47ff59
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Select
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Select as QuerySelect;
+
+class Select extends QuerySelect {
+  public function forUpdate($set = TRUE) {
+    // SQLite does not support FOR UPDATE so nothing to do.
+    return $this;
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php
new file mode 100644
index 0000000000000000000000000000000000000000..531b6d08b249732fb0b40db064198b5a22a27e54
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php
@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Statement
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\StatementPrefetch;
+use Drupal\Core\Database\StatementInterface;
+
+use Iterator;
+use PDOException;
+
+/**
+ * Specific SQLite implementation of DatabaseConnection.
+ *
+ * See DatabaseConnection_sqlite::PDOPrepare() for reasons why we must prefetch
+ * the data instead of using PDOStatement.
+ *
+ * @see DatabaseConnection_sqlite::PDOPrepare()
+ */
+class Statement extends StatementPrefetch implements Iterator, StatementInterface {
+
+  /**
+   * SQLite specific implementation of getStatement().
+   *
+   * The PDO SQLite layer doesn't replace numeric placeholders in queries
+   * correctly, and this makes numeric expressions (such as COUNT(*) >= :count)
+   * fail. We replace numeric placeholders in the query ourselves to work
+   * around this bug.
+   *
+   * See http://bugs.php.net/bug.php?id=45259 for more details.
+   */
+  protected function getStatement($query, &$args = array()) {
+    if (count($args)) {
+      // Check if $args is a simple numeric array.
+      if (range(0, count($args) - 1) === array_keys($args)) {
+        // In that case, we have unnamed placeholders.
+        $count = 0;
+        $new_args = array();
+        foreach ($args as $value) {
+          if (is_float($value) || is_int($value)) {
+            if (is_float($value)) {
+              // Force the conversion to float so as not to loose precision
+              // in the automatic cast.
+              $value = sprintf('%F', $value);
+            }
+            $query = substr_replace($query, $value, strpos($query, '?'), 1);
+          }
+          else {
+            $placeholder = ':db_statement_placeholder_' . $count++;
+            $query = substr_replace($query, $placeholder, strpos($query, '?'), 1);
+            $new_args[$placeholder] = $value;
+          }
+        }
+        $args = $new_args;
+      }
+      else {
+        // Else, this is using named placeholders.
+        foreach ($args as $placeholder => $value) {
+          if (is_float($value) || is_int($value)) {
+            if (is_float($value)) {
+              // Force the conversion to float so as not to loose precision
+              // in the automatic cast.
+              $value = sprintf('%F', $value);
+            }
+
+            // We will remove this placeholder from the query as PDO throws an
+            // exception if the number of placeholders in the query and the
+            // arguments does not match.
+            unset($args[$placeholder]);
+            // PDO allows placeholders to not be prefixed by a colon. See
+            // http://marc.info/?l=php-internals&m=111234321827149&w=2 for
+            // more.
+            if ($placeholder[0] != ':') {
+              $placeholder = ":$placeholder";
+            }
+            // When replacing the placeholders, make sure we search for the
+            // exact placeholder. For example, if searching for
+            // ':db_placeholder_1', do not replace ':db_placeholder_11'.
+            $query = preg_replace('/' . preg_quote($placeholder) . '\b/', $value, $query);
+          }
+        }
+      }
+    }
+
+    return $this->dbh->PDOPrepare($query);
+  }
+
+  public function execute($args = array(), $options = array()) {
+    try {
+      $return = parent::execute($args, $options);
+    }
+    catch (PDOException $e) {
+      if (!empty($e->errorInfo[1]) && $e->errorInfo[1] === 17) {
+        // The schema has changed. SQLite specifies that we must resend the query.
+        $return = parent::execute($args, $options);
+      }
+      else {
+        // Rethrow the exception.
+        throw $e;
+      }
+    }
+
+    // In some weird cases, SQLite will prefix some column names by the name
+    // of the table. We post-process the data, by renaming the column names
+    // using the same convention as MySQL and PostgreSQL.
+    $rename_columns = array();
+    foreach ($this->columnNames as $k => $column) {
+      // In some SQLite versions, SELECT DISTINCT(field) will return "(field)"
+      // instead of "field".
+      if (preg_match("/^\((.*)\)$/", $column, $matches)) {
+        $rename_columns[$column] = $matches[1];
+        $this->columnNames[$k] = $matches[1];
+        $column = $matches[1];
+      }
+
+      // Remove "table." prefixes.
+      if (preg_match("/^.*\.(.*)$/", $column, $matches)) {
+        $rename_columns[$column] = $matches[1];
+        $this->columnNames[$k] = $matches[1];
+      }
+    }
+    if ($rename_columns) {
+      // DatabaseStatementPrefetch already extracted the first row,
+      // put it back into the result set.
+      if (isset($this->currentRow)) {
+        $this->data[0] = &$this->currentRow;
+      }
+
+      // Then rename all the columns across the result set.
+      foreach ($this->data as $k => $row) {
+        foreach ($rename_columns as $old_column => $new_column) {
+          $this->data[$k][$new_column] = $this->data[$k][$old_column];
+          unset($this->data[$k][$old_column]);
+        }
+      }
+
+      // Finally, extract the first row again.
+      $this->currentRow = $this->data[0];
+      unset($this->data[0]);
+    }
+
+    return $return;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Transaction.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae73ed8c98799984a4878bd53d56ef770f17fcda
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Transaction.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Transaction
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Transaction as DatabaseTransaction;
+
+class Transaction extends DatabaseTransaction { }
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Truncate.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc635404447f94f1e880f09265e27797f35f05ff
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Truncate.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Truncate
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Truncate as QueryTruncate;
+
+/**
+ * SQLite specific implementation of TruncateQuery.
+ *
+ * SQLite doesn't support TRUNCATE, but a DELETE query with no condition has
+ * exactly the effect (it is implemented by DROPing the table).
+ */
+class Truncate extends QueryTruncate {
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Update.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..18332e7d5578eddf430da2a57604d34583c050e0
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Update.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Driver\sqlite\Update
+ */
+
+namespace Drupal\Core\Database\Driver\sqlite;
+
+use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Database\Query\ConditionInterface;
+use Drupal\Core\Database\Query\Update as QueryUpdate;
+
+/**
+ * SQLite specific implementation of UpdateQuery.
+ *
+ * SQLite counts all the rows that match the conditions as modified, even if they
+ * will not be affected by the query. We workaround this by ensuring that
+ * we don't select those rows.
+ *
+ * A query like this one:
+ *   UPDATE test SET name = 'newname' WHERE tid = 1
+ * will become:
+ *   UPDATE test SET name = 'newname' WHERE tid = 1 AND name <> 'newname'
+ */
+class Update extends QueryUpdate {
+  /**
+   * Helper function that removes the fields that are already in a condition.
+   *
+   * @param $fields
+   *   The fields.
+   * @param QueryConditionInterface $condition
+   *   A database condition.
+   */
+  protected function removeFieldsInCondition(&$fields, ConditionInterface $condition) {
+    foreach ($condition->conditions() as $child_condition) {
+      if ($child_condition['field'] instanceof ConditionInterface) {
+        $this->removeFieldsInCondition($fields, $child_condition['field']);
+      }
+      else {
+        unset($fields[$child_condition['field']]);
+      }
+    }
+  }
+
+  public function execute() {
+    if (!empty($this->queryOptions['sqlite_return_matched_rows'])) {
+      return parent::execute();
+    }
+
+    // Get the fields used in the update query, and remove those that are already
+    // in the condition.
+    $fields = $this->expressionFields + $this->fields;
+    $this->removeFieldsInCondition($fields, $this->condition);
+
+    // Add the inverse of the fields to the condition.
+    $condition = new Condition('OR');
+    foreach ($fields as $field => $data) {
+      if (is_array($data)) {
+        // The field is an expression.
+        $condition->where($field . ' <> ' . $data['expression']);
+        $condition->isNull($field);
+      }
+      elseif (!isset($data)) {
+        // The field will be set to NULL.
+        $condition->isNotNull($field);
+      }
+      else {
+        $condition->condition($field, $data, '<>');
+        $condition->isNull($field);
+      }
+    }
+    if (count($condition)) {
+      $condition->compile($this->connection, $this);
+      $this->condition->where((string) $condition, $condition->arguments());
+    }
+    return parent::execute();
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Database/DriverNotSpecifiedException.php b/core/lib/Drupal/Core/Database/DriverNotSpecifiedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..946393142cc09e2c06ff2c95b466474728905f4e
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/DriverNotSpecifiedException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\DriverNotSpecifiedException
+ */
+
+namespace Drupal\Core\Database;
+
+use RuntimeException;
+
+/**
+ * Exception thrown if no driver is specified for a database connection.
+ */
+class DriverNotSpecifiedException extends RuntimeException {}
diff --git a/core/lib/Drupal/Core/Database/Install/TaskException.php b/core/lib/Drupal/Core/Database/Install/TaskException.php
new file mode 100644
index 0000000000000000000000000000000000000000..d93b736c00210ea914cbdc2489cfdef0fba28e16
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Install/TaskException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Install\TaskException
+ */
+
+namespace Drupal\Core\Database\Install;
+
+use RuntimeException;
+
+/**
+ * Exception thrown if the database installer fails.
+ */
+class TaskException extends RuntimeException { }
diff --git a/core/lib/Drupal/Core/Database/Install/Tasks.php b/core/lib/Drupal/Core/Database/Install/Tasks.php
new file mode 100644
index 0000000000000000000000000000000000000000..ece3c7c251931d458802fbd340da2275fb1ce837
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
@@ -0,0 +1,305 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Install\Tasks
+ */
+
+namespace Drupal\Core\Database\Install;
+
+use Drupal\Core\Database\Database;
+
+use PDO;
+
+/**
+ * Database installer structure.
+ *
+ * Defines basic Drupal requirements for databases.
+ */
+abstract class Tasks {
+
+  /**
+   * Structure that describes each task to run.
+   *
+   * @var array
+   *
+   * Each value of the tasks array is an associative array defining the function
+   * to call (optional) and any arguments to be passed to the function.
+   */
+  protected $tasks = array(
+    array(
+      'function'    => 'checkEngineVersion',
+      'arguments'   => array(),
+    ),
+    array(
+      'arguments'   => array(
+        'CREATE TABLE {drupal_install_test} (id int NULL)',
+        'Drupal can use CREATE TABLE database commands.',
+        'Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>',
+        TRUE,
+      ),
+    ),
+    array(
+      'arguments'   => array(
+        'INSERT INTO {drupal_install_test} (id) VALUES (1)',
+        'Drupal can use INSERT database commands.',
+        'Failed to <strong>INSERT</strong> a value into a test table on your database server. We tried inserting a value with the command %query and the server reported the following error: %error.',
+      ),
+    ),
+    array(
+      'arguments'   => array(
+        'UPDATE {drupal_install_test} SET id = 2',
+        'Drupal can use UPDATE database commands.',
+        'Failed to <strong>UPDATE</strong> a value in a test table on your database server. We tried updating a value with the command %query and the server reported the following error: %error.',
+      ),
+    ),
+    array(
+      'arguments'   => array(
+        'DELETE FROM {drupal_install_test}',
+        'Drupal can use DELETE database commands.',
+        'Failed to <strong>DELETE</strong> a value from a test table on your database server. We tried deleting a value with the command %query and the server reported the following error: %error.',
+      ),
+    ),
+    array(
+      'arguments'   => array(
+        'DROP TABLE {drupal_install_test}',
+        'Drupal can use DROP TABLE database commands.',
+        'Failed to <strong>DROP</strong> a test table from your database server. We tried dropping a table with the command %query and the server reported the following error %error.',
+      ),
+    ),
+  );
+
+  /**
+   * Results from tasks.
+   *
+   * @var array
+   */
+  protected $results = array();
+
+  /**
+   * Ensure the PDO driver is supported by the version of PHP in use.
+   */
+  protected function hasPdoDriver() {
+    return in_array($this->pdoDriver, PDO::getAvailableDrivers());
+  }
+
+  /**
+   * Assert test as failed.
+   */
+  protected function fail($message) {
+    $this->results[$message] = FALSE;
+  }
+
+  /**
+   * Assert test as a pass.
+   */
+  protected function pass($message) {
+    $this->results[$message] = TRUE;
+  }
+
+  /**
+   * Check whether Drupal is installable on the database.
+   */
+  public function installable() {
+    return $this->hasPdoDriver() && empty($this->error);
+  }
+
+  /**
+   * Return the human-readable name of the driver.
+   */
+  abstract public function name();
+
+  /**
+   * Return the minimum required version of the engine.
+   *
+   * @return
+   *   A version string. If not NULL, it will be checked against the version
+   *   reported by the Database engine using version_compare().
+   */
+  public function minimumVersion() {
+    return NULL;
+  }
+
+  /**
+   * Run database tasks and tests to see if Drupal can run on the database.
+   */
+  public function runTasks() {
+    // We need to establish a connection before we can run tests.
+    if ($this->connect()) {
+      foreach ($this->tasks as $task) {
+        if (!isset($task['function'])) {
+          $task['function'] = 'runTestQuery';
+        }
+        if (method_exists($this, $task['function'])) {
+          // Returning false is fatal. No other tasks can run.
+          if (FALSE === call_user_func_array(array($this, $task['function']), $task['arguments'])) {
+            break;
+          }
+        }
+        else {
+          throw new TaskException(st("Failed to run all tasks against the database server. The task %task wasn't found.", array('%task' => $task['function'])));
+        }
+      }
+    }
+    // Check for failed results and compile message
+    $message = '';
+    foreach ($this->results as $result => $success) {
+      if (!$success) {
+        $message .= '<p class="error">' . $result  . '</p>';
+      }
+    }
+    if (!empty($message)) {
+      $message = '<p>In order for Drupal to work, and to continue with the installation process, you must resolve all issues reported below. For more help with configuring your database server, see the <a href="http://drupal.org/getting-started/install">installation handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.</p>' . $message;
+      throw new TaskException($message);
+    }
+  }
+
+  /**
+   * Check if we can connect to the database.
+   */
+  protected function connect() {
+    try {
+      // This doesn't actually test the connection.
+      db_set_active();
+      // Now actually do a check.
+      Database::getConnection();
+      $this->pass('Drupal can CONNECT to the database ok.');
+    }
+    catch (Exception $e) {
+      $this->fail(st('Failed to connect to your database server. The server reports the following message: %error.<ul><li>Is the database server running?</li><li>Does the database exist, and have you entered the correct database name?</li><li>Have you entered the correct username and password?</li><li>Have you entered the correct database hostname?</li></ul>', array('%error' => $e->getMessage())));
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  /**
+   * Run SQL tests to ensure the database can execute commands with the current user.
+   */
+  protected function runTestQuery($query, $pass, $fail, $fatal = FALSE) {
+    try {
+      db_query($query);
+      $this->pass(st($pass));
+    }
+    catch (Exception $e) {
+      $this->fail(st($fail, array('%query' => $query, '%error' => $e->getMessage(), '%name' => $this->name())));
+      return !$fatal;
+    }
+  }
+
+  /**
+   * Check the engine version.
+   */
+  protected function checkEngineVersion() {
+    if ($this->minimumVersion() && version_compare(Database::getConnection()->version(), $this->minimumVersion(), '<')) {
+      $this->fail(st("The database version %version is less than the minimum required version %minimum_version.", array('%version' => Database::getConnection()->version(), '%minimum_version' => $this->minimumVersion())));
+    }
+  }
+
+  /**
+   * Return driver specific configuration options.
+   *
+   * @param $database
+   *  An array of driver specific configuration options.
+   *
+   * @return
+   *   The options form array.
+   */
+  public function getFormOptions($database) {
+    $form['database'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database name'),
+      '#default_value' => empty($database['database']) ? '' : $database['database'],
+      '#size' => 45,
+      '#required' => TRUE,
+      '#description' => st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_distribution_name())),
+    );
+
+    $form['username'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database username'),
+      '#default_value' => empty($database['username']) ? '' : $database['username'],
+      '#required' => TRUE,
+      '#size' => 45,
+    );
+
+    $form['password'] = array(
+      '#type' => 'password',
+      '#title' => st('Database password'),
+      '#default_value' => empty($database['password']) ? '' : $database['password'],
+      '#required' => FALSE,
+      '#size' => 45,
+    );
+
+    $form['advanced_options'] = array(
+      '#type' => 'fieldset',
+      '#title' => st('Advanced options'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider."),
+      '#weight' => 10,
+    );
+
+    $profile = drupal_get_profile();
+    $db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
+    $form['advanced_options']['db_prefix'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Table prefix'),
+      '#default_value' => '',
+      '#size' => 45,
+      '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_distribution_name(), '%prefix' => $db_prefix)),
+      '#weight' => 10,
+    );
+
+    $form['advanced_options']['host'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database host'),
+      '#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
+      '#size' => 45,
+      // Hostnames can be 255 characters long.
+      '#maxlength' => 255,
+      '#required' => TRUE,
+      '#description' => st('If your database is located on a different server, change this.'),
+    );
+
+    $form['advanced_options']['port'] = array(
+      '#type' => 'textfield',
+      '#title' => st('Database port'),
+      '#default_value' => empty($database['port']) ? '' : $database['port'],
+      '#size' => 45,
+      // The maximum port number is 65536, 5 digits.
+      '#maxlength' => 5,
+      '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Validates driver specific configuration settings.
+   *
+   * Checks to ensure correct basic database settings and that a proper
+   * connection to the database can be established.
+   *
+   * @param $database
+   *   An array of driver specific configuration options.
+   *
+   * @return
+   *   An array of driver configuration errors, keyed by form element name.
+   */
+  public function validateDatabaseSettings($database) {
+    $errors = array();
+
+    // Verify the table prefix.
+    if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
+      $errors[$database['driver'] . '][advanced_options][db_prefix'] = st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $database['prefix']));
+    }
+
+    // Verify the database port.
+    if (!empty($database['port']) && !is_numeric($database['port'])) {
+      $errors[$database['driver'] . '][advanced_options][port'] =  st('Database port must be a number.');
+    }
+
+    return $errors;
+  }
+
+}
diff --git a/core/includes/database/log.inc b/core/lib/Drupal/Core/Database/Log.php
similarity index 80%
rename from core/includes/database/log.inc
rename to core/lib/Drupal/Core/Database/Log.php
index ec27ef8e6332ad6543ce7b489b0048b4aa3a8034..5d5d560c152157491cdd3868f75413422b3dedc1 100644
--- a/core/includes/database/log.inc
+++ b/core/lib/Drupal/Core/Database/Log.php
@@ -2,9 +2,11 @@
 
 /**
  * @file
- * Logging classes for the database layer.
+ * Definition of Drupal\Core\Database\Log
  */
 
+namespace Drupal\Core\Database;
+
 /**
  * Database query logger.
  *
@@ -16,7 +18,7 @@
  * Every connection has one and only one logging object on it for all targets
  * and logging keys.
  */
-class DatabaseLog {
+class Log {
 
   /**
    * Cache of logged queries. This will only be used if the query logger is enabled.
@@ -112,7 +114,7 @@ public function end($logging_key) {
    * @param $time
    *   The time in milliseconds the query took to execute.
    */
-  public function log(DatabaseStatementInterface $statement, $args, $time) {
+  public function log(StatementInterface $statement, $args, $time) {
     foreach (array_keys($this->queryLog) as $key) {
       $this->queryLog[$key][] = array(
         'query' => $statement->getQueryString(),
@@ -128,9 +130,12 @@ public function log(DatabaseStatementInterface $statement, $args, $time) {
    * Determine the routine that called this query.
    *
    * We define "the routine that called this query" as the first entry in
-   * the call stack that is not inside includes/database. That makes the
-   * climbing logic very simple, and handles the variable stack depth caused
-   * by the query builders.
+   * the call stack that is not inside the includes/Drupal/Database directory
+   * and does not begin with db_. That makes the climbing logic very simple, and
+   * handles the variable stack depth caused by the query builders.
+   *
+   * @todo Revisit this logic to not be dependent on file path, so that we can
+   *       split most of the DB layer out of Drupal.
    *
    * @link http://www.php.net/debug_backtrace
    * @return
@@ -142,9 +147,14 @@ public function log(DatabaseStatementInterface $statement, $args, $time) {
    */
   public function findCaller() {
     $stack = debug_backtrace();
-    $stack_count = count($stack);
-    for ($i = 0; $i < $stack_count; ++$i) {
-      if (strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
+    for ($i = 0, $stack_count = count($stack); $i < $stack_count; ++$i) {
+      // If the call was made from a function, 'class' will be empty. It's
+      // just easier to give it a default value than to try and integrate
+      // that into the if statement below.
+      if (empty($stack[$i]['class'])) {
+        $stack[$i]['class'] = '';
+      }
+      if (strpos($stack[$i]['class'], __NAMESPACE__) === FALSE && strpos($stack[$i + 1]['function'], 'db_') === FALSE) {
         return array(
           'file' => $stack[$i]['file'],
           'line' => $stack[$i]['line'],
diff --git a/core/lib/Drupal/Core/Database/Query/AlterableInterface.php b/core/lib/Drupal/Core/Database/Query/AlterableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..66a41e2e32719d31243220a27ddfdf028ed8c70c
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/AlterableInterface.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\AlterableInterface
+ */
+
+namespace Drupal\Core\Database\Query;
+
+/**
+ * Interface for a query that can be manipulated via an alter hook.
+ */
+interface AlterableInterface {
+
+  /**
+   * Adds a tag to a query.
+   *
+   * Tags are strings that identify a query. A query may have any number of
+   * tags. Tags are used to mark a query so that alter hooks may decide if they
+   * wish to take action. Tags should be all lower-case and contain only
+   * letters, numbers, and underscore, and start with a letter. That is, they
+   * should follow the same rules as PHP identifiers in general.
+   *
+   * @param $tag
+   *   The tag to add.
+   *
+   * @return Drupal\Core\Database\Query\AlterableInterface
+   *   The called object.
+   */
+  public function addTag($tag);
+
+  /**
+   * Determines if a given query has a given tag.
+   *
+   * @param $tag
+   *   The tag to check.
+   *
+   * @return
+   *   TRUE if this query has been marked with this tag, FALSE otherwise.
+   */
+  public function hasTag($tag);
+
+  /**
+   * Determines if a given query has all specified tags.
+   *
+   * @param $tags
+   *   A variable number of arguments, one for each tag to check.
+   *
+   * @return
+   *   TRUE if this query has been marked with all specified tags, FALSE
+   *   otherwise.
+   */
+  public function hasAllTags();
+
+  /**
+   * Determines if a given query has any specified tag.
+   *
+   * @param $tags
+   *   A variable number of arguments, one for each tag to check.
+   *
+   * @return
+   *   TRUE if this query has been marked with at least one of the specified
+   *   tags, FALSE otherwise.
+   */
+  public function hasAnyTag();
+
+  /**
+   * Adds additional metadata to the query.
+   *
+   * Often, a query may need to provide additional contextual data to alter
+   * hooks. Alter hooks may then use that information to decide if and how
+   * to take action.
+   *
+   * @param $key
+   *   The unique identifier for this piece of metadata. Must be a string that
+   *   follows the same rules as any other PHP identifier.
+   * @param $object
+   *   The additional data to add to the query. May be any valid PHP variable.
+   *
+   * @return Drupal\Core\Database\Query\AlterableInterface
+   *   The called object.
+   */
+  public function addMetaData($key, $object);
+
+  /**
+   * Retrieves a given piece of metadata.
+   *
+   * @param $key
+   *   The unique identifier for the piece of metadata to retrieve.
+   *
+   * @return
+   *   The previously attached metadata object, or NULL if one doesn't exist.
+   */
+  public function getMetaData($key);
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Condition.php b/core/lib/Drupal/Core/Database/Query/Condition.php
new file mode 100644
index 0000000000000000000000000000000000000000..9faabc6fb3b5b3d2722713def33f0af0045c4114
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Condition.php
@@ -0,0 +1,317 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Condition
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Connection;
+
+use Countable;
+
+/**
+ * Generic class for a series of conditions in a query.
+ */
+class Condition implements ConditionInterface, Countable {
+
+  /**
+   * Array of conditions.
+   *
+   * @var array
+   */
+  protected $conditions = array();
+
+  /**
+   * Array of arguments.
+   *
+   * @var array
+   */
+  protected $arguments = array();
+
+  /**
+   * Whether the conditions have been changed.
+   *
+   * TRUE if the condition has been changed since the last compile.
+   * FALSE if the condition has been compiled and not changed.
+   *
+   * @var bool
+   */
+  protected $changed = TRUE;
+
+  /**
+   * The identifier of the query placeholder this condition has been compiled against.
+   */
+  protected $queryPlaceholderIdentifier;
+
+  /**
+   * Constructs a Condition object.
+   *
+   * @param string $conjunction
+   *   The operator to use to combine conditions: 'AND' or 'OR'.
+   */
+  public function __construct($conjunction) {
+    $this->conditions['#conjunction'] = $conjunction;
+  }
+
+  /**
+   * Implements Countable::count().
+   *
+   * Returns the size of this conditional. The size of the conditional is the
+   * size of its conditional array minus one, because one element is the the
+   * conjunction.
+   */
+  public function count() {
+    return count($this->conditions) - 1;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
+   */
+  public function condition($field, $value = NULL, $operator = NULL) {
+    if (!isset($operator)) {
+      if (is_array($value)) {
+        $operator = 'IN';
+      }
+      else {
+        $operator = '=';
+      }
+    }
+    $this->conditions[] = array(
+      'field' => $field,
+      'value' => $value,
+      'operator' => $operator,
+    );
+
+    $this->changed = TRUE;
+
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::where().
+   */
+  public function where($snippet, $args = array()) {
+    $this->conditions[] = array(
+      'field' => $snippet,
+      'value' => $args,
+      'operator' => NULL,
+    );
+    $this->changed = TRUE;
+
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
+   */
+  public function isNull($field) {
+    return $this->condition($field, NULL, 'IS NULL');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
+   */
+  public function isNotNull($field) {
+    return $this->condition($field, NULL, 'IS NOT NULL');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::exists().
+   */
+  public function exists(SelectInterface $select) {
+    return $this->condition('', $select, 'EXISTS');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $select) {
+    return $this->condition('', $select, 'NOT EXISTS');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
+   */
+  public function &conditions() {
+    return $this->conditions;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
+   */
+  public function arguments() {
+    // If the caller forgot to call compile() first, refuse to run.
+    if ($this->changed) {
+      return NULL;
+    }
+    return $this->arguments;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    // Re-compile if this condition changed or if we are compiled against a
+    // different query placeholder object.
+    if ($this->changed || isset($this->queryPlaceholderIdentifier) && ($this->queryPlaceholderIdentifier != $queryPlaceholder->uniqueIdentifier())) {
+      $this->queryPlaceholderIdentifier = $queryPlaceholder->uniqueIdentifier();
+
+      $condition_fragments = array();
+      $arguments = array();
+
+      $conditions = $this->conditions;
+      $conjunction = $conditions['#conjunction'];
+      unset($conditions['#conjunction']);
+      foreach ($conditions as $condition) {
+        if (!empty($GLOBALS['lg'])) debug($condition);
+        if (empty($condition['operator'])) {
+          // This condition is a literal string, so let it through as is.
+          $condition_fragments[] = ' (' . $condition['field'] . ') ';
+          $arguments += $condition['value'];
+        }
+        else {
+          // It's a structured condition, so parse it out accordingly.
+          // Note that $condition['field'] will only be an object for a dependent
+          // DatabaseCondition object, not for a dependent subquery.
+          if ($condition['field'] instanceof ConditionInterface) {
+            // Compile the sub-condition recursively and add it to the list.
+            $condition['field']->compile($connection, $queryPlaceholder);
+            $condition_fragments[] = '(' . (string) $condition['field'] . ')';
+            $arguments += $condition['field']->arguments();
+          }
+          else {
+            // For simplicity, we treat all operators as the same data structure.
+            // In the typical degenerate case, this won't get changed.
+            $operator_defaults = array(
+              'prefix' => '',
+              'postfix' => '',
+              'delimiter' => '',
+              'operator' => $condition['operator'],
+              'use_value' => TRUE,
+            );
+            $operator = $connection->mapConditionOperator($condition['operator']);
+            if (!isset($operator)) {
+              $operator = $this->mapConditionOperator($condition['operator']);
+            }
+            $operator += $operator_defaults;
+
+            $placeholders = array();
+            if ($condition['value'] instanceof SelectInterface) {
+              $condition['value']->compile($connection, $queryPlaceholder);
+              $placeholders[] = (string) $condition['value'];
+              $arguments += $condition['value']->arguments();
+              // Subqueries are the actual value of the operator, we don't
+              // need to add another below.
+              $operator['use_value'] = FALSE;
+            }
+            // We assume that if there is a delimiter, then the value is an
+            // array. If not, it is a scalar. For simplicity, we first convert
+            // up to an array so that we can build the placeholders in the same way.
+            elseif (!$operator['delimiter']) {
+              $condition['value'] = array($condition['value']);
+            }
+            if ($operator['use_value']) {
+              foreach ($condition['value'] as $value) {
+                $placeholder = ':db_condition_placeholder_' . $queryPlaceholder->nextPlaceholder();
+                $arguments[$placeholder] = $value;
+                $placeholders[] = $placeholder;
+              }
+            }
+            $condition_fragments[] = ' (' . $connection->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
+          }
+        }
+      }
+
+      $this->changed = FALSE;
+      $this->stringVersion = implode($conjunction, $condition_fragments);
+      $this->arguments = $arguments;
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return !$this->changed;
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the conditions to string.
+   *
+   * @return string
+   *   A string version of the conditions.
+   */
+  public function __toString() {
+    // If the caller forgot to call compile() first, refuse to run.
+    if ($this->changed) {
+      return '';
+    }
+    return $this->stringVersion;
+  }
+
+  /**
+   * PHP magic __clone() method.
+   *
+   * Only copies fields that implement Drupal\Core\Database\Query\ConditionInterface. Also sets
+   * $this->changed to TRUE.
+   */
+  function __clone() {
+    $this->changed = TRUE;
+    foreach ($this->conditions as $key => $condition) {
+      if ($condition['field'] instanceOf ConditionInterface) {
+        $this->conditions[$key]['field'] = clone($condition['field']);
+      }
+    }
+  }
+
+  /**
+   * Gets any special processing requirements for the condition operator.
+   *
+   * Some condition types require special processing, such as IN, because
+   * the value data they pass in is not a simple value. This is a simple
+   * overridable lookup function.
+   *
+   * @param $operator
+   *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
+   *
+   * @return
+   *   The extra handling directives for the specified operator, or NULL.
+   */
+  protected function mapConditionOperator($operator) {
+    // $specials does not use drupal_static as its value never changes.
+    static $specials = array(
+      'BETWEEN' => array('delimiter' => ' AND '),
+      'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
+      'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
+      'EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
+      'NOT EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
+      'IS NULL' => array('use_value' => FALSE),
+      'IS NOT NULL' => array('use_value' => FALSE),
+      // Use backslash for escaping wildcard characters.
+      'LIKE' => array('postfix' => " ESCAPE '\\\\'"),
+      'NOT LIKE' => array('postfix' => " ESCAPE '\\\\'"),
+      // These ones are here for performance reasons.
+      '=' => array(),
+      '<' => array(),
+      '>' => array(),
+      '>=' => array(),
+      '<=' => array(),
+    );
+    if (isset($specials[$operator])) {
+      $return = $specials[$operator];
+    }
+    else {
+      // We need to upper case because PHP index matches are case sensitive but
+      // do not need the more expensive drupal_strtoupper because SQL statements are ASCII.
+      $operator = strtoupper($operator);
+      $return = isset($specials[$operator]) ? $specials[$operator] : array();
+    }
+
+    $return += array('operator' => $operator);
+
+    return $return;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Database/Query/ConditionInterface.php b/core/lib/Drupal/Core/Database/Query/ConditionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..70c23c785443dab1996f15f70842b5963b755eda
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/ConditionInterface.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\ConditionInterface
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Connection;
+
+/**
+ * Interface for a conditional clause in a query.
+ */
+interface ConditionInterface {
+
+  /**
+   * Helper function: builds the most common conditional clauses.
+   *
+   * This method can take a variable number of parameters. If called with two
+   * parameters, they are taken as $field and $value with $operator having a
+   * value of IN if $value is an array and = otherwise.
+   *
+   * Do not use this method to test for NULL values. Instead, use
+   * QueryConditionInterface::isNull() or QueryConditionInterface::isNotNull().
+   *
+   * @param $field
+   *   The name of the field to check. If you would like to add a more complex
+   *   condition involving operators or functions, use where().
+   * @param $value
+   *   The value to test the field against. In most cases, this is a scalar.
+   *   For more complex options, it is an array. The meaning of each element in
+   *   the array is dependent on the $operator.
+   * @param $operator
+   *   The comparison operator, such as =, <, or >=. It also accepts more
+   *   complex options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is
+   *   an array, and = otherwise.
+   *
+   * @return QueryConditionInterface
+   *   The called object.
+   *
+   * @see Drupal\Core\Database\Query\ConditionInterface::isNull()
+   * @see Drupal\Core\Database\Query\ConditionInterface::isNotNull()
+   */
+  public function condition($field, $value = NULL, $operator = NULL);
+
+  /**
+   * Adds an arbitrary WHERE clause to the query.
+   *
+   * @param $snippet
+   *   A portion of a WHERE clause as a prepared statement. It must use named
+   *   placeholders, not ? placeholders.
+   * @param $args
+   *   An associative array of arguments.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function where($snippet, $args = array());
+
+  /**
+   * Sets a condition that the specified field be NULL.
+   *
+   * @param $field
+   *   The name of the field to check.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function isNull($field);
+
+  /**
+   * Sets a condition that the specified field be NOT NULL.
+   *
+   * @param $field
+   *   The name of the field to check.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function isNotNull($field);
+
+  /**
+   * Sets a condition that the specified subquery returns values.
+   *
+   * @param Drupal\Core\Database\Query\SelectInterface $select
+   *   The subquery that must contain results.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function exists(SelectInterface $select);
+
+  /**
+   * Sets a condition that the specified subquery returns no values.
+   *
+   * @param Drupal\Core\Database\Query\SelectInterface $select
+   *   The subquery that must not contain results.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function notExists(SelectInterface $select);
+
+  /**
+   * Gets a complete list of all conditions in this conditional clause.
+   *
+   * This method returns by reference. That allows alter hooks to access the
+   * data structure directly and manipulate it before it gets compiled.
+   *
+   * The data structure that is returned is an indexed array of entries, where
+   * each entry looks like the following:
+   * @code
+   * array(
+   *   'field' => $field,
+   *   'value' => $value,
+   *   'operator' => $operator,
+   * );
+   * @endcode
+   *
+   * In the special case that $operator is NULL, the $field is taken as a raw
+   * SQL snippet (possibly containing a function) and $value is an associative
+   * array of placeholders for the snippet.
+   *
+   * There will also be a single array entry of #conjunction, which is the
+   * conjunction that will be applied to the array, such as AND.
+   */
+  public function &conditions();
+
+  /**
+   * Gets a complete list of all values to insert into the prepared statement.
+   *
+   * @return
+   *   An associative array of placeholders and values.
+   */
+  public function arguments();
+
+  /**
+   * Compiles the saved conditions for later retrieval.
+   *
+   * This method does not return anything, but simply prepares data to be
+   * retrieved via __toString() and arguments().
+   *
+   * @param $connection
+   *   The database connection for which to compile the conditionals.
+   * @param $queryPlaceholder
+   *   The query this condition belongs to. If not given, the current query is
+   *   used.
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder);
+
+  /**
+   * Check whether a condition has been previously compiled.
+   *
+   * @return
+   *   TRUE if the condition has been previously compiled.
+   */
+  public function compiled();
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Delete.php b/core/lib/Drupal/Core/Database/Query/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ecd0407d75121aa071472dbdb60d7c0a171b6c2
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Delete.php
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Delete
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+/**
+ * General class for an abstracted DELETE operation.
+ */
+class Delete extends Query implements ConditionInterface {
+
+  /**
+   * The table from which to delete.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * The condition object for this query.
+   *
+   * Condition handling is handled via composition.
+   *
+   * @var Condition
+   */
+  protected $condition;
+
+  /**
+   * Constructs a Delete object.
+   *
+   * @param Drupal\Core\Database\Connection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
+  public function __construct(Connection $connection, $table, array $options = array()) {
+    $options['return'] = Database::RETURN_AFFECTED;
+    parent::__construct($connection, $options);
+    $this->table = $table;
+
+    $this->condition = new Condition('AND');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
+   */
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->condition->condition($field, $value, $operator);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
+   */
+  public function isNull($field) {
+    $this->condition->isNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
+   */
+  public function isNotNull($field) {
+    $this->condition->isNotNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::exists().
+   */
+  public function exists(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
+   */
+  public function &conditions() {
+    return $this->condition->conditions();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
+   */
+  public function arguments() {
+    return $this->condition->arguments();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::where().
+   */
+  public function where($snippet, $args = array()) {
+    $this->condition->where($snippet, $args);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->condition->compile($connection, $queryPlaceholder);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return $this->condition->compiled();
+  }
+
+  /**
+   * Executes the DELETE query.
+   *
+   * @return
+   *   The return value is dependent on the database connection.
+   */
+  public function execute() {
+    $values = array();
+    if (count($this->condition)) {
+      $this->condition->compile($this->connection, $this);
+      $values = $this->condition->arguments();
+    }
+
+    return $this->connection->query((string) $this, $values, $this->queryOptions);
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    $query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
+
+    if (count($this->condition)) {
+
+      $this->condition->compile($this->connection, $this);
+      $query .= "\nWHERE " . $this->condition;
+    }
+
+    return $query;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/ExtendableInterface.php b/core/lib/Drupal/Core/Database/Query/ExtendableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ebac45ac1983852b1bf15012ddfcafd6bc9660a
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/ExtendableInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\ExtendableInterface
+ */
+
+namespace Drupal\Core\Database\Query;
+
+/**
+ * Interface for extendable query objects.
+ *
+ * "Extenders" follow the "Decorator" OOP design pattern.  That is, they wrap
+ * and "decorate" another object.  In our case, they implement the same interface
+ * as select queries and wrap a select query, to which they delegate almost all
+ * operations.  Subclasses of this class may implement additional methods or
+ * override existing methods as appropriate.  Extenders may also wrap other
+ * extender objects, allowing for arbitrarily complex "enhanced" queries.
+ */
+interface ExtendableInterface {
+
+  /**
+   * Enhance this object by wrapping it in an extender object.
+   *
+   * @param $extender_name
+   *   The base name of the extending class.  The base name will be checked
+   *   against the current database connection to allow driver-specific subclasses
+   *   as well, using the same logic as the query objects themselves.  For example,
+   *   PagerDefault_mysql is the MySQL-specific override for PagerDefault.
+   * @return Drupal\Core\Database\Query\ExtendableInterface
+   *   The extender object, which now contains a reference to this object.
+   */
+  public function extend($extender_name);
+}
diff --git a/core/lib/Drupal/Core/Database/Query/FieldsOverlapException.php b/core/lib/Drupal/Core/Database/Query/FieldsOverlapException.php
new file mode 100644
index 0000000000000000000000000000000000000000..f9d93728b158059da4e1ab5cd1559c8837afe187
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/FieldsOverlapException.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\FieldsOverlapExceptoin
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\DatabaseException;
+
+use InvalidArgumentException;
+
+/**
+ * Exception thrown if an insert query specifies a field twice.
+ *
+ * It is not allowed to specify a field as default and insert field, this
+ * exception is thrown if that is the case.
+ */
+class FieldsOverlapException extends InvalidArgumentException implements DatabaseException {}
diff --git a/core/lib/Drupal/Core/Database/Query/Insert.php b/core/lib/Drupal/Core/Database/Query/Insert.php
new file mode 100644
index 0000000000000000000000000000000000000000..e19de45cfa75319eca5abdc471bb9c3ef781da2d
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Insert.php
@@ -0,0 +1,301 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Insert
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+
+/**
+ * General class for an abstracted INSERT query.
+ */
+class Insert extends Query {
+
+  /**
+   * The table on which to insert.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * An array of fields on which to insert.
+   *
+   * @var array
+   */
+  protected $insertFields = array();
+
+  /**
+   * An array of fields that should be set to their database-defined defaults.
+   *
+   * @var array
+   */
+  protected $defaultFields = array();
+
+  /**
+   * A nested array of values to insert.
+   *
+   * $insertValues is an array of arrays. Each sub-array is either an
+   * associative array whose keys are field names and whose values are field
+   * values to insert, or a non-associative array of values in the same order
+   * as $insertFields.
+   *
+   * Whether multiple insert sets will be run in a single query or multiple
+   * queries is left to individual drivers to implement in whatever manner is
+   * most appropriate. The order of values in each sub-array must match the
+   * order of fields in $insertFields.
+   *
+   * @var array
+   */
+  protected $insertValues = array();
+
+  /**
+   * A SelectQuery object to fetch the rows that should be inserted.
+   *
+   * @var SelectQueryInterface
+   */
+  protected $fromQuery;
+
+  /**
+   * Constructs an Insert object.
+   *
+   * @param Drupal\Core\Database\Connection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
+  public function __construct($connection, $table, array $options = array()) {
+    if (!isset($options['return'])) {
+      $options['return'] = Database::RETURN_INSERT_ID;
+    }
+    parent::__construct($connection, $options);
+    $this->table = $table;
+  }
+
+  /**
+   * Adds a set of field->value pairs to be inserted.
+   *
+   * This method may only be called once. Calling it a second time will be
+   * ignored. To queue up multiple sets of values to be inserted at once,
+   * use the values() method.
+   *
+   * @param $fields
+   *   An array of fields on which to insert. This array may be indexed or
+   *   associative. If indexed, the array is taken to be the list of fields.
+   *   If associative, the keys of the array are taken to be the fields and
+   *   the values are taken to be corresponding values to insert. If a
+   *   $values argument is provided, $fields must be indexed.
+   * @param $values
+   *   An array of fields to insert into the database. The values must be
+   *   specified in the same order as the $fields array.
+   *
+   * @return Drupal\Core\Database\Query\Insert
+   *   The called object.
+   */
+  public function fields(array $fields, array $values = array()) {
+    if (empty($this->insertFields)) {
+      if (empty($values)) {
+        if (!is_numeric(key($fields))) {
+          $values = array_values($fields);
+          $fields = array_keys($fields);
+        }
+      }
+      $this->insertFields = $fields;
+      if (!empty($values)) {
+        $this->insertValues[] = $values;
+      }
+    }
+
+    return $this;
+  }
+
+  /**
+   * Adds another set of values to the query to be inserted.
+   *
+   * If $values is a numeric-keyed array, it will be assumed to be in the same
+   * order as the original fields() call. If it is associative, it may be
+   * in any order as long as the keys of the array match the names of the
+   * fields.
+   *
+   * @param $values
+   *   An array of values to add to the query.
+   *
+   * @return Drupal\Core\Database\Query\Insert
+   *   The called object.
+   */
+  public function values(array $values) {
+    if (is_numeric(key($values))) {
+      $this->insertValues[] = $values;
+    }
+    else {
+      // Reorder the submitted values to match the fields array.
+      foreach ($this->insertFields as $key) {
+        $insert_values[$key] = $values[$key];
+      }
+      // For consistency, the values array is always numerically indexed.
+      $this->insertValues[] = array_values($insert_values);
+    }
+    return $this;
+  }
+
+  /**
+   * Specifies fields for which the database defaults should be used.
+   *
+   * If you want to force a given field to use the database-defined default,
+   * not NULL or undefined, use this method to instruct the database to use
+   * default values explicitly. In most cases this will not be necessary
+   * unless you are inserting a row that is all default values, as you cannot
+   * specify no values in an INSERT query.
+   *
+   * Specifying a field both in fields() and in useDefaults() is an error
+   * and will not execute.
+   *
+   * @param $fields
+   *   An array of values for which to use the default values
+   *   specified in the table definition.
+   *
+   * @return Drupal\Core\Database\Query\Insert
+   *   The called object.
+   */
+  public function useDefaults(array $fields) {
+    $this->defaultFields = $fields;
+    return $this;
+  }
+
+  /**
+   * Sets the fromQuery on this InsertQuery object.
+   *
+   * @param SelectQueryInterface $query
+   *   The query to fetch the rows that should be inserted.
+   *
+   * @return InsertQuery
+   *   The called object.
+   */
+  public function from(SelectInterface $query) {
+    $this->fromQuery = $query;
+    return $this;
+  }
+
+  /**
+   * Executes the insert query.
+   *
+   * @return
+   *   The last insert ID of the query, if one exists. If the query
+   *   was given multiple sets of values to insert, the return value is
+   *   undefined. If no fields are specified, this method will do nothing and
+   *   return NULL. That makes it safe to use in multi-insert loops.
+   */
+  public function execute() {
+    // If validation fails, simply return NULL. Note that validation routines
+    // in preExecute() may throw exceptions instead.
+    if (!$this->preExecute()) {
+      return NULL;
+    }
+
+    // If we're selecting from a SelectQuery, finish building the query and
+    // pass it back, as any remaining options are irrelevant.
+    if (!empty($this->fromQuery)) {
+      $sql = (string) $this;
+      // The SelectQuery may contain arguments, load and pass them through.
+      return $this->connection->query($sql, $this->fromQuery->getArguments(), $this->queryOptions);
+    }
+
+    $last_insert_id = 0;
+
+    // Each insert happens in its own query in the degenerate case. However,
+    // we wrap it in a transaction so that it is atomic where possible. On many
+    // databases, such as SQLite, this is also a notable performance boost.
+    $transaction = $this->connection->startTransaction();
+
+    try {
+      $sql = (string) $this;
+      foreach ($this->insertValues as $insert_values) {
+        $last_insert_id = $this->connection->query($sql, $insert_values, $this->queryOptions);
+      }
+    }
+    catch (Exception $e) {
+      // One of the INSERTs failed, rollback the whole batch.
+      $transaction->rollback();
+      // Rethrow the exception for the calling code.
+      throw $e;
+    }
+
+    // Re-initialize the values array so that we can re-use this query.
+    $this->insertValues = array();
+
+    // Transaction commits here where $transaction looses scope.
+
+    return $last_insert_id;
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    // Default fields are always placed first for consistency.
+    $insert_fields = array_merge($this->defaultFields, $this->insertFields);
+
+    if (!empty($this->fromQuery)) {
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+    }
+
+    // For simplicity, we will use the $placeholders array to inject
+    // default keywords even though they are not, strictly speaking,
+    // placeholders for prepared statements.
+    $placeholders = array();
+    $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
+    $placeholders = array_pad($placeholders, count($this->insertFields), '?');
+
+    return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', $placeholders) . ')';
+  }
+
+  /**
+   * Preprocesses and validates the query.
+   *
+   * @return
+   *   TRUE if the validation was successful, FALSE if not.
+   *
+   * @throws Drupal\Core\Database\Query\FieldsOverlapException
+   * @throws Drupal\Core\Database\Query\NoFieldsException
+   */
+  public function preExecute() {
+    // Confirm that the user did not try to specify an identical
+    // field and default field.
+    if (array_intersect($this->insertFields, $this->defaultFields)) {
+      throw new FieldsOverlapException('You may not specify the same field to have a value and a schema-default value.');
+    }
+
+    if (!empty($this->fromQuery)) {
+      // We have to assume that the used aliases match the insert fields.
+      // Regular fields are added to the query before expressions, maintain the
+      // same order for the insert fields.
+      // This behavior can be overridden by calling fields() manually as only the
+      // first call to fields() does have an effect.
+      $this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions())));
+    }
+
+    // Don't execute query without fields.
+    if (count($this->insertFields) + count($this->defaultFields) == 0) {
+      throw new NoFieldsException('There are no fields available to insert with.');
+    }
+
+    // If no values have been added, silently ignore this query. This can happen
+    // if values are added conditionally, so we don't want to throw an
+    // exception.
+    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->fromQuery)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/InvalidMergeQueryException.php b/core/lib/Drupal/Core/Database/Query/InvalidMergeQueryException.php
new file mode 100644
index 0000000000000000000000000000000000000000..59ad1c9c3037e637b050c42d9b1fd87cc0364f13
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/InvalidMergeQueryException.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\InvalidMergeQueryException
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\DatabaseException;
+
+use InvalidArgumentException;
+
+/**
+ * Exception thrown for merge queries that do not make semantic sense.
+ *
+ * There are many ways that a merge query could be malformed.  They should all
+ * throw this exception and set an appropriately descriptive message.
+ */
+class InvalidMergeQueryException extends InvalidArgumentException implements DatabaseException {}
diff --git a/core/lib/Drupal/Core/Database/Query/Merge.php b/core/lib/Drupal/Core/Database/Query/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..547a22323b2d90bfa52205378a7d0a0c22b4598c
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Merge.php
@@ -0,0 +1,457 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Merge
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+use Exception;
+
+/**
+ * General class for an abstracted MERGE query operation.
+ *
+ * An ANSI SQL:2003 compatible database would run the following query:
+ *
+ * @code
+ * MERGE INTO table_name_1 USING table_name_2 ON (condition)
+ *   WHEN MATCHED THEN
+ *   UPDATE SET column1 = value1 [, column2 = value2 ...]
+ *   WHEN NOT MATCHED THEN
+ *   INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...
+ * @endcode
+ *
+ * Other databases (most notably MySQL, PostgreSQL and SQLite) will emulate
+ * this statement by running a SELECT and then INSERT or UPDATE.
+ *
+ * By default, the two table names are identical and they are passed into the
+ * the constructor. table_name_2 can be specified by the
+ * MergeQuery::conditionTable() method. It can be either a string or a
+ * subquery.
+ *
+ * The condition is built exactly like SelectQuery or UpdateQuery conditions,
+ * the UPDATE query part is built similarly like an UpdateQuery and finally the
+ * INSERT query part is built similarly like an InsertQuery. However, both
+ * UpdateQuery and InsertQuery has a fields method so
+ * MergeQuery::updateFields() and MergeQuery::insertFields() needs to be called
+ * instead. MergeQuery::fields() can also be called which calls both of these
+ * methods as the common case is to use the same column-value pairs for both
+ * INSERT and UPDATE. However, this is not mandatory. Another convinient
+ * wrapper is MergeQuery::key() which adds the same column-value pairs to the
+ * condition and the INSERT query part.
+ *
+ * Several methods (key(), fields(), insertFields()) can be called to set a
+ * key-value pair for the INSERT query part. Subsequent calls for the same
+ * fields override the earlier ones. The same is true for UPDATE and key(),
+ * fields() and updateFields().
+ */
+class Merge extends Query implements ConditionInterface {
+  /**
+   * Returned by execute() if an INSERT query has been executed.
+   */
+  const STATUS_INSERT = 1;
+
+  /**
+   * Returned by execute() if an UPDATE query has been executed.
+   */
+  const STATUS_UPDATE = 2;
+
+  /**
+   * The table to be used for INSERT and UPDATE.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * The table or subquery to be used for the condition.
+   */
+  protected $conditionTable;
+
+  /**
+   * An array of fields on which to insert.
+   *
+   * @var array
+   */
+  protected $insertFields = array();
+
+  /**
+   * An array of fields which should be set to their database-defined defaults.
+   *
+   * Used on INSERT.
+   *
+   * @var array
+   */
+  protected $defaultFields = array();
+
+  /**
+   * An array of values to be inserted.
+   *
+   * @var string
+   */
+  protected $insertValues = array();
+
+  /**
+   * An array of fields that will be updated.
+   *
+   * @var array
+   */
+  protected $updateFields = array();
+
+  /**
+   * Array of fields to update to an expression in case of a duplicate record.
+   *
+   * This variable is a nested array in the following format:
+   * @code
+   * <some field> => array(
+   *  'condition' => <condition to execute, as a string>,
+   *  'arguments' => <array of arguments for condition, or NULL for none>,
+   * );
+   * @endcode
+   *
+   * @var array
+   */
+  protected $expressionFields = array();
+
+  /**
+   * Flag indicating whether an UPDATE is necessary.
+   *
+   * @var boolean
+   */
+  protected $needsUpdate = FALSE;
+
+  /**
+  * Constructs a Merge object.
+  *
+  * @param Drupal\Core\Database\Connection $connection
+  *   A Drupal\Core\Database\Connection object.
+  * @param string $table
+  *   Name of the table to associate with this query.
+  * @param array $options
+  *   Array of database options.
+  */
+  public function __construct(Connection $connection, $table, array $options = array()) {
+    $options['return'] = Database::RETURN_AFFECTED;
+    parent::__construct($connection, $options);
+    $this->table = $table;
+    $this->conditionTable = $table;
+    $this->condition = new Condition('AND');
+  }
+
+  /**
+   * Sets the table or subquery to be used for the condition.
+   *
+   * @param $table
+   *   The table name or the subquery to be used. Use a Select query object to
+   *   pass in a subquery.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  protected function conditionTable($table) {
+    $this->conditionTable = $table;
+    return $this;
+  }
+
+  /**
+   * Adds a set of field->value pairs to be updated.
+   *
+   * @param $fields
+   *   An associative array of fields to write into the database. The array keys
+   *   are the field names and the values are the values to which to set them.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function updateFields(array $fields) {
+    $this->updateFields = $fields;
+    $this->needsUpdate = TRUE;
+    return $this;
+  }
+
+  /**
+   * Specifies fields to be updated as an expression.
+   *
+   * Expression fields are cases such as counter = counter + 1. This method
+   * takes precedence over MergeQuery::updateFields() and it's wrappers,
+   * MergeQuery::key() and MergeQuery::fields().
+   *
+   * @param $field
+   *   The field to set.
+   * @param $expression
+   *   The field will be set to the value of this expression. This parameter
+   *   may include named placeholders.
+   * @param $arguments
+   *   If specified, this is an array of key/value pairs for named placeholders
+   *   corresponding to the expression.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function expression($field, $expression, array $arguments = NULL) {
+    $this->expressionFields[$field] = array(
+      'expression' => $expression,
+      'arguments' => $arguments,
+    );
+    $this->needsUpdate = TRUE;
+    return $this;
+  }
+
+  /**
+   * Adds a set of field->value pairs to be inserted.
+   *
+   * @param $fields
+   *   An array of fields on which to insert. This array may be indexed or
+   *   associative. If indexed, the array is taken to be the list of fields.
+   *   If associative, the keys of the array are taken to be the fields and
+   *   the values are taken to be corresponding values to insert. If a
+   *   $values argument is provided, $fields must be indexed.
+   * @param $values
+   *   An array of fields to insert into the database. The values must be
+   *   specified in the same order as the $fields array.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function insertFields(array $fields, array $values = array()) {
+    if ($values) {
+      $fields = array_combine($fields, $values);
+    }
+    $this->insertFields = $fields;
+    return $this;
+  }
+
+  /**
+   * Specifies fields for which the database-defaults should be used.
+   *
+   * If you want to force a given field to use the database-defined default,
+   * not NULL or undefined, use this method to instruct the database to use
+   * default values explicitly. In most cases this will not be necessary
+   * unless you are inserting a row that is all default values, as you cannot
+   * specify no values in an INSERT query.
+   *
+   * Specifying a field both in fields() and in useDefaults() is an error
+   * and will not execute.
+   *
+   * @param $fields
+   *   An array of values for which to use the default values
+   *   specified in the table definition.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function useDefaults(array $fields) {
+    $this->defaultFields = $fields;
+    return $this;
+  }
+
+  /**
+   * Sets common field-value pairs in the INSERT and UPDATE query parts.
+   *
+   * This method should only be called once. It may be called either
+   * with a single associative array or two indexed arrays. If called
+   * with an associative array, the keys are taken to be the fields
+   * and the values are taken to be the corresponding values to set.
+   * If called with two arrays, the first array is taken as the fields
+   * and the second array is taken as the corresponding values.
+   *
+   * @param $fields
+   *   An array of fields to insert, or an associative array of fields and
+   *   values. The keys of the array are taken to be the fields and the values
+   *   are taken to be corresponding values to insert.
+   * @param $values
+   *   An array of values to set into the database. The values must be
+   *   specified in the same order as the $fields array.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function fields(array $fields, array $values = array()) {
+    if ($values) {
+      $fields = array_combine($fields, $values);
+    }
+    foreach ($fields as $key => $value) {
+      $this->insertFields[$key] = $value;
+      $this->updateFields[$key] = $value;
+    }
+    $this->needsUpdate = TRUE;
+    return $this;
+  }
+
+  /**
+   * Sets the key field(s) to be used as conditions for this query.
+   *
+   * This method should only be called once. It may be called either
+   * with a single associative array or two indexed arrays. If called
+   * with an associative array, the keys are taken to be the fields
+   * and the values are taken to be the corresponding values to set.
+   * If called with two arrays, the first array is taken as the fields
+   * and the second array is taken as the corresponding values.
+   *
+   * The fields are copied to the condition of the query and the INSERT part.
+   * If no other method is called, the UPDATE will become a no-op.
+   *
+   * @param $fields
+   *   An array of fields to set, or an associative array of fields and values.
+   * @param $values
+   *   An array of values to set into the database. The values must be
+   *   specified in the same order as the $fields array.
+   *
+   * @return Drupal\Core\Database\Query\Merge
+   *   The called object.
+   */
+  public function key(array $fields, array $values = array()) {
+    if ($values) {
+      $fields = array_combine($fields, $values);
+    }
+    foreach ($fields as $key => $value) {
+      $this->insertFields[$key] = $value;
+      $this->condition($key, $value);
+    }
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
+   */
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->condition->condition($field, $value, $operator);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
+   */
+  public function isNull($field) {
+    $this->condition->isNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
+   */
+  public function isNotNull($field) {
+    $this->condition->isNotNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::exists().
+   */
+  public function exists(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
+   */
+  public function &conditions() {
+    return $this->condition->conditions();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
+   */
+  public function arguments() {
+    return $this->condition->arguments();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::where().
+   */
+  public function where($snippet, $args = array()) {
+    $this->condition->where($snippet, $args);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->condition->compile($connection, $queryPlaceholder);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return $this->condition->compiled();
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * In the degenerate case, there is no string-able query as this operation
+   * is potentially two queries.
+   *
+   * @return string
+   *   The prepared query statement.
+   */
+  public function __toString() {
+  }
+
+  public function execute() {
+    // Wrap multiple queries in a transaction, if the database supports it.
+    $transaction = $this->connection->startTransaction();
+    try {
+      if (!count($this->condition)) {
+        throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
+      }
+      $select = $this->connection->select($this->conditionTable)
+        ->condition($this->condition)
+        ->forUpdate();
+      $select->addExpression('1');
+      if (!$select->execute()->fetchField()) {
+        try {
+          $insert = $this->connection->insert($this->table)->fields($this->insertFields);
+          if ($this->defaultFields) {
+            $insert->useDefaults($this->defaultFields);
+          }
+          $insert->execute();
+          return self::STATUS_INSERT;
+        }
+        catch (Exception $e) {
+          // The insert query failed, maybe it's because a racing insert query
+          // beat us in inserting the same row. Retry the select query, if it
+          // returns a row, ignore the error and continue with the update
+          // query below.
+          if (!$select->execute()->fetchField()) {
+            throw $e;
+          }
+        }
+      }
+      if ($this->needsUpdate) {
+        $update = $this->connection->update($this->table)
+          ->fields($this->updateFields)
+          ->condition($this->condition);
+        if ($this->expressionFields) {
+          foreach ($this->expressionFields as $field => $data) {
+            $update->expression($field, $data['expression'], $data['arguments']);
+          }
+        }
+        $update->execute();
+        return self::STATUS_UPDATE;
+      }
+    }
+    catch (Exception $e) {
+      // Something really wrong happened here, bubble up the exception to the
+      // caller.
+      $transaction->rollback();
+      throw $e;
+    }
+    // Transaction commits here where $transaction looses scope.
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/NoFieldsException.php b/core/lib/Drupal/Core/Database/Query/NoFieldsException.php
new file mode 100644
index 0000000000000000000000000000000000000000..18851fdce52151188d0f29e5b56ed82ad29e4ff0
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/NoFieldsException.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\NoFieldsException
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\DatabaseException;
+
+use InvalidArgumentException;
+
+/**
+ * Exception thrown if an insert query doesn't specify insert or default fields.
+ */
+class NoFieldsException extends InvalidArgumentException implements DatabaseException {}
diff --git a/core/lib/Drupal/Core/Database/Query/PlaceholderInterface.php b/core/lib/Drupal/Core/Database/Query/PlaceholderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..68b802e676cb9fdf5d0c9886bbeac492393f16dd
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/PlaceholderInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\PlaceholderInterface
+ */
+
+namespace Drupal\Core\Database\Query;
+
+/**
+ * Interface for a query that accepts placeholders.
+ */
+interface PlaceholderInterface {
+
+  /**
+   * Returns a unique identifier for this object.
+   */
+  public function uniqueIdentifier();
+
+  /**
+   * Returns the next placeholder ID for the query.
+   *
+   * @return
+   *   The next available placeholder ID as an integer.
+   */
+  public function nextPlaceholder();
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Query.php b/core/lib/Drupal/Core/Database/Query/Query.php
new file mode 100644
index 0000000000000000000000000000000000000000..95ab4b9225dc2c5729ebafc7b47e40c5289408a9
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Query.php
@@ -0,0 +1,180 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Query
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+/**
+ * Base class for query builders.
+ *
+ * Note that query builders use PHP's magic __toString() method to compile the
+ * query object into a prepared statement.
+ */
+abstract class Query implements PlaceholderInterface {
+
+  /**
+   * The connection object on which to run this query.
+   *
+   * @var Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * The target of the connection object.
+   *
+   * @var string
+   */
+  protected $connectionTarget;
+
+  /**
+   * The key of the connection object.
+   *
+   * @var string
+   */
+  protected $connectionKey;
+
+  /**
+   * The query options to pass on to the connection object.
+   *
+   * @var array
+   */
+  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
+   */
+  protected $comments = array();
+
+  /**
+   * Constructs a Query object.
+   *
+   * @param Drupal\Core\Database\Connection $connection
+   *   Database connection object.
+   * @param array $options
+   *   Array of query options.
+   */
+  public function __construct(Connection $connection, $options) {
+    $this->uniqueIdentifier = uniqid('', TRUE);
+
+    $this->connection = $connection;
+    $this->connectionKey = $this->connection->getKey();
+    $this->connectionTarget = $this->connection->getTarget();
+
+    $this->queryOptions = $options;
+  }
+
+  /**
+   * Implements the magic __sleep function to disconnect from the database.
+   */
+  public function __sleep() {
+    $keys = get_object_vars($this);
+    unset($keys['connection']);
+    return array_keys($keys);
+  }
+
+  /**
+   * Implements the magic __wakeup function to reconnect to the database.
+   */
+  public function __wakeup() {
+    $this->connection = Database::getConnection($this->connectionTarget, $this->connectionKey);
+  }
+
+  /**
+   * Implements the magic __clone function.
+   */
+  public function __clone() {
+    $this->uniqueIdentifier = uniqid('', TRUE);
+  }
+
+  /**
+   * Runs the query against the database.
+   */
+  abstract protected function execute();
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * The toString operation is how we compile a query object to a prepared
+   * statement.
+   *
+   * @return
+   *   A prepared statement query string for this object.
+   */
+  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
+   * query log or the list of active queries on an SQL server. This allows
+   * for easier debugging and allows you to more easily find where a query
+   * with a performance problem is being generated.
+   *
+   * The comment string will be sanitized to remove * / and other characters
+   * that may terminate the string early so as to avoid SQL injection attacks.
+   *
+   * @param $comment
+   *   The comment string to be inserted into the query.
+   *
+   * @return Drupal\Core\Database\Query\Query
+   *   The called object.
+   */
+  public function comment($comment) {
+    $this->comments[] = $comment;
+    return $this;
+  }
+
+  /**
+   * Returns a reference to the comments array for the query.
+   *
+   * Because this method returns by reference, alter hooks may edit the comments
+   * array directly to make their changes. If just adding comments, however, the
+   * use of comment() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   * @code
+   * $comments =& $query->getComments();
+   * @endcode
+   *
+   * @return
+   *   A reference to the comments array structure.
+   */
+  public function &getComments() {
+    return $this->comments;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Select.php b/core/lib/Drupal/Core/Database/Query/Select.php
new file mode 100644
index 0000000000000000000000000000000000000000..2d3159c36e7bde7c0ed981ac7e334283057343fe
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Select.php
@@ -0,0 +1,765 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Select
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+
+/**
+ * Query builder for SELECT statements.
+ */
+class Select extends Query implements SelectInterface {
+
+  /**
+   * The fields to SELECT.
+   *
+   * @var array
+   */
+  protected $fields = array();
+
+  /**
+   * The expressions to SELECT as virtual fields.
+   *
+   * @var array
+   */
+  protected $expressions = array();
+
+  /**
+   * The tables against which to JOIN.
+   *
+   * This property is a nested array. Each entry is an array representing
+   * a single table against which to join. The structure of each entry is:
+   *
+   * array(
+   *   'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER),
+   *   'table' => $table,
+   *   'alias' => $alias_of_the_table,
+   *   'condition' => $condition_clause_on_which_to_join,
+   *   'arguments' => $array_of_arguments_for_placeholders_in_the condition.
+   *   'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise.
+   * )
+   *
+   * If $table is a string, it is taken as the name of a table. If it is
+   * a Select query object, it is taken as a subquery.
+   *
+   * @var array
+   */
+  protected $tables = array();
+
+  /**
+   * The fields by which to order this query.
+   *
+   * This is an associative array. The keys are the fields to order, and the value
+   * is the direction to order, either ASC or DESC.
+   *
+   * @var array
+   */
+  protected $order = array();
+
+  /**
+   * The fields by which to group.
+   *
+   * @var array
+   */
+  protected $group = array();
+
+  /**
+   * The conditional object for the WHERE clause.
+   *
+   * @var Drupal\Core\Database\Query\Condition
+   */
+  protected $where;
+
+  /**
+   * The conditional object for the HAVING clause.
+   *
+   * @var Drupal\Core\Database\Query\Condition
+   */
+  protected $having;
+
+  /**
+   * Whether or not this query should be DISTINCT
+   *
+   * @var boolean
+   */
+  protected $distinct = FALSE;
+
+  /**
+   * The range limiters for this query.
+   *
+   * @var array
+   */
+  protected $range;
+
+  /**
+   * An array whose elements specify a query to UNION, and the UNION type. The
+   * 'type' key may be '', 'ALL', or 'DISTINCT' to represent a 'UNION',
+   * 'UNION ALL', or 'UNION DISTINCT' statement, respectively.
+   *
+   * All entries in this array will be applied from front to back, with the
+   * first query to union on the right of the original query, the second union
+   * to the right of the first, etc.
+   *
+   * @var array
+   */
+  protected $union = array();
+
+  /**
+   * Indicates if preExecute() has already been called.
+   * @var boolean
+   */
+  protected $prepared = FALSE;
+
+  /**
+   * The FOR UPDATE status
+   */
+  protected $forUpdate = FALSE;
+
+  public function __construct($table, $alias = NULL, Connection $connection, $options = array()) {
+    $options['return'] = Database::RETURN_STATEMENT;
+    parent::__construct($connection, $options);
+    $this->where = new Condition('AND');
+    $this->having = new Condition('AND');
+    $this->addJoin(NULL, $table, $alias);
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\AlterableInterface. */
+
+  public function addTag($tag) {
+    $this->alterTags[$tag] = 1;
+    return $this;
+  }
+
+  public function hasTag($tag) {
+    return isset($this->alterTags[$tag]);
+  }
+
+  public function hasAllTags() {
+    return !(boolean)array_diff(func_get_args(), array_keys($this->alterTags));
+  }
+
+  public function hasAnyTag() {
+    return (boolean)array_intersect(func_get_args(), array_keys($this->alterTags));
+  }
+
+  public function addMetaData($key, $object) {
+    $this->alterMetaData[$key] = $object;
+    return $this;
+  }
+
+  public function getMetaData($key) {
+    return isset($this->alterMetaData[$key]) ? $this->alterMetaData[$key] : NULL;
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */
+
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->where->condition($field, $value, $operator);
+    return $this;
+  }
+
+  public function &conditions() {
+    return $this->where->conditions();
+  }
+
+  public function arguments() {
+    if (!$this->compiled()) {
+      return NULL;
+    }
+
+    $args = $this->where->arguments() + $this->having->arguments();
+
+    foreach ($this->tables as $table) {
+      if ($table['arguments']) {
+        $args += $table['arguments'];
+      }
+      // If this table is a subquery, grab its arguments recursively.
+      if ($table['table'] instanceof SelectInterface) {
+        $args += $table['table']->arguments();
+      }
+    }
+
+    foreach ($this->expressions as $expression) {
+      if ($expression['arguments']) {
+        $args += $expression['arguments'];
+      }
+    }
+
+    // If there are any dependent queries to UNION,
+    // incorporate their arguments recursively.
+    foreach ($this->union as $union) {
+      $args += $union['query']->arguments();
+    }
+
+    return $args;
+  }
+
+  public function where($snippet, $args = array()) {
+    $this->where->where($snippet, $args);
+    return $this;
+  }
+
+  public function isNull($field) {
+    $this->where->isNull($field);
+    return $this;
+  }
+
+  public function isNotNull($field) {
+    $this->where->isNotNull($field);
+    return $this;
+  }
+
+  public function exists(SelectInterface $select) {
+    $this->where->exists($select);
+    return $this;
+  }
+
+  public function notExists(SelectInterface $select) {
+    $this->where->notExists($select);
+    return $this;
+  }
+
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    $this->where->compile($connection, $queryPlaceholder);
+    $this->having->compile($connection, $queryPlaceholder);
+
+    foreach ($this->tables as $table) {
+      // If this table is a subquery, compile it recursively.
+      if ($table['table'] instanceof SelectInterface) {
+        $table['table']->compile($connection, $queryPlaceholder);
+      }
+    }
+
+    // If there are any dependent queries to UNION, compile it recursively.
+    foreach ($this->union as $union) {
+      $union['query']->compile($connection, $queryPlaceholder);
+    }
+  }
+
+  public function compiled() {
+    if (!$this->where->compiled() || !$this->having->compiled()) {
+      return FALSE;
+    }
+
+    foreach ($this->tables as $table) {
+      // If this table is a subquery, check its status recursively.
+      if ($table['table'] instanceof SelectInterface) {
+        if (!$table['table']->compiled()) {
+          return FALSE;
+        }
+      }
+    }
+
+    foreach ($this->union as $union) {
+      if (!$union['query']->compiled()) {
+        return FALSE;
+      }
+    }
+
+    return TRUE;
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the HAVING clause. */
+
+  public function havingCondition($field, $value = NULL, $operator = NULL) {
+    $this->having->condition($field, $value, $operator);
+    return $this;
+  }
+
+  public function &havingConditions() {
+    return $this->having->conditions();
+  }
+
+  public function havingArguments() {
+    return $this->having->arguments();
+  }
+
+  public function having($snippet, $args = array()) {
+    $this->having->where($snippet, $args);
+    return $this;
+  }
+
+  public function havingCompile(Connection $connection) {
+    return $this->having->compile($connection, $this);
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ExtendableInterface. */
+
+  public function extend($extender_name) {
+    $override_class = $extender_name . '_' . $this->connection->driver();
+    if (class_exists($override_class)) {
+      $extender_name = $override_class;
+    }
+    return new $extender_name($this, $this->connection);
+  }
+
+  public function havingIsNull($field) {
+    $this->having->isNull($field);
+    return $this;
+  }
+
+  public function havingIsNotNull($field) {
+    $this->having->isNotNull($field);
+    return $this;
+  }
+
+  public function havingExists(SelectInterface $select) {
+    $this->having->exists($select);
+    return $this;
+  }
+
+  public function havingNotExists(SelectInterface $select) {
+    $this->having->notExists($select);
+    return $this;
+  }
+
+  public function forUpdate($set = TRUE) {
+    if (isset($set)) {
+      $this->forUpdate = $set;
+    }
+    return $this;
+  }
+
+  /* Alter accessors to expose the query data to alter hooks. */
+
+  public function &getFields() {
+    return $this->fields;
+  }
+
+  public function &getExpressions() {
+    return $this->expressions;
+  }
+
+  public function &getOrderBy() {
+    return $this->order;
+  }
+
+  public function &getGroupBy() {
+    return $this->group;
+  }
+
+  public function &getTables() {
+    return $this->tables;
+  }
+
+  public function &getUnion() {
+    return $this->union;
+  }
+
+  public function getArguments(PlaceholderInterface $queryPlaceholder = NULL) {
+    if (!isset($queryPlaceholder)) {
+      $queryPlaceholder = $this;
+    }
+    $this->compile($this->connection, $queryPlaceholder);
+    return $this->arguments();
+  }
+
+  /**
+   * Indicates if preExecute() has already been called on that object.
+   */
+  public function isPrepared() {
+    return $this->prepared;
+  }
+
+  /**
+   * Generic preparation and validation for a SELECT query.
+   *
+   * @return
+   *   TRUE if the validation was successful, FALSE if not.
+   */
+  public function preExecute(SelectInterface $query = NULL) {
+    // If no query object is passed in, use $this.
+    if (!isset($query)) {
+      $query = $this;
+    }
+
+    // Only execute this once.
+    if ($query->isPrepared()) {
+      return TRUE;
+    }
+
+    // Modules may alter all queries or only those having a particular tag.
+    if (isset($this->alterTags)) {
+      $hooks = array('query');
+      foreach ($this->alterTags as $tag => $value) {
+        $hooks[] = 'query_' . $tag;
+      }
+      drupal_alter($hooks, $query);
+    }
+
+    $this->prepared = TRUE;
+
+    // Now also prepare any sub-queries.
+    foreach ($this->tables as $table) {
+      if ($table['table'] instanceof SelectInterface) {
+        $table['table']->preExecute();
+      }
+    }
+
+    foreach ($this->union as $union) {
+      $union['query']->preExecute();
+    }
+
+    return $this->prepared;
+  }
+
+  public function execute() {
+    // If validation fails, simply return NULL.
+    // Note that validation routines in preExecute() may throw exceptions instead.
+    if (!$this->preExecute()) {
+      return NULL;
+    }
+
+    $args = $this->getArguments();
+    return $this->connection->query((string) $this, $args, $this->queryOptions);
+  }
+
+  public function distinct($distinct = TRUE) {
+    $this->distinct = $distinct;
+    return $this;
+  }
+
+  public function addField($table_alias, $field, $alias = NULL) {
+    // If no alias is specified, first try the field name itself.
+    if (empty($alias)) {
+      $alias = $field;
+    }
+
+    // If that's already in use, try the table name and field name.
+    if (!empty($this->fields[$alias])) {
+      $alias = $table_alias . '_' . $field;
+    }
+
+    // If that is already used, just add a counter until we find an unused alias.
+    $alias_candidate = $alias;
+    $count = 2;
+    while (!empty($this->fields[$alias_candidate])) {
+      $alias_candidate = $alias . '_' . $count++;
+    }
+    $alias = $alias_candidate;
+
+    $this->fields[$alias] = array(
+      'field' => $field,
+      'table' => $table_alias,
+      'alias' => $alias,
+    );
+
+    return $alias;
+  }
+
+  public function fields($table_alias, array $fields = array()) {
+
+    if ($fields) {
+      foreach ($fields as $field) {
+        // We don't care what alias was assigned.
+        $this->addField($table_alias, $field);
+      }
+    }
+    else {
+      // We want all fields from this table.
+      $this->tables[$table_alias]['all_fields'] = TRUE;
+    }
+
+    return $this;
+  }
+
+  public function addExpression($expression, $alias = NULL, $arguments = array()) {
+    if (empty($alias)) {
+      $alias = 'expression';
+    }
+
+    $alias_candidate = $alias;
+    $count = 2;
+    while (!empty($this->expressions[$alias_candidate])) {
+      $alias_candidate = $alias . '_' . $count++;
+    }
+    $alias = $alias_candidate;
+
+    $this->expressions[$alias] = array(
+      'expression' => $expression,
+      'alias' => $alias,
+      'arguments' => $arguments,
+    );
+
+    return $alias;
+  }
+
+  public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
+  }
+
+  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
+  }
+
+  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->addJoin('LEFT OUTER', $table, $alias, $condition, $arguments);
+  }
+
+  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->addJoin('RIGHT OUTER', $table, $alias, $condition, $arguments);
+  }
+
+  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
+
+    if (empty($alias)) {
+      if ($table instanceof SelectInterface) {
+        $alias = 'subquery';
+      }
+      else {
+        $alias = $table;
+      }
+    }
+
+    $alias_candidate = $alias;
+    $count = 2;
+    while (!empty($this->tables[$alias_candidate])) {
+      $alias_candidate = $alias . '_' . $count++;
+    }
+    $alias = $alias_candidate;
+
+    if (is_string($condition)) {
+      $condition = str_replace('%alias', $alias, $condition);
+    }
+
+    $this->tables[$alias] = array(
+      'join type' => $type,
+      'table' => $table,
+      'alias' => $alias,
+      'condition' => $condition,
+      'arguments' => $arguments,
+    );
+
+    return $alias;
+  }
+
+  public function orderBy($field, $direction = 'ASC') {
+    $this->order[$field] = $direction;
+    return $this;
+  }
+
+  public function orderRandom() {
+    $alias = $this->addExpression('RAND()', 'random_field');
+    $this->orderBy($alias);
+    return $this;
+  }
+
+  public function range($start = NULL, $length = NULL) {
+    $this->range = func_num_args() ? array('start' => $start, 'length' => $length) : array();
+    return $this;
+  }
+
+  public function union(SelectInterface $query, $type = '') {
+    // Handle UNION aliasing.
+    switch ($type) {
+      // Fold UNION DISTINCT to UNION for better cross database support.
+      case 'DISTINCT':
+      case '':
+        $type = 'UNION';
+        break;
+
+      case 'ALL':
+        $type = 'UNION ALL';
+      default:
+    }
+
+    $this->union[] = array(
+      'type' => $type,
+      'query' => $query,
+    );
+
+    return $this;
+  }
+
+  public function groupBy($field) {
+    $this->group[$field] = $field;
+    return $this;
+  }
+
+  public function countQuery() {
+    // Create our new query object that we will mutate into a count query.
+    $count = clone($this);
+
+    $group_by = $count->getGroupBy();
+    $having = $count->havingConditions();
+
+    if (!$count->distinct && !isset($having[0])) {
+      // When not executing a distinct query, we can zero-out existing fields
+      // and expressions that are not used by a GROUP BY or HAVING. Fields
+      // listed in a GROUP BY or HAVING clause need to be present in the
+      // query.
+      $fields =& $count->getFields();
+      foreach (array_keys($fields) as $field) {
+        if (empty($group_by[$field])) {
+          unset($fields[$field]);
+        }
+      }
+
+      $expressions =& $count->getExpressions();
+      foreach (array_keys($expressions) as $field) {
+        if (empty($group_by[$field])) {
+          unset($expressions[$field]);
+        }
+      }
+
+      // Also remove 'all_fields' statements, which are expanded into tablename.*
+      // when the query is executed.
+      foreach ($count->tables as $alias => &$table) {
+        unset($table['all_fields']);
+      }
+    }
+
+    // If we've just removed all fields from the query, make sure there is at
+    // least one so that the query still runs.
+    $count->addExpression('1');
+
+    // Ordering a count query is a waste of cycles, and breaks on some
+    // databases anyway.
+    $orders = &$count->getOrderBy();
+    $orders = array();
+
+    if ($count->distinct && !empty($group_by)) {
+      // If the query is distinct and contains a GROUP BY, we need to remove the
+      // distinct because SQL99 does not support counting on distinct multiple fields.
+      $count->distinct = FALSE;
+    }
+
+    $query = $this->connection->select($count);
+    $query->addExpression('COUNT(*)');
+
+    return $query;
+  }
+
+  public function __toString() {
+    // For convenience, we compile the query ourselves if the caller forgot
+    // to do it. This allows constructs like "(string) $query" to work. When
+    // the query will be executed, it will be recompiled using the proper
+    // placeholder generator anyway.
+    if (!$this->compiled()) {
+      $this->compile($this->connection, $this);
+    }
+
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    // SELECT
+    $query = $comments . 'SELECT ';
+    if ($this->distinct) {
+      $query .= 'DISTINCT ';
+    }
+
+    // FIELDS and EXPRESSIONS
+    $fields = array();
+    foreach ($this->tables as $alias => $table) {
+      if (!empty($table['all_fields'])) {
+        $fields[] = $this->connection->escapeTable($alias) . '.*';
+      }
+    }
+    foreach ($this->fields as $alias => $field) {
+      // Always use the AS keyword for field aliases, as some
+      // databases require it (e.g., PostgreSQL).
+      $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
+    }
+    foreach ($this->expressions as $alias => $expression) {
+      $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
+    }
+    $query .= implode(', ', $fields);
+
+
+    // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
+    $query .= "\nFROM ";
+    foreach ($this->tables as $alias => $table) {
+      $query .= "\n";
+      if (isset($table['join type'])) {
+        $query .= $table['join type'] . ' JOIN ';
+      }
+
+      // If the table is a subquery, compile it and integrate it into this query.
+      if ($table['table'] instanceof SelectInterface) {
+        // Run preparation steps on this sub-query before converting to string.
+        $subquery = $table['table'];
+        $subquery->preExecute();
+        $table_string = '(' . (string) $subquery . ')';
+      }
+      else {
+        $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
+      }
+
+      // Don't use the AS keyword for table aliases, as some
+      // databases don't support it (e.g., Oracle).
+      $query .=  $table_string . ' ' . $this->connection->escapeTable($table['alias']);
+
+      if (!empty($table['condition'])) {
+        $query .= ' ON ' . $table['condition'];
+      }
+    }
+
+    // WHERE
+    if (count($this->where)) {
+      // There is an implicit string cast on $this->condition.
+      $query .= "\nWHERE " . $this->where;
+    }
+
+    // GROUP BY
+    if ($this->group) {
+      $query .= "\nGROUP BY " . implode(', ', $this->group);
+    }
+
+    // HAVING
+    if (count($this->having)) {
+      // There is an implicit string cast on $this->having.
+      $query .= "\nHAVING " . $this->having;
+    }
+
+    // ORDER BY
+    if ($this->order) {
+      $query .= "\nORDER BY ";
+      $fields = array();
+      foreach ($this->order as $field => $direction) {
+        $fields[] = $field . ' ' . $direction;
+      }
+      $query .= implode(', ', $fields);
+    }
+
+    // RANGE
+    // There is no universal SQL standard for handling range or limit clauses.
+    // Fortunately, all core-supported databases use the same range syntax.
+    // Databases that need a different syntax can override this method and
+    // do whatever alternate logic they need to.
+    if (!empty($this->range)) {
+      $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
+    }
+
+    // UNION is a little odd, as the select queries to combine are passed into
+    // this query, but syntactically they all end up on the same level.
+    if ($this->union) {
+      foreach ($this->union as $union) {
+        $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
+      }
+    }
+
+    if ($this->forUpdate) {
+      $query .= ' FOR UPDATE';
+    }
+
+    return $query;
+  }
+
+  public function __clone() {
+    // On cloning, also clone the dependent objects. However, we do not
+    // want to clone the database connection object as that would duplicate the
+    // connection itself.
+
+    $this->where = clone($this->where);
+    $this->having = clone($this->having);
+    foreach ($this->union as $key => $aggregate) {
+      $this->union[$key]['query'] = clone($aggregate['query']);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/SelectExtender.php b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f27d1b4b3b156a831af95c5cf2210b771ee053a
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
@@ -0,0 +1,330 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\SelectExtender
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Connection;
+
+/**
+ * The base extender class for Select queries.
+ */
+class SelectExtender implements SelectInterface {
+
+  /**
+   * The Select query object we are extending/decorating.
+   *
+   * @var Drupal\Core\Database\Query\SelectInterface
+   */
+  protected $query;
+
+  /**
+   * The connection object on which to run this query.
+   *
+   * @var DatabaseConnection
+   */
+  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) {
+    $this->query->addTag($tag);
+    return $this;
+  }
+
+  public function hasTag($tag) {
+    return $this->query->hasTag($tag);
+  }
+
+  public function hasAllTags() {
+    return call_user_func_array(array($this->query, 'hasAllTags'), func_get_args());
+  }
+
+  public function hasAnyTag() {
+    return call_user_func_array(array($this->query, 'hasAnyTags'), func_get_args());
+  }
+
+  public function addMetaData($key, $object) {
+    $this->query->addMetaData($key, $object);
+    return $this;
+  }
+
+  public function getMetaData($key) {
+    return $this->query->getMetaData($key);
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */
+
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->query->condition($field, $value, $operator);
+    return $this;
+  }
+
+  public function &conditions() {
+    return $this->query->conditions();
+  }
+
+  public function arguments() {
+    return $this->query->arguments();
+  }
+
+  public function where($snippet, $args = array()) {
+    $this->query->where($snippet, $args);
+    return $this;
+  }
+
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->query->compile($connection, $queryPlaceholder);
+  }
+
+  public function compiled() {
+    return $this->query->compiled();
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the HAVING clause. */
+
+  public function havingCondition($field, $value = NULL, $operator = '=') {
+    $this->query->havingCondition($field, $value, $operator);
+    return $this;
+  }
+
+  public function &havingConditions() {
+    return $this->query->havingConditions();
+  }
+
+  public function havingArguments() {
+    return $this->query->havingArguments();
+  }
+
+  public function having($snippet, $args = array()) {
+    $this->query->having($snippet, $args);
+    return $this;
+  }
+
+  public function havingCompile(Connection $connection) {
+    return $this->query->havingCompile($connection);
+  }
+
+  /* Implementations of Drupal\Core\Database\Query\ExtendableInterface. */
+
+  public function extend($extender_name) {
+    $class = $this->connection->getDriverClass($extender_name);
+    return new $class($this, $this->connection);
+  }
+
+  /* Alter accessors to expose the query data to alter hooks. */
+
+  public function &getFields() {
+    return $this->query->getFields();
+  }
+
+  public function &getExpressions() {
+    return $this->query->getExpressions();
+  }
+
+  public function &getOrderBy() {
+    return $this->query->getOrderBy();
+  }
+
+  public function &getGroupBy() {
+    return $this->query->getGroupBy();
+  }
+
+  public function &getTables() {
+    return $this->query->getTables();
+  }
+
+  public function &getUnion() {
+    return $this->query->getUnion();
+  }
+
+  public function getArguments(PlaceholderInterface $queryPlaceholder = NULL) {
+    return $this->query->getArguments($queryPlaceholder);
+  }
+
+  public function isPrepared() {
+    return $this->query->isPrepared();
+  }
+
+  public function preExecute(SelectInterface $query = NULL) {
+    // If no query object is passed in, use $this.
+    if (!isset($query)) {
+      $query = $this;
+    }
+
+    return $this->query->preExecute($query);
+  }
+
+  public function execute() {
+    // By calling preExecute() here, we force it to preprocess the extender
+    // object rather than just the base query object.  That means
+    // hook_query_alter() gets access to the extended object.
+    if (!$this->preExecute($this)) {
+      return NULL;
+    }
+
+    return $this->query->execute();
+  }
+
+  public function distinct($distinct = TRUE) {
+    $this->query->distinct($distinct);
+    return $this;
+  }
+
+  public function addField($table_alias, $field, $alias = NULL) {
+    return $this->query->addField($table_alias, $field, $alias);
+  }
+
+  public function fields($table_alias, array $fields = array()) {
+    $this->query->fields($table_alias, $fields);
+    return $this;
+  }
+
+  public function addExpression($expression, $alias = NULL, $arguments = array()) {
+    return $this->query->addExpression($expression, $alias, $arguments);
+  }
+
+  public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->query->join($table, $alias, $condition, $arguments);
+  }
+
+  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->query->innerJoin($table, $alias, $condition, $arguments);
+  }
+
+  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->query->leftJoin($table, $alias, $condition, $arguments);
+  }
+
+  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->query->rightJoin($table, $alias, $condition, $arguments);
+  }
+
+  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
+    return $this->query->addJoin($type, $table, $alias, $condition, $arguments);
+  }
+
+  public function orderBy($field, $direction = 'ASC') {
+    $this->query->orderBy($field, $direction);
+    return $this;
+  }
+
+  public function orderRandom() {
+    $this->query->orderRandom();
+    return $this;
+  }
+
+  public function range($start = NULL, $length = NULL) {
+    $this->query->range($start, $length);
+    return $this;
+  }
+
+  public function union(SelectInterface $query, $type = '') {
+    $this->query->union($query, $type);
+    return $this;
+  }
+
+  public function groupBy($field) {
+    $this->query->groupBy($field);
+    return $this;
+  }
+
+  public function forUpdate($set = TRUE) {
+    $this->query->forUpdate($set);
+    return $this;
+  }
+
+  public function countQuery() {
+    return $this->query->countQuery();
+  }
+
+  function isNull($field) {
+    $this->query->isNull($field);
+    return $this;
+  }
+
+  function isNotNull($field) {
+    $this->query->isNotNull($field);
+    return $this;
+  }
+
+  public function exists(SelectInterface $select) {
+    $this->query->exists($select);
+    return $this;
+  }
+
+  public function notExists(SelectInterface $select) {
+    $this->query->notExists($select);
+    return $this;
+  }
+
+  public function __toString() {
+    return (string) $this->query;
+  }
+
+  public function __clone() {
+    $this->uniqueIdentifier = uniqid('', TRUE);
+
+    // We need to deep-clone the query we're wrapping, which in turn may
+    // deep-clone other objects.  Exciting!
+    $this->query = clone($this->query);
+  }
+
+  /**
+   * Magic override for undefined methods.
+   *
+   * If one extender extends another extender, then methods in the inner extender
+   * will not be exposed on the outer extender.  That's because we cannot know
+   * in advance what those methods will be, so we cannot provide wrapping
+   * implementations as we do above.  Instead, we use this slower catch-all method
+   * to handle any additional methods.
+   */
+  public function __call($method, $args) {
+    $return = call_user_func_array(array($this->query, $method), $args);
+
+    // Some methods will return the called object as part of a fluent interface.
+    // Others will return some useful value.  If it's a value, then the caller
+    // probably wants that value.  If it's the called object, then we instead
+    // return this object.  That way we don't "lose" an extender layer when
+    // chaining methods together.
+    if ($return instanceof SelectInterface) {
+      return $this;
+    }
+    else {
+      return $return;
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/SelectInterface.php b/core/lib/Drupal/Core/Database/Query/SelectInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..779e69d2f74f397d5b703b1d4dacf181a0c57013
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/SelectInterface.php
@@ -0,0 +1,504 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\SelectInterface
+ */
+
+namespace Drupal\Core\Database\Query;
+
+/**
+ * Interface definition for a Select Query object.
+ */
+interface SelectInterface extends ConditionInterface, AlterableInterface, ExtendableInterface, PlaceholderInterface {
+
+  /* Alter accessors to expose the query data to alter hooks. */
+
+  /**
+   * Returns a reference to the fields array for this query.
+   *
+   * Because this method returns by reference, alter hooks may edit the fields
+   * array directly to make their changes. If just adding fields, however, the
+   * use of addField() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getFields();
+   * @endcode
+   *
+   * @return
+   *   A reference to the fields array structure.
+   */
+  public function &getFields();
+
+  /**
+   * Returns a reference to the expressions array for this query.
+   *
+   * Because this method returns by reference, alter hooks may edit the expressions
+   * array directly to make their changes. If just adding expressions, however, the
+   * use of addExpression() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getExpressions();
+   * @endcode
+   *
+   * @return
+   *   A reference to the expression array structure.
+   */
+  public function &getExpressions();
+
+  /**
+   * Returns a reference to the order by array for this query.
+   *
+   * Because this method returns by reference, alter hooks may edit the order-by
+   * array directly to make their changes. If just adding additional ordering
+   * fields, however, the use of orderBy() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getOrderBy();
+   * @endcode
+   *
+   * @return
+   *   A reference to the expression array structure.
+   */
+  public function &getOrderBy();
+
+  /**
+   * Returns a reference to the group-by array for this query.
+   *
+   * Because this method returns by reference, alter hooks may edit the group-by
+   * array directly to make their changes. If just adding additional grouping
+   * fields, however, the use of groupBy() is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getGroupBy();
+   * @endcode
+   *
+   * @return
+   *   A reference to the group-by array structure.
+   */
+  public function &getGroupBy();
+
+  /**
+   * Returns a reference to the tables array for this query.
+   *
+   * Because this method returns by reference, alter hooks may edit the tables
+   * array directly to make their changes. If just adding tables, however, the
+   * use of the join() methods is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getTables();
+   * @endcode
+   *
+   * @return
+   *   A reference to the tables array structure.
+   */
+  public function &getTables();
+
+  /**
+   * Returns a reference to the union queries for this query. This include
+   * queries for UNION, UNION ALL, and UNION DISTINCT.
+   *
+   * Because this method returns by reference, alter hooks may edit the tables
+   * array directly to make their changes. If just adding union queries,
+   * however, the use of the union() method is preferred.
+   *
+   * Note that this method must be called by reference as well:
+   *
+   * @code
+   * $fields =& $query->getUnion();
+   * @endcode
+   *
+   * @return
+   *   A reference to the union query array structure.
+   */
+  public function &getUnion();
+
+  /**
+   * Compiles and returns an associative array of the arguments for this prepared statement.
+   *
+   * @param $queryPlaceholder
+   *   When collecting the arguments of a subquery, the main placeholder
+   *   object should be passed as this parameter.
+   *
+   * @return
+   *   An associative array of all placeholder arguments for this query.
+   */
+  public function getArguments(PlaceholderInterface $queryPlaceholder = NULL);
+
+  /* Query building operations */
+
+  /**
+   * Sets this query to be DISTINCT.
+   *
+   * @param $distinct
+   *   TRUE to flag this query DISTINCT, FALSE to disable it.
+   * @return SelectQueryInterface
+   *   The called object.
+   */
+  public function distinct($distinct = TRUE);
+
+  /**
+   * Adds a field to the list to be SELECTed.
+   *
+   * @param $table_alias
+   *   The name of the table from which the field comes, as an alias. Generally
+   *   you will want to use the return value of join() here to ensure that it is
+   *   valid.
+   * @param $field
+   *   The name of the field.
+   * @param $alias
+   *   The alias for this field. If not specified, one will be generated
+   *   automatically based on the $table_alias and $field. The alias will be
+   *   checked for uniqueness, so the requested alias may not be the alias
+   *   that is assigned in all cases.
+   * @return
+   *   The unique alias that was assigned for this field.
+   */
+  public function addField($table_alias, $field, $alias = NULL);
+
+  /**
+   * Add multiple fields from the same table to be SELECTed.
+   *
+   * This method does not return the aliases set for the passed fields. In the
+   * majority of cases that is not a problem, as the alias will be the field
+   * name. However, if you do need to know the alias you can call getFields()
+   * and examine the result to determine what alias was created. Alternatively,
+   * simply use addField() for the few fields you care about and this method for
+   * the rest.
+   *
+   * @param $table_alias
+   *   The name of the table from which the field comes, as an alias. Generally
+   *   you will want to use the return value of join() here to ensure that it is
+   *   valid.
+   * @param $fields
+   *   An indexed array of fields present in the specified table that should be
+   *   included in this query. If not specified, $table_alias.* will be generated
+   *   without any aliases.
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object.
+   */
+  public function fields($table_alias, array $fields = array());
+
+  /**
+   * Adds an expression to the list of "fields" to be SELECTed.
+   *
+   * An expression can be any arbitrary string that is valid SQL. That includes
+   * various functions, which may in some cases be database-dependent. This
+   * method makes no effort to correct for database-specific functions.
+   *
+   * @param $expression
+   *   The expression string. May contain placeholders.
+   * @param $alias
+   *   The alias for this expression. If not specified, one will be generated
+   *   automatically in the form "expression_#". The alias will be checked for
+   *   uniqueness, so the requested alias may not be the alias that is assigned
+   *   in all cases.
+   * @param $arguments
+   *   Any placeholder arguments needed for this expression.
+   * @return
+   *   The unique alias that was assigned for this expression.
+   */
+  public function addExpression($expression, $alias = NULL, $arguments = array());
+
+  /**
+   * Default Join against another table in the database.
+   *
+   * This method is a convenience method for innerJoin().
+   *
+   * @param $table
+   *   The table against which to join.
+   * @param $alias
+   *   The alias for the table. In most cases this should be the first letter
+   *   of the table, or the first letter of each "word" in the table.
+   * @param $condition
+   *   The condition on which to join this table. If the join requires values,
+   *   this clause should use a named placeholder and the value or values to
+   *   insert should be passed in the 4th parameter. For the first table joined
+   *   on a query, this value is ignored as the first table is taken as the base
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
+   * @param $arguments
+   *   An array of arguments to replace into the $condition of this join.
+   * @return
+   *   The unique alias that was assigned for this table.
+   */
+  public function join($table, $alias = NULL, $condition = NULL, $arguments = array());
+
+  /**
+   * Inner Join against another table in the database.
+   *
+   * @param $table
+   *   The table against which to join.
+   * @param $alias
+   *   The alias for the table. In most cases this should be the first letter
+   *   of the table, or the first letter of each "word" in the table.
+   * @param $condition
+   *   The condition on which to join this table. If the join requires values,
+   *   this clause should use a named placeholder and the value or values to
+   *   insert should be passed in the 4th parameter. For the first table joined
+   *   on a query, this value is ignored as the first table is taken as the base
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
+   * @param $arguments
+   *   An array of arguments to replace into the $condition of this join.
+   * @return
+   *   The unique alias that was assigned for this table.
+   */
+  public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
+
+  /**
+   * Left Outer Join against another table in the database.
+   *
+   * @param $table
+   *   The table against which to join.
+   * @param $alias
+   *   The alias for the table. In most cases this should be the first letter
+   *   of the table, or the first letter of each "word" in the table.
+   * @param $condition
+   *   The condition on which to join this table. If the join requires values,
+   *   this clause should use a named placeholder and the value or values to
+   *   insert should be passed in the 4th parameter. For the first table joined
+   *   on a query, this value is ignored as the first table is taken as the base
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
+   * @param $arguments
+   *   An array of arguments to replace into the $condition of this join.
+   * @return
+   *   The unique alias that was assigned for this table.
+   */
+  public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
+
+  /**
+   * Right Outer Join against another table in the database.
+   *
+   * @param $table
+   *   The table against which to join.
+   * @param $alias
+   *   The alias for the table. In most cases this should be the first letter
+   *   of the table, or the first letter of each "word" in the table.
+   * @param $condition
+   *   The condition on which to join this table. If the join requires values,
+   *   this clause should use a named placeholder and the value or values to
+   *   insert should be passed in the 4th parameter. For the first table joined
+   *   on a query, this value is ignored as the first table is taken as the base
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
+   * @param $arguments
+   *   An array of arguments to replace into the $condition of this join.
+   * @return
+   *   The unique alias that was assigned for this table.
+   */
+  public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
+
+  /**
+   * Join against another table in the database.
+   *
+   * This method does the "hard" work of queuing up a table to be joined against.
+   * In some cases, that may include dipping into the Schema API to find the necessary
+   * fields on which to join.
+   *
+   * @param $type
+   *   The type of join. Typically one one of INNER, LEFT OUTER, and RIGHT OUTER.
+   * @param $table
+   *   The table against which to join. May be a string or another SelectQuery
+   *   object. If a query object is passed, it will be used as a subselect.
+   * @param $alias
+   *   The alias for the table. In most cases this should be the first letter
+   *   of the table, or the first letter of each "word" in the table. If omitted,
+   *   one will be dynamically generated.
+   * @param $condition
+   *   The condition on which to join this table. If the join requires values,
+   *   this clause should use a named placeholder and the value or values to
+   *   insert should be passed in the 4th parameter. For the first table joined
+   *   on a query, this value is ignored as the first table is taken as the base
+   *   table. The token %alias can be used in this string to be replaced with
+   *   the actual alias. This is useful when $alias is modified by the database
+   *   system, for example, when joining the same table more than once.
+   * @param $arguments
+   *   An array of arguments to replace into the $condition of this join.
+   * @return
+   *   The unique alias that was assigned for this table.
+   */
+  public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array());
+
+  /**
+   * Orders the result set by a given field.
+   *
+   * If called multiple times, the query will order by each specified field in the
+   * order this method is called.
+   *
+   * If the query uses DISTINCT or GROUP BY conditions, fields or expressions
+   * that are used for the order must be selected to be compatible with some
+   * databases like PostgreSQL. The PostgreSQL driver can handle simple cases
+   * automatically but it is suggested to explicitly specify them. Additionally,
+   * when ordering on an alias, the alias must be added before orderBy() is
+   * called.
+   *
+   * @param $field
+   *   The field on which to order.
+   * @param $direction
+   *   The direction to sort. Legal values are "ASC" and "DESC".
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object.
+   */
+  public function orderBy($field, $direction = 'ASC');
+
+  /**
+   * Orders the result set by a random value.
+   *
+   * This may be stacked with other orderBy() calls. If so, the query will order
+   * by each specified field, including this one, in the order called. Although
+   * this method may be called multiple times on the same query, doing so
+   * is not particularly useful.
+   *
+   * Note: The method used by most drivers may not scale to very large result
+   * sets. If you need to work with extremely large data sets, you may create
+   * your own database driver by subclassing off of an existing driver and
+   * implementing your own randomization mechanism. See
+   *
+   * http://jan.kneschke.de/projects/mysql/order-by-rand/
+   *
+   * for an example of such an alternate sorting mechanism.
+   *
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object
+   */
+  public function orderRandom();
+
+  /**
+   * Restricts a query to a given range in the result set.
+   *
+   * If this method is called with no parameters, will remove any range
+   * directives that have been set.
+   *
+   * @param $start
+   *   The first record from the result set to return. If NULL, removes any
+   *   range directives that are set.
+   * @param $length
+   *   The number of records to return from the result set.
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object.
+   */
+  public function range($start = NULL, $length = NULL);
+
+  /**
+   * Add another Select query to UNION to this one.
+   *
+   * Union queries consist of two or more queries whose
+   * results are effectively concatenated together. Queries
+   * will be UNIONed in the order they are specified, with
+   * this object's query coming first. Duplicate columns will
+   * be discarded. All forms of UNION are supported, using
+   * the second '$type' argument.
+   *
+   * Note: All queries UNIONed together must have the same
+   * field structure, in the same order. It is up to the
+   * caller to ensure that they match properly. If they do
+   * not, an SQL syntax error will result.
+   *
+   * @param $query
+   *   The query to UNION to this query.
+   * @param $type
+   *   The type of UNION to add to the query. Defaults to plain
+   *   UNION.
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object.
+   */
+  public function union(SelectInterface $query, $type = '');
+
+  /**
+   * Groups the result set by the specified field.
+   *
+   * @param $field
+   *   The field on which to group. This should be the field as aliased.
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   The called object.
+   */
+  public function groupBy($field);
+
+  /**
+   * Get the equivalent COUNT query of this query as a new query object.
+   *
+   * @return Drupal\Core\Database\Query\SelectInterface
+   *   A new SelectQuery object with no fields or expressions besides COUNT(*).
+   */
+  public function countQuery();
+
+  /**
+   * Indicates if preExecute() has already been called on that object.
+   *
+   * @return
+   *   TRUE is this query has already been prepared, FALSE otherwise.
+   */
+  public function isPrepared();
+
+  /**
+   * Generic preparation and validation for a SELECT query.
+   *
+   * @return
+   *   TRUE if the validation was successful, FALSE if not.
+   */
+  public function preExecute(SelectInterface $query = NULL);
+
+  /**
+   * Helper function to build most common HAVING conditional clauses.
+   *
+   * This method can take a variable number of parameters. If called with two
+   * parameters, they are taken as $field and $value with $operator having a value
+   * of IN if $value is an array and = otherwise.
+   *
+   * @param $field
+   *   The name of the field to check. If you would like to add a more complex
+   *   condition involving operators or functions, use having().
+   * @param $value
+   *   The value to test the field against. In most cases, this is a scalar. For more
+   *   complex options, it is an array. The meaning of each element in the array is
+   *   dependent on the $operator.
+   * @param $operator
+   *   The comparison operator, such as =, <, or >=. It also accepts more complex
+   *   options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
+   *   = otherwise.
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function havingCondition($field, $value = NULL, $operator = NULL);
+
+  /**
+   * Clone magic method.
+   *
+   * Select queries have dependent objects that must be deep-cloned.  The
+   * connection object itself, however, should not be cloned as that would
+   * duplicate the connection itself.
+   */
+  public function __clone();
+
+  /**
+   * Add FOR UPDATE to the query.
+   *
+   * FOR UPDATE prevents the rows retrieved by the SELECT statement from being
+   * modified or deleted by other transactions until the current transaction
+   * ends. Other transactions that attempt UPDATE, DELETE, or SELECT FOR UPDATE
+   * of these rows will be blocked until the current transaction ends.
+   *
+   * @param $set
+   *   IF TRUE, FOR UPDATE will be added to the query, if FALSE then it won't.
+   *
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   The called object.
+   */
+  public function forUpdate($set = TRUE);
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Truncate.php b/core/lib/Drupal/Core/Database/Query/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..263acf50ab60a5ce875c1312b6c575ec24f76df5
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Truncate.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Truncate
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+
+/**
+ * General class for an abstracted TRUNCATE operation.
+ */
+class Truncate extends Query {
+
+  /**
+   * The table to truncate.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * Constructs a Truncate query object.
+   *
+   * @param DatabaseConnection $connection
+   *   A DatabaseConnection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
+  public function __construct(Connection $connection, $table, array $options = array()) {
+    $options['return'] = Database::RETURN_AFFECTED;
+    parent::__construct($connection, $options);
+    $this->table = $table;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->condition->compile($connection, $queryPlaceholder);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return $this->condition->compiled();
+  }
+
+  /**
+   * Executes the TRUNCATE query.
+   *
+   * @return
+   *   Return value is dependent on the database type.
+   */
+  public function execute() {
+    return $this->connection->query((string) $this, array(), $this->queryOptions);
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    return $comments . 'TRUNCATE {' . $this->connection->escapeTable($this->table) . '} ';
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Update.php b/core/lib/Drupal/Core/Database/Query/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ffdb33dba244ff239eb785379dbc7e1b15d3f51
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Query/Update.php
@@ -0,0 +1,268 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Query\Update
+ */
+
+namespace Drupal\Core\Database\Query;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+/**
+ * General class for an abstracted UPDATE operation.
+ */
+class Update extends Query implements ConditionInterface {
+
+  /**
+   * The table to update.
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * An array of fields that will be updated.
+   *
+   * @var array
+   */
+  protected $fields = array();
+
+  /**
+   * An array of values to update to.
+   *
+   * @var array
+   */
+  protected $arguments = array();
+
+  /**
+   * The condition object for this query.
+   *
+   * Condition handling is handled via composition.
+   *
+   * @var Drupal\Core\Database\Query\Condition
+   */
+  protected $condition;
+
+  /**
+   * Array of fields to update to an expression in case of a duplicate record.
+   *
+   * This variable is a nested array in the following format:
+   * @code
+   * <some field> => array(
+   *  'condition' => <condition to execute, as a string>,
+   *  'arguments' => <array of arguments for condition, or NULL for none>,
+   * );
+   * @endcode
+   *
+   * @var array
+   */
+  protected $expressionFields = array();
+
+  /**
+   * Constructs an Update query object.
+   *
+   * @param Drupal\Core\Database\Connection $connection
+   *   A Connection object.
+   * @param string $table
+   *   Name of the table to associate with this query.
+   * @param array $options
+   *   Array of database options.
+   */
+  public function __construct(Connection $connection, $table, array $options = array()) {
+    $options['return'] = Database::RETURN_AFFECTED;
+    parent::__construct($connection, $options);
+    $this->table = $table;
+
+    $this->condition = new Condition('AND');
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
+   */
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->condition->condition($field, $value, $operator);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
+   */
+  public function isNull($field) {
+    $this->condition->isNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
+   */
+  public function isNotNull($field) {
+    $this->condition->isNotNull($field);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::exists().
+   */
+  public function exists(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $select) {
+    $this->condition->notExists($select);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
+   */
+  public function &conditions() {
+    return $this->condition->conditions();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
+   */
+  public function arguments() {
+    return $this->condition->arguments();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::where().
+   */
+  public function where($snippet, $args = array()) {
+    $this->condition->where($snippet, $args);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->condition->compile($connection, $queryPlaceholder);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return $this->condition->compiled();
+  }
+
+  /**
+   * Adds a set of field->value pairs to be updated.
+   *
+   * @param $fields
+   *   An associative array of fields to write into the database. The array keys
+   *   are the field names and the values are the values to which to set them.
+   *
+   * @return Drupal\Core\Database\Query\Update
+   *   The called object.
+   */
+  public function fields(array $fields) {
+    $this->fields = $fields;
+    return $this;
+  }
+
+  /**
+   * Specifies fields to be updated as an expression.
+   *
+   * Expression fields are cases such as counter=counter+1. This method takes
+   * precedence over fields().
+   *
+   * @param $field
+   *   The field to set.
+   * @param $expression
+   *   The field will be set to the value of this expression. This parameter
+   *   may include named placeholders.
+   * @param $arguments
+   *   If specified, this is an array of key/value pairs for named placeholders
+   *   corresponding to the expression.
+   *
+   * @return Drupal\Core\Database\Query\Update
+   *   The called object.
+   */
+  public function expression($field, $expression, array $arguments = NULL) {
+    $this->expressionFields[$field] = array(
+      'expression' => $expression,
+      'arguments' => $arguments,
+    );
+
+    return $this;
+  }
+
+  /**
+   * Executes the UPDATE query.
+   *
+   * @return
+   *   The number of rows affected by the update.
+   */
+  public function execute() {
+
+    // Expressions take priority over literal fields, so we process those first
+    // and remove any literal fields that conflict.
+    $fields = $this->fields;
+    $update_values = array();
+    foreach ($this->expressionFields as $field => $data) {
+      if (!empty($data['arguments'])) {
+        $update_values += $data['arguments'];
+      }
+      unset($fields[$field]);
+    }
+
+    // Because we filter $fields the same way here and in __toString(), the
+    // placeholders will all match up properly.
+    $max_placeholder = 0;
+    foreach ($fields as $field => $value) {
+      $update_values[':db_update_placeholder_' . ($max_placeholder++)] = $value;
+    }
+
+    if (count($this->condition)) {
+      $this->condition->compile($this->connection, $this);
+      $update_values = array_merge($update_values, $this->condition->arguments());
+    }
+
+    return $this->connection->query((string) $this, $update_values, $this->queryOptions);
+  }
+
+  /**
+   * Implements PHP magic __toString method to convert the query to a string.
+   *
+   * @return string
+   *   The prepared statement.
+   */
+  public function __toString() {
+    // Create a sanitized comment string to prepend to the query.
+    $comments = $this->connection->makeComment($this->comments);
+
+    // Expressions take priority over literal fields, so we process those first
+    // and remove any literal fields that conflict.
+    $fields = $this->fields;
+    $update_fields = array();
+    foreach ($this->expressionFields as $field => $data) {
+      $update_fields[] = $field . '=' . $data['expression'];
+      unset($fields[$field]);
+    }
+
+    $max_placeholder = 0;
+    foreach ($fields as $field => $value) {
+      $update_fields[] = $field . '=:db_update_placeholder_' . ($max_placeholder++);
+    }
+
+    $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
+
+    if (count($this->condition)) {
+      $this->condition->compile($this->connection, $this);
+      // There is an implicit string cast on $this->condition.
+      $query .= "\nWHERE " . $this->condition;
+    }
+
+    return $query;
+  }
+
+}
diff --git a/core/includes/database/schema.inc b/core/lib/Drupal/Core/Database/Schema.php
similarity index 93%
rename from core/includes/database/schema.inc
rename to core/lib/Drupal/Core/Database/Schema.php
index 8905d3cecc83b860ae14d202b72e896fc7c1d088..9e2f22e38833bac3f4d6bdd61a1ab151d9294546 100644
--- a/core/includes/database/schema.inc
+++ b/core/lib/Drupal/Core/Database/Schema.php
@@ -2,10 +2,14 @@
 
 /**
  * @file
- * Generic Database schema code.
+ * Definition of Drupal\Core\Database\Schema
  */
 
-require_once __DIR__ . '/query.inc';
+namespace Drupal\Core\Database;
+
+use Drupal\Core\Database\SchemaObjectExistsException;
+use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Database\Query\PlaceholderInterface;
 
 /**
  * @defgroup schemaapi Schema API
@@ -157,7 +161,7 @@
  * @see drupal_install_schema()
  */
 
-abstract class DatabaseSchema implements QueryPlaceholderInterface {
+abstract class Schema implements PlaceholderInterface {
 
   protected $connection;
 
@@ -195,14 +199,14 @@ public function __clone() {
   }
 
   /**
-   * Implements QueryPlaceHolderInterface::uniqueIdentifier().
+   * Implements PlaceHolderInterface::uniqueIdentifier().
    */
   public function uniqueIdentifier() {
     return $this->uniqueIdentifier;
   }
 
   /**
-   * Implements QueryPlaceHolderInterface::nextPlaceholder().
+   * Implements PlaceHolderInterface::nextPlaceholder().
    */
   public function nextPlaceholder() {
     return $this->placeholder++;
@@ -279,8 +283,8 @@ function prefixNonTable($table) {
    * @param $add_prefix
    *   Boolean to indicate whether the table name needs to be prefixed.
    *
-   * @return QueryConditionInterface
-   *   A DatabaseCondition object.
+   * @return Drupal\Core\Database\Query\ConditionInterface
+   *   A Drupal\Core\Database\Query\Condition object.
    */
   protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
     $info = $this->connection->getConnectionOptions();
@@ -288,7 +292,7 @@ protected function buildTableNameCondition($table_name, $operator = '=', $add_pr
     // Retrive the table name and schema
     $table_info = $this->getPrefixInfo($table_name, $add_prefix);
 
-    $condition = new DatabaseCondition('AND');
+    $condition = new Condition('AND');
     $condition->condition('table_catalog', $info['database']);
     $condition->condition('table_schema', $table_info['schema']);
     $condition->condition('table_name', $table_info['table'], $operator);
@@ -380,9 +384,9 @@ abstract public function getFieldTypeMap();
    * @param $new_name
    *   The new name for the table.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If a table with the specified new name already exists.
    */
   abstract public function renameTable($table, $new_name);
@@ -420,9 +424,9 @@ abstract public function dropTable($table);
    *   or index including it in this array. See db_change_field() for more
    *   explanation why.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If the specified table already has a field by that name.
    */
   abstract public function addField($table, $field, $spec, $keys_new = array());
@@ -451,7 +455,7 @@ abstract public function dropField($table, $field);
    * @param $default
    *   Default value to be set. NULL for 'default NULL'.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table or field doesn't exist.
    */
   abstract public function fieldSetDefault($table, $field, $default);
@@ -464,7 +468,7 @@ abstract public function fieldSetDefault($table, $field, $default);
    * @param $field
    *   The field to be altered.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table or field doesn't exist.
    */
   abstract public function fieldSetNoDefault($table, $field);
@@ -490,9 +494,9 @@ abstract public function indexExists($table, $name);
    * @param $fields
    *   Fields for the primary key.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If the specified table already has a primary key.
    */
   abstract public function addPrimaryKey($table, $fields);
@@ -519,9 +523,9 @@ abstract public function dropPrimaryKey($table);
    * @param $fields
    *   An array of field names.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If the specified table already has a key by that name.
    */
   abstract public function addUniqueKey($table, $name, $fields);
@@ -550,9 +554,9 @@ abstract public function dropUniqueKey($table, $name);
    * @param $fields
    *   An array of field names.
    *
-   * @throws DatabaseSchemaObjectDoesNotExistException
+   * @throws Drupal\Core\Database\SchemaObjectDoesNotExistException
    *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If the specified table already has an index by that name.
    */
   abstract public function addIndex($table, $name, $fields);
@@ -646,12 +650,12 @@ abstract public function changeField($table, $field, $field_new, $spec, $keys_ne
    * @param $table
    *   A Schema API table definition array.
    *
-   * @throws DatabaseSchemaObjectExistsException
+   * @throws Drupal\Core\Database\SchemaObjectExistsException
    *   If the specified table already exists.
    */
   public function createTable($name, $table) {
     if ($this->tableExists($name)) {
-      throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
+      throw new SchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
     }
     $statements = $this->createTableSql($name, $table);
     foreach ($statements as $statement) {
@@ -699,26 +703,3 @@ public function prepareComment($comment, $length = NULL) {
     return $this->connection->quote($comment);
   }
 }
-
-/**
- * Exception thrown if an object being created already exists.
- *
- * For example, this exception should be thrown whenever there is an attempt to
- * create a new database table, field, or index that already exists in the
- * database schema.
- */
-class DatabaseSchemaObjectExistsException extends Exception {}
-
-/**
- * Exception thrown if an object being modified doesn't exist yet.
- *
- * For example, this exception should be thrown whenever there is an attempt to
- * modify a database table, field, or index that does not currently exist in
- * the database schema.
- */
-class DatabaseSchemaObjectDoesNotExistException extends Exception {}
-
-/**
- * @} End of "defgroup schemaapi".
- */
-
diff --git a/core/lib/Drupal/Core/Database/SchemaException.php b/core/lib/Drupal/Core/Database/SchemaException.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ae72b491489670a08c7c4f8f4aee961bc36414c
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/SchemaException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\SchemaException
+ */
+
+namespace Drupal\Core\Database;
+
+use RuntimeException;
+
+/**
+ * Base exception for Schema-related errors.
+ */
+class SchemaException extends RuntimeException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/SchemaObjectDoesNotExistException.php b/core/lib/Drupal/Core/Database/SchemaObjectDoesNotExistException.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac5a1f8828b958164bd34b901e1f7981e680e5fc
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/SchemaObjectDoesNotExistException.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\SchemaObjectDoesNotExistException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception thrown if an object being modified doesn't exist yet.
+ *
+ * For example, this exception should be thrown whenever there is an attempt to
+ * modify a database table, field, or index that does not currently exist in
+ * the database schema.
+ */
+class SchemaObjectDoesNotExistException extends SchemaException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/SchemaObjectExistsException.php b/core/lib/Drupal/Core/Database/SchemaObjectExistsException.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8221b5267c2f6e41e93e24a328d4746d964d1ea
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/SchemaObjectExistsException.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\SchemaObjectExistsException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception thrown if an object being created already exists.
+ *
+ * For example, this exception should be thrown whenever there is an attempt to
+ * create a new database table, field, or index that already exists in the
+ * database schema.
+ */
+class SchemaObjectExistsException extends SchemaException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/Statement.php b/core/lib/Drupal/Core/Database/Statement.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b23ed3d6a04e29f8032e6713fe0821ba1a6313d
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Statement.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\StatementBase
+ */
+
+namespace Drupal\Core\Database;
+
+use PDO;
+use PDOStatement;
+
+/**
+ * Default implementation of DatabaseStatementInterface.
+ *
+ * PDO allows us to extend the PDOStatement class to provide additional
+ * functionality beyond that offered by default. We do need extra
+ * functionality. By default, this class is not driver-specific. If a given
+ * driver needs to set a custom statement class, it may do so in its
+ * constructor.
+ *
+ * @see http://us.php.net/pdostatement
+ */
+class Statement extends PDOStatement implements StatementInterface {
+
+  /**
+   * Reference to the database connection object for this statement.
+   *
+   * The name $dbh is inherited from PDOStatement.
+   *
+   * @var DatabaseConnection
+   */
+  public $dbh;
+
+  protected function __construct($dbh) {
+    $this->dbh = $dbh;
+    $this->setFetchMode(PDO::FETCH_OBJ);
+  }
+
+  public function execute($args = array(), $options = array()) {
+    if (isset($options['fetch'])) {
+      if (is_string($options['fetch'])) {
+        // Default to an object. Note: db fields will be added to the object
+        // before the constructor is run. If you need to assign fields after
+        // the constructor is run, see http://drupal.org/node/315092.
+        $this->setFetchMode(PDO::FETCH_CLASS, $options['fetch']);
+      }
+      else {
+        $this->setFetchMode($options['fetch']);
+      }
+    }
+
+    $logger = $this->dbh->getLogger();
+    if (!empty($logger)) {
+      $query_start = microtime(TRUE);
+    }
+
+    $return = parent::execute($args);
+
+    if (!empty($logger)) {
+      $query_end = microtime(TRUE);
+      $logger->log($this, $args, $query_end - $query_start);
+    }
+
+    return $return;
+  }
+
+  public function getQueryString() {
+    return $this->queryString;
+  }
+
+  public function fetchCol($index = 0) {
+    return $this->fetchAll(PDO::FETCH_COLUMN, $index);
+  }
+
+  public function fetchAllAssoc($key, $fetch = NULL) {
+    $return = array();
+    if (isset($fetch)) {
+      if (is_string($fetch)) {
+        $this->setFetchMode(PDO::FETCH_CLASS, $fetch);
+      }
+      else {
+        $this->setFetchMode($fetch);
+      }
+    }
+
+    foreach ($this as $record) {
+      $record_key = is_object($record) ? $record->$key : $record[$key];
+      $return[$record_key] = $record;
+    }
+
+    return $return;
+  }
+
+  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
+    $return = array();
+    $this->setFetchMode(PDO::FETCH_NUM);
+    foreach ($this as $record) {
+      $return[$record[$key_index]] = $record[$value_index];
+    }
+    return $return;
+  }
+
+  public function fetchField($index = 0) {
+    // Call PDOStatement::fetchColumn to fetch the field.
+    return $this->fetchColumn($index);
+  }
+
+  public function fetchAssoc() {
+    // Call PDOStatement::fetch to fetch the row.
+    return $this->fetch(PDO::FETCH_ASSOC);
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/StatementEmpty.php b/core/lib/Drupal/Core/Database/StatementEmpty.php
new file mode 100644
index 0000000000000000000000000000000000000000..84ccb6a2ab5843630af916a9b99d561d07806708
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/StatementEmpty.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\StatementEmpty
+ */
+
+namespace Drupal\Core\Database;
+
+use Iterator;
+
+/**
+ * Empty implementation of a database statement.
+ *
+ * This class satisfies the requirements of being a database statement/result
+ * object, but does not actually contain data.  It is useful when developers
+ * need to safely return an "empty" result set without connecting to an actual
+ * database.  Calling code can then treat it the same as if it were an actual
+ * result set that happens to contain no records.
+ *
+ * @see SearchQuery
+ */
+class StatementEmpty implements Iterator, StatementInterface {
+
+  public function execute($args = array(), $options = array()) {
+    return FALSE;
+  }
+
+  public function getQueryString() {
+    return '';
+  }
+
+  public function rowCount() {
+    return 0;
+  }
+
+  public function setFetchMode($mode, $a1 = NULL, $a2 = array()) {
+    return;
+  }
+
+  public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL) {
+    return NULL;
+  }
+
+  public function fetchField($index = 0) {
+    return NULL;
+  }
+
+  public function fetchObject() {
+    return NULL;
+  }
+
+  public function fetchAssoc() {
+    return NULL;
+  }
+
+  function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments = array()) {
+    return array();
+  }
+
+  public function fetchCol($index = 0) {
+    return array();
+  }
+
+  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
+    return array();
+  }
+
+  public function fetchAllAssoc($key, $fetch = NULL) {
+    return array();
+  }
+
+  /* Implementations of Iterator. */
+
+  public function current() {
+    return NULL;
+  }
+
+  public function key() {
+    return NULL;
+  }
+
+  public function rewind() {
+    // Nothing to do: our DatabaseStatement can't be rewound.
+  }
+
+  public function next() {
+    // Do nothing, since this is an always-empty implementation.
+  }
+
+  public function valid() {
+    return FALSE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/StatementInterface.php b/core/lib/Drupal/Core/Database/StatementInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2fb57fcf14a752b4452c38d021c6737a78a3c024
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/StatementInterface.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\StatementInterface
+ */
+
+namespace Drupal\Core\Database;
+
+use Traversable;
+
+/**
+ * Represents a prepared statement.
+ *
+ * Some methods in that class are purposefully commented out. Due to a change in
+ * how PHP defines PDOStatement, we can't define a signature for those methods
+ * that will work the same way between versions older than 5.2.6 and later
+ * versions.  See http://bugs.php.net/bug.php?id=42452 for more details.
+ *
+ * Child implementations should either extend PDOStatement:
+ * @code
+ * class Drupal\Core\Database\Driver\oracle\Statement extends PDOStatement implements Drupal\Core\Database\StatementInterface {}
+ * @endcode
+ * or define their own class. If defining their own class, they will also have
+ * to implement either the Iterator or IteratorAggregate interface before
+ * Drupal\Core\Database\StatementInterface:
+ * @code
+ * class Drupal\Core\Database\Driver\oracle\Statement implements Iterator, Drupal\Core\Database\StatementInterface {}
+ * @endcode
+ */
+interface StatementInterface extends Traversable {
+
+  /**
+   * Executes a prepared statement
+   *
+   * @param $args
+   *   An array of values with as many elements as there are bound parameters in
+   *   the SQL statement being executed.
+   * @param $options
+   *   An array of options for this query.
+   *
+   * @return
+   *   TRUE on success, or FALSE on failure.
+   */
+  public function execute($args = array(), $options = array());
+
+  /**
+   * Gets the query string of this statement.
+   *
+   * @return
+   *   The query string, in its form with placeholders.
+   */
+  public function getQueryString();
+
+  /**
+   * Returns the number of rows affected by the last SQL statement.
+   *
+   * @return
+   *   The number of rows affected by the last DELETE, INSERT, or UPDATE
+   *   statement executed.
+   */
+  public function rowCount();
+
+  /**
+   * Sets the default fetch mode for this statement.
+   *
+   * See http://php.net/manual/en/pdo.constants.php for the definition of the
+   * constants used.
+   *
+   * @param $mode
+   *   One of the PDO::FETCH_* constants.
+   * @param $a1
+   *   An option depending of the fetch mode specified by $mode:
+   *   - for PDO::FETCH_COLUMN, the index of the column to fetch
+   *   - for PDO::FETCH_CLASS, the name of the class to create
+   *   - for PDO::FETCH_INTO, the object to add the data to
+   * @param $a2
+   *   If $mode is PDO::FETCH_CLASS, the optional arguments to pass to the
+   *   constructor.
+   */
+  // public function setFetchMode($mode, $a1 = NULL, $a2 = array());
+
+  /**
+   * Fetches the next row from a result set.
+   *
+   * See http://php.net/manual/en/pdo.constants.php for the definition of the
+   * constants used.
+   *
+   * @param $mode
+   *   One of the PDO::FETCH_* constants.
+   *   Default to what was specified by setFetchMode().
+   * @param $cursor_orientation
+   *   Not implemented in all database drivers, don't use.
+   * @param $cursor_offset
+   *   Not implemented in all database drivers, don't use.
+   *
+   * @return
+   *   A result, formatted according to $mode.
+   */
+  // public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL);
+
+  /**
+   * Returns a single field from the next record of a result set.
+   *
+   * @param $index
+   *   The numeric index of the field to return. Defaults to the first field.
+   *
+   * @return
+   *   A single field from the next record, or FALSE if there is no next record.
+   */
+  public function fetchField($index = 0);
+
+  /**
+   * Fetches the next row and returns it as an object.
+   *
+   * The object will be of the class specified by DatabaseStatementInterface::setFetchMode()
+   * or stdClass if not specified.
+   */
+  // public function fetchObject();
+
+  /**
+   * Fetches the next row and returns it as an associative array.
+   *
+   * This method corresponds to PDOStatement::fetchObject(), but for associative
+   * arrays. For some reason PDOStatement does not have a corresponding array
+   * helper method, so one is added.
+   *
+   * @return
+   *   An associative array, or FALSE if there is no next row.
+   */
+  public function fetchAssoc();
+
+  /**
+   * Returns an array containing all of the result set rows.
+   *
+   * @param $mode
+   *   One of the PDO::FETCH_* constants.
+   * @param $column_index
+   *   If $mode is PDO::FETCH_COLUMN, the index of the column to fetch.
+   * @param $constructor_arguments
+   *   If $mode is PDO::FETCH_CLASS, the arguments to pass to the constructor.
+   *
+   * @return
+   *   An array of results.
+   */
+  // function fetchAll($mode = NULL, $column_index = NULL, array $constructor_arguments);
+
+  /**
+   * Returns an entire single column of a result set as an indexed array.
+   *
+   * Note that this method will run the result set to the end.
+   *
+   * @param $index
+   *   The index of the column number to fetch.
+   *
+   * @return
+   *   An indexed array, or an empty array if there is no result set.
+   */
+  public function fetchCol($index = 0);
+
+  /**
+   * Returns the entire result set as a single associative array.
+   *
+   * This method is only useful for two-column result sets. It will return an
+   * associative array where the key is one column from the result set and the
+   * value is another field. In most cases, the default of the first two columns
+   * is appropriate.
+   *
+   * Note that this method will run the result set to the end.
+   *
+   * @param $key_index
+   *   The numeric index of the field to use as the array key.
+   * @param $value_index
+   *   The numeric index of the field to use as the array value.
+   *
+   * @return
+   *   An associative array, or an empty array if there is no result set.
+   */
+  public function fetchAllKeyed($key_index = 0, $value_index = 1);
+
+  /**
+   * Returns the result set as an associative array keyed by the given field.
+   *
+   * If the given key appears multiple times, later records will overwrite
+   * earlier ones.
+   *
+   * @param $key
+   *   The name of the field on which to index the array.
+   * @param $fetch
+   *   The fetchmode to use. If set to PDO::FETCH_ASSOC, PDO::FETCH_NUM, or
+   *   PDO::FETCH_BOTH the returned value with be an array of arrays. For any
+   *   other value it will be an array of objects. By default, the fetch mode
+   *   set for the query will be used.
+   *
+   * @return
+   *   An associative array, or an empty array if there is no result set.
+   */
+  public function fetchAllAssoc($key, $fetch = NULL);
+}
diff --git a/core/includes/database/prefetch.inc b/core/lib/Drupal/Core/Database/StatementPrefetch.php
similarity index 95%
rename from core/includes/database/prefetch.inc
rename to core/lib/Drupal/Core/Database/StatementPrefetch.php
index 4f2b19d1f3d1882c19dbef6264cfb52511ca149a..f860a9ff0909bf9e0d67bdba91a3a2afe13e7068 100644
--- a/core/includes/database/prefetch.inc
+++ b/core/lib/Drupal/Core/Database/StatementPrefetch.php
@@ -2,16 +2,15 @@
 
 /**
  * @file
- * Database interface code for engines that need complete control over their
- * result sets. For example, SQLite will prefix some column names by the name
- * of the table. We post-process the data, by renaming the column names
- * using the same convention as MySQL and PostgreSQL.
+ * Definition of Drupal\Core\Database\StatementPrefetch
  */
 
-/**
- * @ingroup database
- * @{
- */
+namespace Drupal\Core\Database;
+
+use Drupal\Core\Database\Connection;
+use Iterator;
+use PDO;
+use PDOException;
 
 /**
  * An implementation of DatabaseStatementInterface that prefetches all data.
@@ -19,7 +18,7 @@
  * This class behaves very similar to a PDOStatement but as it always fetches
  * every row it is possible to manipulate those results.
  */
-class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface {
+class StatementPrefetch implements Iterator, StatementInterface {
 
   /**
    * The query string.
@@ -40,7 +39,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
    *
    * The name $dbh is inherited from PDOStatement.
    *
-   * @var DatabaseConnection
+   * @var Drupal\Core\Database\Connection
    */
   public $dbh;
 
@@ -125,7 +124,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface
     'column' => 0,
   );
 
-  public function __construct(DatabaseConnection $connection, $query, array $driver_options = array()) {
+  public function __construct(Connection $connection, $query, array $driver_options = array()) {
     $this->dbh = $connection;
     $this->queryString = $query;
     $this->driverOptions = $driver_options;
@@ -500,8 +499,3 @@ public function fetchAllAssoc($key, $fetch_style = NULL) {
   }
 
 }
-
-/**
- * @} End of "ingroup database".
- */
-
diff --git a/core/lib/Drupal/Core/Database/Transaction.php b/core/lib/Drupal/Core/Database/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..10adadb7111f08cb2a191f2d9f48a4f3f3f5fdac
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/Transaction.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\Transaction
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * A wrapper class for creating and managing database transactions.
+ *
+ * Not all databases or database configurations support transactions. For
+ * example, MySQL MyISAM tables do not. It is also easy to begin a transaction
+ * and then forget to commit it, which can lead to connection errors when
+ * another transaction is started.
+ *
+ * This class acts as a wrapper for transactions. To begin a transaction,
+ * simply instantiate it. When the object goes out of scope and is destroyed
+ * it will automatically commit. It also will check to see if the specified
+ * connection supports transactions. If not, it will simply skip any transaction
+ * commands, allowing user-space code to proceed normally. The only difference
+ * is that rollbacks won't actually do anything.
+ *
+ * In the vast majority of cases, you should not instantiate this class
+ * directly. Instead, call ->startTransaction(), from the appropriate connection
+ * object.
+ */
+class Transaction {
+
+  /**
+   * The connection object for this transaction.
+   *
+   * @var Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * A boolean value to indicate whether this transaction has been rolled back.
+   *
+   * @var Boolean
+   */
+  protected $rolledBack = FALSE;
+
+  /**
+   * The name of the transaction.
+   *
+   * This is used to label the transaction savepoint. It will be overridden to
+   * 'drupal_transaction' if there is no transaction depth.
+   */
+  protected $name;
+
+  public function __construct(Connection &$connection, $name = NULL) {
+    $this->connection = &$connection;
+    // If there is no transaction depth, then no transaction has started. Name
+    // the transaction 'drupal_transaction'.
+    if (!$depth = $connection->transactionDepth()) {
+      $this->name = 'drupal_transaction';
+    }
+    // Within transactions, savepoints are used. Each savepoint requires a
+    // name. So if no name is present we need to create one.
+    elseif (!$name) {
+      $this->name = 'savepoint_' . $depth;
+    }
+    else {
+      $this->name = $name;
+    }
+    $this->connection->pushTransaction($this->name);
+  }
+
+  public function __destruct() {
+    // If we rolled back then the transaction would have already been popped.
+    if (!$this->rolledBack) {
+      $this->connection->popTransaction($this->name);
+    }
+  }
+
+  /**
+   * Retrieves the name of the transaction or savepoint.
+   */
+  public function name() {
+    return $this->name;
+  }
+
+  /**
+   * Rolls back the current transaction.
+   *
+   * This is just a wrapper method to rollback whatever transaction stack we are
+   * currently in, which is managed by the connection object itself. Note that
+   * logging (preferable with watchdog_exception()) needs to happen after a
+   * transaction has been rolled back or the log messages will be rolled back
+   * too.
+   *
+   * @see Drupal\Core\Database\Connection::rollback()
+   * @see watchdog_exception()
+   */
+  public function rollback() {
+    $this->rolledBack = TRUE;
+    $this->connection->rollback($this->name);
+  }
+}
diff --git a/core/lib/Drupal/Core/Database/TransactionCommitFailedException.php b/core/lib/Drupal/Core/Database/TransactionCommitFailedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a5309ea823746aacf5f11f275bb3e286e06cd40
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionCommitFailedException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionCommitFailedException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception thrown when a commit() function fails.
+ */
+class TransactionCommitFailedException extends TransactionException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/TransactionException.php b/core/lib/Drupal/Core/Database/TransactionException.php
new file mode 100644
index 0000000000000000000000000000000000000000..25079f5f23c01e771bc42732b1f4f657373f269c
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionException
+ */
+
+namespace Drupal\Core\Database;
+
+use RuntimeException;
+
+/**
+ * Exception thrown by an error in a database transaction.
+ */
+class TransactionException extends RuntimeException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/TransactionExplicitCommitNotAllowedException.php b/core/lib/Drupal/Core/Database/TransactionExplicitCommitNotAllowedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd4bf23438048fe161abb8af018e835c4b4337a7
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionExplicitCommitNotAllowedException.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionExplicitCommitNotAllowedException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception to deny attempts to explicitly manage transactions.
+ *
+ * This exception will be thrown when the PDO connection commit() is called.
+ * Code should never call this method directly.
+ */
+class TransactionExplicitCommitNotAllowedException extends TransactionException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/TransactionNameNonUniqueException.php b/core/lib/Drupal/Core/Database/TransactionNameNonUniqueException.php
new file mode 100644
index 0000000000000000000000000000000000000000..aef40cb81deb522dac38c5b7df82e5ac79859fe6
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionNameNonUniqueException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionNameNonUniqueException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception thrown when a savepoint or transaction name occurs twice.
+ */
+class TransactionNameNonUniqueException extends TransactionException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/TransactionNoActiveException.php b/core/lib/Drupal/Core/Database/TransactionNoActiveException.php
new file mode 100644
index 0000000000000000000000000000000000000000..44acede1d55fe2d0c3231583cafcde25fc58736b
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionNoActiveException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionNoActiveException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception for when popTransaction() is called with no active transaction.
+ */
+class TransactionNoActiveException extends TransactionException implements DatabaseException { }
diff --git a/core/lib/Drupal/Core/Database/TransactionOutOfOrderException.php b/core/lib/Drupal/Core/Database/TransactionOutOfOrderException.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e2fe7a90d45760951c75726197a7ee3a3a278a0
--- /dev/null
+++ b/core/lib/Drupal/Core/Database/TransactionOutOfOrderException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Database\TransactionOutOfOrderException
+ */
+
+namespace Drupal\Core\Database;
+
+/**
+ * Exception thrown when a rollback() resulted in other active transactions being rolled-back.
+ */
+class TransactionOutOfOrderException extends TransactionException implements DatabaseException { }
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index 1f6c8c2f7f1aa4539514b2710cac57a995f464af..9c54ddfd32918695162ec8584d99e780cae7edeb 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * System monitoring and logging for administrators.
diff --git a/core/modules/entity/entity.query.inc b/core/modules/entity/entity.query.inc
index fde912376993cadd679afa0d00509e27ec8f1345..fb7ebf06ca38cb7532207100983781297ce649f6 100644
--- a/core/modules/entity/entity.query.inc
+++ b/core/modules/entity/entity.query.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Query\Select;
+
 /**
  * @file
  * Entity query API.
@@ -940,7 +942,7 @@ function finishQuery($select_query, $id_key = 'entity_id') {
    *   HAVING or WHERE. This is necessary because SQL can't handle WHERE
    *   conditions on aliased columns.
    */
-  public function addCondition(SelectQuery $select_query, $sql_field, $condition, $having = FALSE) {
+  public function addCondition(Select $select_query, $sql_field, $condition, $having = FALSE) {
     $method = $having ? 'havingCondition' : 'condition';
     $like_prefix = '';
     switch ($condition['operator']) {
diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.module b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
index 561eab6eba22d8ece593dde29e48577bd8586900..adc50bd61114661d7259808029aa6a2128a1fb08 100644
--- a/core/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Query\Select;
+
 /**
  * @file
  * Default implementation of the field storage API.
@@ -592,7 +595,7 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
  * @return
  *   The name of the entity base table joined in.
  */
-function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity_type, $field_base_table) {
+function _field_sql_storage_query_join_entity(Select $select_query, $entity_type, $field_base_table) {
   $entity_info = entity_get_info($entity_type);
   $entity_base_table = $entity_info['base table'];
   $entity_field = $entity_info['entity keys']['id'];
@@ -615,7 +618,7 @@ function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity
  *   A callback that should return the column name to be used for the field
  *   conditions. Accepts a field name and a field column name as parameters.
  */
-function _field_sql_storage_query_field_conditions(EntityFieldQuery $query, SelectQuery $select_query, $conditions, $table_aliases, $column_callback) {
+function _field_sql_storage_query_field_conditions(EntityFieldQuery $query, Select $select_query, $conditions, $table_aliases, $column_callback) {
   $groups = &drupal_static(__FUNCTION__, array());
   foreach ($conditions as $key => $condition) {
     $table_alias = $table_aliases[$key];
diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.test b/core/modules/field/modules/field_sql_storage/field_sql_storage.test
index b87227023a0c733cfa78e0b6a1f42641b89cc651..d6c766e9f9462934fe3ab1f830bce59afddc51c5 100644
--- a/core/modules/field/modules/field_sql_storage/field_sql_storage.test
+++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Tests for field_sql_storage.module.
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index d78ebf7588cea26bdbc2f207561dc0a6686499e2..1a33174c67cf587933a8bb78ad308479160b59cd 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Query\SelectInterface;
+
 /**
  * @file
  * Content administration and module settings UI.
@@ -125,7 +127,7 @@ function node_filters() {
  * @param $query
  *   A SelectQuery to which the filters should be applied.
  */
-function node_build_filter_query(SelectQueryInterface $query) {
+function node_build_filter_query(SelectInterface $query) {
   // Build query
   $filter_data = isset($_SESSION['node_overview_filter']) ? $_SESSION['node_overview_filter'] : array();
   foreach ($filter_data as $index => $filter) {
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 152360f48151adce03be7744d9a9da02fd4312e4..80d0897d193a6ce7df404109007f3f98920c591c 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1,5 +1,9 @@
 <?php
 
+use Drupal\Core\Database\Query\AlterableInterface;
+use Drupal\Core\Database\Query\SelectExtender;
+use Drupal\Core\Database\Query\SelectInterface;
+
 /**
  * @file
  * The core module that allows content to be submitted to the site.
@@ -1637,7 +1641,7 @@ function node_permission() {
  * @param $query
  *   A query object that has been extended with the Search DB Extender.
  */
-function _node_rankings(SelectQueryExtender $query) {
+function _node_rankings(SelectExtender $query) {
   if ($ranking = module_invoke_all('ranking')) {
     $tables = &$query->getTables();
     foreach ($ranking as $rank => $values) {
@@ -3281,7 +3285,7 @@ function node_access_view_all_nodes($account = NULL) {
  * the 'op' meta-data (or 'view' if not provided; other possible values are
  * 'update' and 'delete').
  */
-function node_query_node_access_alter(QueryAlterableInterface $query) {
+function node_query_node_access_alter(AlterableInterface $query) {
   _node_query_node_access_alter($query, 'node');
 }
 
@@ -3292,7 +3296,7 @@ function node_query_node_access_alter(QueryAlterableInterface $query) {
  * node_query_node_access_alter() for the SQL field storage engine. Node access
  * conditions are added for field values belonging to nodes only.
  */
-function node_query_entity_field_access_alter(QueryAlterableInterface $query) {
+function node_query_entity_field_access_alter(AlterableInterface $query) {
   _node_query_node_access_alter($query, 'entity');
 }
 
@@ -3336,7 +3340,7 @@ function _node_query_node_access_alter($query, $type) {
   if (!$base_table) {
     $fallback = '';
     foreach ($tables as $alias => $table_info) {
-      if (!($table_info instanceof SelectQueryInterface)) {
+      if (!($table_info instanceof SelectInterface)) {
         $table = $table_info['table'];
         // If the node table is in the query, it wins immediately.
         if ($table == 'node') {
@@ -3408,7 +3412,7 @@ function _node_query_node_access_alter($query, $type) {
   }
   foreach ($tables as $nalias => $tableinfo) {
     $table = $tableinfo['table'];
-    if (!($table instanceof SelectQueryInterface) && $table == $base_table) {
+    if (!($table instanceof SelectInterface) && $table == $base_table) {
 
       // The node_access table has the access grants for any given node so JOIN
       // it to the table containing the nid which can be either the node
diff --git a/core/modules/node/node.test b/core/modules/node/node.test
index 02001c713f29f2a658eb3c530d36fdd10c3aa19f..96d4e01e340cf7206de3bec2d132293667f2119a 100644
--- a/core/modules/node/node.test
+++ b/core/modules/node/node.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Tests for node.module.
diff --git a/core/modules/search/search.extender.inc b/core/modules/search/search.extender.inc
index ad4b86e896137799cb0ed2dddf4af1e85c47f1e7..73f783652f6dba592d189337d45e5d4496915535 100644
--- a/core/modules/search/search.extender.inc
+++ b/core/modules/search/search.extender.inc
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Core\Database\Query\SelectExtender;
+use Drupal\Core\Database\StatementEmpty;
+
 /**
  * @file
  * Search query extender and helper functions.
@@ -24,7 +27,7 @@
  * The used query object has the tag 'search_$module' and can be further
  * extended with hook_query_alter().
  */
-class SearchQuery extends SelectQueryExtender {
+class SearchQuery extends SelectExtender {
   /**
    * The search query that is used for searching.
    *
@@ -433,7 +436,7 @@ public function execute()
       $this->executeFirstPass();
     }
     if (!$this->normalize) {
-      return new DatabaseStatementEmpty();
+      return new StatementEmpty();
     }
 
     // Add conditions to query.
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index 2852fca9d1f323595dbdba095774a7f0c01e99a9..e5d36c338ba7809dbc12e60566402df657aa41fb 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\ConnectionNotDefinedException;
+
 /**
  * Global variable that holds information about the tests being run.
  *
@@ -152,7 +155,7 @@ protected function assert($status, $message = '', $group = 'Other', array $calle
     try {
       $connection = Database::getConnection('default', 'simpletest_original_default');
     }
-    catch (DatabaseConnectionNotDefinedException $e) {
+    catch (ConnectionNotDefinedException $e) {
       // If the test was not set up, the simpletest_original_default
       // connection does not exist.
       $connection = Database::getConnection('default', 'default');
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 831ea859ec5c1d64f1513d6fc434fb0b78ca8cd4..080b621b3b7b2a4ff9c370a598efe793a7faac7a 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Provides testing functionality.
diff --git a/core/modules/simpletest/tests/database_test.module b/core/modules/simpletest/tests/database_test.module
index 6fac31919c7362d950415cb6f1ddefa6941c15fd..0ab51d80747ac345162d2eb9fd925ea770b1062d 100644
--- a/core/modules/simpletest/tests/database_test.module
+++ b/core/modules/simpletest/tests/database_test.module
@@ -1,9 +1,11 @@
 <?php
 
+use Drupal\Core\Database\Query\AlterableInterface;
+
 /**
  * Implements hook_query_alter().
  */
-function database_test_query_alter(QueryAlterableInterface $query) {
+function database_test_query_alter(AlterableInterface $query) {
 
   if ($query->hasTag('database_test_alter_add_range')) {
     $query->range(0, 2);
@@ -37,7 +39,7 @@ function database_test_query_alter(QueryAlterableInterface $query) {
  *
  * Called by DatabaseTestCase::testAlterRemoveRange.
  */
-function database_test_query_database_test_alter_remove_range_alter(QueryAlterableInterface $query) {
+function database_test_query_database_test_alter_remove_range_alter(AlterableInterface $query) {
   $query->range();
 }
 
diff --git a/core/modules/simpletest/tests/database_test.test b/core/modules/simpletest/tests/database_test.test
index 16c09c654c4fb3e9257bba878d0da10ce885ef1a..1d38ebb3766bef2aa2bf2bfe3f917be89f936238 100644
--- a/core/modules/simpletest/tests/database_test.test
+++ b/core/modules/simpletest/tests/database_test.test
@@ -1,5 +1,14 @@
 <?php
 
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\StatementEmpty;
+use Drupal\Core\Database\StatementInterface;
+use Drupal\Core\Database\TransactionOutOfOrderException;
+use Drupal\Core\Database\TransactionNoActiveException;
+use Drupal\Core\Database\Query\Merge;
+use Drupal\Core\Database\Query\InvalidMergeQueryException;
+use Drupal\Core\Database\Query\NoFieldsException;
+
 /**
  * Dummy class for fetching into a class.
  *
@@ -307,7 +316,7 @@ class DatabaseFetchTestCase extends DatabaseTestCase {
   function testQueryFetchDefault() {
     $records = array();
     $result = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 25));
-    $this->assertTrue($result instanceof DatabaseStatementInterface, t('Result set is a Drupal statement object.'));
+    $this->assertTrue($result instanceof StatementInterface, t('Result set is a Drupal statement object.'));
     foreach ($result as $record) {
       $records[] = $record;
       $this->assertTrue(is_object($record), t('Record is an object.'));
@@ -1090,7 +1099,7 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
       ))
       ->execute();
 
-    $this->assertEqual($result, MergeQuery::STATUS_INSERT, t('Insert status returned.'));
+    $this->assertEqual($result, Merge::STATUS_INSERT, t('Insert status returned.'));
 
     $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
     $this->assertEqual($num_records_before + 1, $num_records_after, t('Merge inserted properly.'));
@@ -1115,7 +1124,7 @@ class DatabaseMergeTestCase extends DatabaseTestCase {
       ))
       ->execute();
 
-    $this->assertEqual($result, MergeQuery::STATUS_UPDATE, t('Update status returned.'));
+    $this->assertEqual($result, Merge::STATUS_UPDATE, t('Update status returned.'));
 
     $num_records_after = db_query('SELECT COUNT(*) FROM {test_people}')->fetchField();
     $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.'));
@@ -3512,7 +3521,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
         // "ROLLBACK" fails silently in MySQL if there is no transaction active.
         // $this->fail(t('Rolling back a transaction containing DDL should fail.'));
       }
-      catch (DatabaseTransactionNoActiveException $e) {
+      catch (TransactionNoActiveException $e) {
         $this->pass(t('Rolling back a transaction containing DDL should fail.'));
       }
       $this->assertRowPresent('row');
@@ -3680,7 +3689,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
       unset($transaction);
       $this->fail(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
     }
-    catch (DatabaseTransactionOutOfOrderException $e) {
+    catch (TransactionOutOfOrderException $e) {
       $this->pass(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.'));
     }
     $this->assertFalse($database->inTransaction(), t('No more in a transaction after rolling back the outer transaction'));
@@ -3693,7 +3702,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase {
       unset($transaction2);
       $this->fail(t('Trying to commit an inner transaction resulted in an exception.'));
     }
-    catch (DatabaseTransactionNoActiveException $e) {
+    catch (TransactionNoActiveException $e) {
       $this->pass(t('Trying to commit an inner transaction resulted in an exception.'));
     }
     $this->assertRowAbsent('outer');
@@ -3746,9 +3755,9 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
    * Test that the empty result set behaves as empty.
    */
   function testEmpty() {
-    $result = new DatabaseStatementEmpty();
+    $result = new StatementEmpty();
 
-    $this->assertTrue($result instanceof DatabaseStatementInterface, t('Class implements expected interface'));
+    $this->assertTrue($result instanceof StatementInterface, t('Class implements expected interface'));
     $this->assertNull($result->fetchObject(), t('Null result returned.'));
   }
 
@@ -3756,7 +3765,7 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
    * Test that the empty result set iterates safely.
    */
   function testEmptyIteration() {
-    $result = new DatabaseStatementEmpty();
+    $result = new StatementEmpty();
 
     foreach ($result as $record) {
       $this->fail(t('Iterating empty result set should not iterate.'));
@@ -3770,7 +3779,7 @@ class DatabaseEmptyStatementTestCase extends DrupalWebTestCase {
    * Test that the empty result set mass-fetches in an expected way.
    */
   function testEmptyFetchAll() {
-    $result = new DatabaseStatementEmpty();
+    $result = new StatementEmpty();
 
     $this->assertEqual($result->fetchAll(), array(), t('Empty array returned from empty result set.'));
   }
diff --git a/core/modules/simpletest/tests/schema.test b/core/modules/simpletest/tests/schema.test
index 8945117cbbdba4b13b70f9fd50ffbb4fce8a1460..5a105678fc7c9845032b994e787ef83138dbcb57 100644
--- a/core/modules/simpletest/tests/schema.test
+++ b/core/modules/simpletest/tests/schema.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Tests for the Database Schema API.
diff --git a/core/modules/simpletest/tests/upgrade/upgrade.test b/core/modules/simpletest/tests/upgrade/upgrade.test
index 381816c72e84485f26a6e47b9c5714aa87dd045f..aafb642cfd4799a40b2a011358b79a8698360025 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * Perform end-to-end tests of the upgrade path.
  */
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 4d225d5b35709a83ac6c696d6b8e04a193814826..907b7b5f18a5704e9d91ecbedce1cf12d409129b 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -2746,10 +2746,10 @@ function hook_schema_alter(&$schema) {
  *
  * @see hook_query_TAG_alter()
  * @see node_query_node_access_alter()
- * @see QueryAlterableInterface
- * @see SelectQueryInterface
+ * @see AlterableInterface
+ * @see SelectInterface
  */
-function hook_query_alter(QueryAlterableInterface $query) {
+function hook_query_alter(Drupal\Database\Query\AlterableInterface $query) {
   if ($query->hasTag('micro_limit')) {
     $query->range(0, 2);
   }
@@ -2763,10 +2763,10 @@ function hook_query_alter(QueryAlterableInterface $query) {
  *
  * @see hook_query_alter()
  * @see node_query_node_access_alter()
- * @see QueryAlterableInterface
- * @see SelectQueryInterface
+ * @see AlterableInterface
+ * @see SelectInterface
  */
-function hook_query_TAG_alter(QueryAlterableInterface $query) {
+function hook_query_TAG_alter(Drupal\Database\Query\AlterableInterface $query) {
   // Skip the extra expensive alterations if site has no node access control modules.
   if (!node_access_view_all_nodes()) {
     // Prevent duplicates records.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 117cfa9506943bdb067dca6575dd3e4fda2602d9..d562bf68e286e94b7f1c9ab4d179af8684649fde 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Install, update and uninstall functions for the system module.
@@ -180,7 +182,7 @@ function system_requirements($phase) {
   }
   else {
     // Database information.
-    $class = 'DatabaseTasks_' . Database::getConnection()->driver();
+    $class = Database::getConnection()->getDriverClass('Install\\Tasks');
     $tasks = new $class();
     $requirements['database_system'] = array(
       'title' => $t('Database system'),
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 8d6566709454f6114533dad91779eded531df5f2..64774c458146e553b481ff7db1381f81dcf2d1ce 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Database;
+
 /**
  * @file
  * Tests for system.module.
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index f4479ec4c2c9f5a4bbca5241939a3283a5db20c8..3ac4cd682313d0f4a76bdaf4ab163dddeb4ded60 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Core\Database\Query\SelectInterface;
+
 /**
  * @file
  * Enables the user registration and login system.
@@ -3377,7 +3379,7 @@ function user_filters() {
  * @param $query
  *   Query object that should be filtered.
  */
-function user_build_filter_query(SelectQuery $query) {
+function user_build_filter_query(SelectInterface $query) {
   $filters = user_filters();
   // Extend Query with filter conditions.
   foreach (isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array() as $filter) {