diff --git a/core/includes/Drupal/Database/Connection.php b/core/includes/Drupal/Database/Connection.php
new file mode 100644
index 0000000000000000000000000000000000000000..9706afc83797148aa476364de95c1eba07c700d0
--- /dev/null
+++ b/core/includes/Drupal/Database/Connection.php
@@ -0,0 +1,1119 @@
+<?php
+
+namespace Drupal\Database;
+
+use PDO;
+
+/**
+ * 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 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 = '\\Drupal\\Database\\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] = "Drupal\\Database\\Driver\\{$driver}\\{$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('Select', 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('Insert', 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('Merge', 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('Update', 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('Delete', 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('Truncate', 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('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 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 rolled back.
+    if (!in_array($savepoint_name, $this->transactionLayers)) {
+      return;
+    }
+
+    // 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;
+    }
+    if (!isset($this->transactionLayers[$name])) {
+      throw new DatabaseTransactionNoActiveException();
+    }
+
+    // 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);
+}
diff --git a/core/includes/Drupal/Database/Database.php b/core/includes/Drupal/Database/Database.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ec1b151a2b395fd20267e0f4bf0300d798bd511
--- /dev/null
+++ b/core/includes/Drupal/Database/Database.php
@@ -0,0 +1,455 @@
+<?php
+
+namespace Drupal\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 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 = "Drupal\\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;
+  }
+
+  /**
+   * 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;
+        }
+      }
+    }
+  }
+}
diff --git a/core/includes/Drupal/Database/DatabaseConnectionNotDefinedException.php b/core/includes/Drupal/Database/DatabaseConnectionNotDefinedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..be6e4a412dd9f83a525c6b4441daba264db12cf1
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseConnectionNotDefinedException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown if an undefined database connection is requested.
+ */
+class DatabaseConnectionNotDefinedException extends Exception {}
diff --git a/core/includes/Drupal/Database/DatabaseDriverNotSpecifiedException.php b/core/includes/Drupal/Database/DatabaseDriverNotSpecifiedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..12fb5c3c8f5c4999d3f492db907f0f5c2a104ae7
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseDriverNotSpecifiedException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown if no driver is specified for a database connection.
+ */
+class DatabaseDriverNotSpecifiedException extends Exception {}
diff --git a/core/includes/database/log.inc b/core/includes/Drupal/Database/DatabaseLog.php
similarity index 98%
rename from core/includes/database/log.inc
rename to core/includes/Drupal/Database/DatabaseLog.php
index ec27ef8e6332ad6543ce7b489b0048b4aa3a8034..99a0e5a604bce7e093c53e8a51b17b9cc65043fb 100644
--- a/core/includes/database/log.inc
+++ b/core/includes/Drupal/Database/DatabaseLog.php
@@ -1,9 +1,6 @@
 <?php
 
-/**
- * @file
- * Logging classes for the database layer.
- */
+namespace Drupal\Database;
 
 /**
  * Database query logger.
diff --git a/core/includes/database/schema.inc b/core/includes/Drupal/Database/DatabaseSchema.php
similarity index 96%
rename from core/includes/database/schema.inc
rename to core/includes/Drupal/Database/DatabaseSchema.php
index 27934dcdf0410b87a26af9fc0bc397e1c725d3b5..70f5f6ccfe77cea506d033398f824ec062057b87 100644
--- a/core/includes/database/schema.inc
+++ b/core/includes/Drupal/Database/DatabaseSchema.php
@@ -1,11 +1,8 @@
 <?php
 
-/**
- * @file
- * Generic Database schema code.
- */
+namespace Drupal\Database;
 
-require_once __DIR__ . '/query.inc';
+use Drupal\Database\Query\PlaceholderInterface;
 
 /**
  * @defgroup schemaapi Schema API
@@ -156,7 +153,7 @@
  * @see drupal_install_schema()
  */
 
-abstract class DatabaseSchema implements QueryPlaceholderInterface {
+abstract class DatabaseSchema implements PlaceholderInterface {
 
   protected $connection;
 
@@ -194,14 +191,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++;
@@ -698,26 +695,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/includes/Drupal/Database/DatabaseSchemaObjectDoesNotExistException.php b/core/includes/Drupal/Database/DatabaseSchemaObjectDoesNotExistException.php
new file mode 100644
index 0000000000000000000000000000000000000000..28ed22b30474ecb5894d99af970a6ed035712ffb
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseSchemaObjectDoesNotExistException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\Database;
+
+use 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 {}
diff --git a/core/includes/Drupal/Database/DatabaseSchemaObjectExistsException.php b/core/includes/Drupal/Database/DatabaseSchemaObjectExistsException.php
new file mode 100644
index 0000000000000000000000000000000000000000..1a96b1610bddd94d7d190f7d7c87054d20e2a250
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseSchemaObjectExistsException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * 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 {}
diff --git a/core/includes/Drupal/Database/DatabaseStatementBase.php b/core/includes/Drupal/Database/DatabaseStatementBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..19020f9a9fe1987b413a4984de0b6aeda3c0932a
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseStatementBase.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Drupal\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 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);
+  }
+}
diff --git a/core/includes/Drupal/Database/DatabaseStatementEmpty.php b/core/includes/Drupal/Database/DatabaseStatementEmpty.php
new file mode 100644
index 0000000000000000000000000000000000000000..fee3ffdbd2a37e6cb6d54e4172663ce4fd31006c
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseStatementEmpty.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Drupal\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 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;
+  }
+}
diff --git a/core/includes/Drupal/Database/DatabaseStatementInterface.php b/core/includes/Drupal/Database/DatabaseStatementInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..37d30563fd5e25ee844f1403ebacd29dbddfe214
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseStatementInterface.php
@@ -0,0 +1,194 @@
+<?php
+
+namespace Drupal\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 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);
+}
diff --git a/core/includes/database/prefetch.inc b/core/includes/Drupal/Database/DatabaseStatementPrefetch.php
similarity index 96%
rename from core/includes/database/prefetch.inc
rename to core/includes/Drupal/Database/DatabaseStatementPrefetch.php
index 4f2b19d1f3d1882c19dbef6264cfb52511ca149a..5c0419aa0cc28bc3ee87a88d29d61550e7b83d18 100644
--- a/core/includes/database/prefetch.inc
+++ b/core/includes/Drupal/Database/DatabaseStatementPrefetch.php
@@ -1,17 +1,10 @@
 <?php
 
-/**
- * @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.
- */
+namespace Drupal\Database;
 
-/**
- * @ingroup database
- * @{
- */
+use Drupal\Database\Connection;
+use Iterator;
+use PDO;
 
 /**
  * An implementation of DatabaseStatementInterface that prefetches all data.
@@ -125,7 +118,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 +493,3 @@ public function fetchAllAssoc($key, $fetch_style = NULL) {
   }
 
 }
-
-/**
- * @} End of "ingroup database".
- */
-
diff --git a/core/includes/Drupal/Database/DatabaseTransactionCommitFailedException.php b/core/includes/Drupal/Database/DatabaseTransactionCommitFailedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..0df9490cbbd4911c4d47b44ae853588507ef938f
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseTransactionCommitFailedException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown when a commit() function fails.
+ */
+class DatabaseTransactionCommitFailedException extends Exception { }
diff --git a/core/includes/Drupal/Database/DatabaseTransactionExplicitCommitNotAllowedException.php b/core/includes/Drupal/Database/DatabaseTransactionExplicitCommitNotAllowedException.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e38d8b02b69856ec3e9225c52fc53a3094c1041
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseTransactionExplicitCommitNotAllowedException.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Drupal\Database;
+
+use 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 { }
diff --git a/core/includes/Drupal/Database/DatabaseTransactionNameNonUniqueException.php b/core/includes/Drupal/Database/DatabaseTransactionNameNonUniqueException.php
new file mode 100644
index 0000000000000000000000000000000000000000..857ebe1c84ac1f0a21431e2c0b4ebaff69dedab7
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseTransactionNameNonUniqueException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown when a savepoint or transaction name occurs twice.
+ */
+class DatabaseTransactionNameNonUniqueException extends Exception { }
diff --git a/core/includes/Drupal/Database/DatabaseTransactionNoActiveException.php b/core/includes/Drupal/Database/DatabaseTransactionNoActiveException.php
new file mode 100644
index 0000000000000000000000000000000000000000..25d749d8c22bf32d29de69c648ff19f5b5cf6352
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseTransactionNoActiveException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception for when popTransaction() is called with no active transaction.
+ */
+class DatabaseTransactionNoActiveException extends Exception { }
diff --git a/core/includes/Drupal/Database/DatabaseTransactionOutOfOrderException.php b/core/includes/Drupal/Database/DatabaseTransactionOutOfOrderException.php
new file mode 100644
index 0000000000000000000000000000000000000000..452632ee30048edfabfc9e85d2ea09d796679491
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseTransactionOutOfOrderException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown when a rollback() resulted in other active transactions being rolled-back.
+ */
+class DatabaseTransactionOutOfOrderException extends Exception { }
diff --git a/core/includes/database/mysql/database.inc b/core/includes/Drupal/Database/Driver/mysql/Connection.php
similarity index 98%
rename from core/includes/database/mysql/database.inc
rename to core/includes/Drupal/Database/Driver/mysql/Connection.php
index a57f7dd022836e96347eb3d35c135a311e6e1c60..1f82247bea8f9e1bb6d85ae149709fcd064326bf 100644
--- a/core/includes/database/mysql/database.inc
+++ b/core/includes/Drupal/Database/Driver/mysql/Connection.php
@@ -1,16 +1,17 @@
 <?php
 
-/**
- * @file
- * Database interface code for MySQL database servers.
- */
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Connection as DatabaseConnection;
+
+use PDO;
 
 /**
  * @ingroup database
  * @{
  */
 
-class DatabaseConnection_mysql extends DatabaseConnection {
+class Connection extends DatabaseConnection {
 
   /**
    * Flag to indicate if we have registered the nextID cleanup function.
diff --git a/core/includes/database/mysql/schema.inc b/core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php
similarity index 99%
rename from core/includes/database/mysql/schema.inc
rename to core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php
index 4e88fa169ebeb6dca90fdf66a55f6ffe10f3bc06..41b92f3722ccfe45a15ea18ea8d175f1115ec876 100644
--- a/core/includes/database/mysql/schema.inc
+++ b/core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php
@@ -1,17 +1,15 @@
 <?php
 
-/**
- * @file
- * Database schema code for MySQL database servers.
- */
+namespace Drupal\Database\Driver\mysql;
 
+use Drupal\Database\DatabaseSchema as DatabaseDatabaseSchema;
 
 /**
  * @ingroup schemaapi
  * @{
  */
 
-class DatabaseSchema_mysql extends DatabaseSchema {
+class DatabaseSchema extends DatabaseDatabaseSchema {
 
   /**
    * Maximum length of a table comment in MySQL.
diff --git a/core/includes/Drupal/Database/Driver/mysql/Delete.php b/core/includes/Drupal/Database/Driver/mysql/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..5d04ea9db57c0eb4e18c09bf3c392ab5f20ae2b2
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Delete.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Query\Delete as QueryDelete;
+
+class Delete extends QueryDelete { }
diff --git a/core/includes/database/mysql/query.inc b/core/includes/Drupal/Database/Driver/mysql/Insert.php
similarity index 75%
rename from core/includes/database/mysql/query.inc
rename to core/includes/Drupal/Database/Driver/mysql/Insert.php
index 888b6a5a450e613b172814e53b0f53f27e76cf69..ff58f3ba5ab098a6393217a32f03ce3c29ba8247 100644
--- a/core/includes/database/mysql/query.inc
+++ b/core/includes/Drupal/Database/Driver/mysql/Insert.php
@@ -1,17 +1,10 @@
 <?php
 
-/**
- * @ingroup database
- * @{
- */
+namespace Drupal\Database\Driver\mysql;
 
-/**
- * @file
- * Query code for MySQL embedded database engine.
- */
+use Drupal\Database\Query\Insert as QueryInsert;
 
-
-class InsertQuery_mysql extends InsertQuery {
+class Insert extends QueryInsert {
 
   public function execute() {
     if (!$this->preExecute()) {
@@ -85,23 +78,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/Drupal/Database/Driver/mysql/Merge.php b/core/includes/Drupal/Database/Driver/mysql/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d75cf2a74a1292ab3ea9485b42b3ab6a08dd212
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Merge.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Query\Merge as QueryMerge;
+
+class Merge extends QueryMerge { }
diff --git a/core/includes/Drupal/Database/Driver/mysql/Select.php b/core/includes/Drupal/Database/Driver/mysql/Select.php
new file mode 100644
index 0000000000000000000000000000000000000000..35ef1d55132bdd95d9aa0a0ed8aef749bf7a4f8a
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Select.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Query\Select as QuerySelect;
+
+class Select extends QuerySelect { }
diff --git a/core/includes/Drupal/Database/Driver/mysql/Transaction.php b/core/includes/Drupal/Database/Driver/mysql/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..57e3fb0c2ebb090680f3974912747da1563ce276
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Transaction.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Transaction as DatabaseTransaction;
+
+class Transaction extends DatabaseTransaction { }
diff --git a/core/includes/Drupal/Database/Driver/mysql/Truncate.php b/core/includes/Drupal/Database/Driver/mysql/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..40c49cd35f6a95b80dc4a125b7d09369543da7ee
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Truncate.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\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/includes/Drupal/Database/Driver/mysql/Update.php b/core/includes/Drupal/Database/Driver/mysql/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b82267bc9d701f84a668fe91f3ab02dad8e22d6
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Update.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Query\Update as QueryUpdate;
+
+class Update extends QueryUpdate { }
diff --git a/core/includes/Drupal/Database/FieldsOverlapException.php b/core/includes/Drupal/Database/FieldsOverlapException.php
new file mode 100644
index 0000000000000000000000000000000000000000..9d3a23f35d0d7188e8f7f765ea54a3c6666ca2f7
--- /dev/null
+++ b/core/includes/Drupal/Database/FieldsOverlapException.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Drupal\Database;
+
+use 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 {}
diff --git a/core/includes/Drupal/Database/InvalidMergeQueryException.php b/core/includes/Drupal/Database/InvalidMergeQueryException.php
new file mode 100644
index 0000000000000000000000000000000000000000..5d173ddda245cccbfee7166019fec4fdaf3336f1
--- /dev/null
+++ b/core/includes/Drupal/Database/InvalidMergeQueryException.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Drupal\Database;
+
+use 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 {}
diff --git a/core/includes/Drupal/Database/NoFieldsException.php b/core/includes/Drupal/Database/NoFieldsException.php
new file mode 100644
index 0000000000000000000000000000000000000000..1864841e4c0eeff7f8d2797e0d6a80e91bdb27ff
--- /dev/null
+++ b/core/includes/Drupal/Database/NoFieldsException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\Database;
+
+use Exception;
+
+/**
+ * Exception thrown if an insert query doesn't specify insert or default fields.
+ */
+class NoFieldsException extends Exception {}
diff --git a/core/includes/Drupal/Database/Query/AlterableInterface.php b/core/includes/Drupal/Database/Query/AlterableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef0f78b63e09a5530920b9b29c89549fb05c2f41
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/AlterableInterface.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\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 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);
+}
diff --git a/core/includes/Drupal/Database/Query/ConditionInterface.php b/core/includes/Drupal/Database/Query/ConditionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a30abf815224e664f3544138cc4e180c37f5a6d
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/ConditionInterface.php
@@ -0,0 +1,154 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\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 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(SelectInterface $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(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/includes/Drupal/Database/Query/DatabaseCondition.php b/core/includes/Drupal/Database/Query/DatabaseCondition.php
new file mode 100644
index 0000000000000000000000000000000000000000..5200fd2676a9a11696c0ae08c32c78741533cfdc
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/DatabaseCondition.php
@@ -0,0 +1,312 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Connection;
+
+use Countable;
+
+/**
+ * Generic class for a series of conditions in a query.
+ */
+class DatabaseCondition 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 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(SelectInterface $select) {
+    return $this->condition('', $select, 'EXISTS');
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $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(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 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 '';
+    }
+    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 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/includes/Drupal/Database/Query/Delete.php b/core/includes/Drupal/Database/Query/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ff7267d9a49be7195ae2ad4a001e2ba3d09909e
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Delete.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Database;
+use Drupal\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 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(Connection $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(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $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(Connection $connection, PlaceholderInterface $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;
+  }
+}
diff --git a/core/includes/Drupal/Database/Query/ExtendableInterface.php b/core/includes/Drupal/Database/Query/ExtendableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..edc24d9265c7118158bf6b5c8bde0bd21b907fff
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/ExtendableInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\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 QueryExtendableInterface
+   *   The extender object, which now contains a reference to this object.
+   */
+  public function extend($extender_name);
+}
diff --git a/core/includes/Drupal/Database/Query/Insert.php b/core/includes/Drupal/Database/Query/Insert.php
new file mode 100644
index 0000000000000000000000000000000000000000..d33498d36ea3d08ebde15132f56d466eddf6e8e2
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Insert.php
@@ -0,0 +1,296 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\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 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;
+  }
+}
diff --git a/core/includes/Drupal/Database/Query/Merge.php b/core/includes/Drupal/Database/Query/Merge.php
new file mode 100644
index 0000000000000000000000000000000000000000..2fea04139c6978b80c1d38b35b2f25de074ae780
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Merge.php
@@ -0,0 +1,451 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Database;
+use Drupal\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 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(Connection $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(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $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(Connection $connection, PlaceholderInterface $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 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/includes/Drupal/Database/Query/PlaceholderInterface.php b/core/includes/Drupal/Database/Query/PlaceholderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..509a30d29af2ca6825f6771ec588375bf787bcbe
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/PlaceholderInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Drupal\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/includes/Drupal/Database/Query/Query.php b/core/includes/Drupal/Database/Query/Query.php
new file mode 100644
index 0000000000000000000000000000000000000000..21cfb8ebea98b88c85871ac2592c98d96bf39251
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Query.php
@@ -0,0 +1,175 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Database;
+use Drupal\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 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(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 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/includes/Drupal/Database/Query/Select.php b/core/includes/Drupal/Database/Query/Select.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f5c78db72a78ffb8f476e33cd6d72cbacb3bd58
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Select.php
@@ -0,0 +1,760 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Database;
+use Drupal\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 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, Connection $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 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 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(Connection $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(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/includes/Drupal/Database/Query/SelectExtender.php b/core/includes/Drupal/Database/Query/SelectExtender.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea96bba1215e911ab387249f95d0e75023553dc3
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/SelectExtender.php
@@ -0,0 +1,327 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Connection;
+
+/**
+ * The base extender class for Select queries.
+ */
+class SelectExtender implements SelectInterface {
+
+  /**
+   * 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(SelectInterface $query, Connection $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(Connection $connection, PlaceholderInterface $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(Connection $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(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/includes/Drupal/Database/Query/SelectInterface.php b/core/includes/Drupal/Database/Query/SelectInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b023778cac180ef23234a4f6eff5763ade9222b0
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/SelectInterface.php
@@ -0,0 +1,499 @@
+<?php
+
+namespace Drupal\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 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(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 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(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 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);
+}
diff --git a/core/includes/Drupal/Database/Query/Truncate.php b/core/includes/Drupal/Database/Query/Truncate.php
new file mode 100644
index 0000000000000000000000000000000000000000..59f4a29d9701c69e3e92fc72f7b1bec66e52d7ab
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Truncate.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Connection;
+
+
+/**
+ * General class for an abstracted TRUNCATE operation.
+ */
+class Truncate 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(Connection $connection, $table, array $options = array()) {
+    $options['return'] = Database::RETURN_AFFECTED;
+    parent::__construct($connection, $options);
+    $this->table = $table;
+  }
+
+  /**
+   * Implements QueryConditionInterface::compile().
+   */
+  public function compile(Connection $connection, PlaceholderInterface $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) . '} ';
+  }
+}
diff --git a/core/includes/Drupal/Database/Query/Update.php b/core/includes/Drupal/Database/Query/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..f1d32ab6a3d81e512fe224097dad14f3d21656a0
--- /dev/null
+++ b/core/includes/Drupal/Database/Query/Update.php
@@ -0,0 +1,263 @@
+<?php
+
+namespace Drupal\Database\Query;
+
+use Drupal\Database\Database;
+use Drupal\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 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(Connection $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(SelectInterface $select) {
+    $this->condition->exists($select);
+    return $this;
+  }
+
+  /**
+   * Implements QueryConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $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(Connection $connection, PlaceholderInterface $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;
+  }
+
+}
diff --git a/core/includes/Drupal/Database/Transaction.php b/core/includes/Drupal/Database/Transaction.php
new file mode 100644
index 0000000000000000000000000000000000000000..e2b34f588258d1d20b603765ba6b27042a5e87ec
--- /dev/null
+++ b/core/includes/Drupal/Database/Transaction.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Drupal\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 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(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 DatabaseConnection::rollback()
+   * @see watchdog_exception()
+   */
+  public function rollback() {
+    $this->rolledBack = TRUE;
+    $this->connection->rollback($this->name);
+  }
+}
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 0026cb03f75b5e978516e64b69143c62dd522616..4da73db25d2ccf450e1f6bb0602b22abddc98709 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Functions that need to be loaded on every Drupal request.
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 9da67ac903120c2b21e573d4708dad224def25fb..25b5c594263e1155ddf004959533b812b12f2848 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\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 dcf0d1ecbd5eefbd740a1abe1ae07d292b6cb805..aa1f44487c10dce7a81426447e5a0cb0afbbdcb9 100644
--- a/core/includes/database/database.inc
+++ b/core/includes/database/database.inc
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Database\Database;
+use Drupal\Database\Query\DatabaseCondition;
+
 /**
  * @file
  * Core systems for the database layer.
@@ -171,2105 +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 rolled back.
-    if (!in_array($savepoint_name, $this->transactionLayers)) {
-      return;
-    }
-
-    // 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;
-    }
-    if (!isset($this->transactionLayers[$name])) {
-      throw new DatabaseTransactionNoActiveException();
-    }
-
-    // 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.
  *
diff --git a/core/includes/database/pgsql/install.inc b/core/includes/database/pgsql/install.inc
index c350634ec40058a19c7ae470f2d5c8a03bc71c4c..9268687cab3d544a208884d3e6dd2cee161d07cf 100644
--- a/core/includes/database/pgsql/install.inc
+++ b/core/includes/database/pgsql/install.inc
@@ -1,11 +1,12 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Install functions for PostgreSQL embedded database engine.
  */
 
-
 // PostgreSQL specific install functions
 
 class DatabaseTasks_pgsql extends DatabaseTasks {
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/install.inc b/core/includes/install.inc
index 8d7f22d784ec89942072184f9b5c323f70b6e88f..925c9ae0c638374cee0bf1761c8491d8f2d992cd 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * Indicates that a module has not been installed yet.
  */
diff --git a/core/includes/pager.inc b/core/includes/pager.inc
index a5d3e6be03c9c643670b1b9f0b6da4084be09a92..2c71e0b4d7ceb20298dab37c69b7711953ec5a45 100644
--- a/core/includes/pager.inc
+++ b/core/includes/pager.inc
@@ -1,18 +1,21 @@
 <?php
 
+use Drupal\Database\Connection;
+use Drupal\Database\Query\SelectExtender;
+use Drupal\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 8961f7a18b631328f40053fefbb0556cf7c642cf..66a647e436fd8daba39d95f5f2651f0b4e7636d8 100644
--- a/core/includes/registry.inc
+++ b/core/includes/registry.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * This file contains the code registry parser engine.
diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc
index 7873cdb2db42f2aba2a6f0ae876f7ffb7c02def2..799b0c7a9527d098c762f088a311385bf76acf95 100644
--- a/core/includes/tablesort.inc
+++ b/core/includes/tablesort.inc
@@ -1,5 +1,8 @@
 <?php
 
+use Drupal\Database\Query\SelectExtender;
+use Drupal\Database\Query\SelectInterface;
+
 /**
  * @file
  * Functions to aid in the creation of sortable tables.
@@ -8,11 +11,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 +23,7 @@ class TableSort extends SelectQueryExtender {
    */
   protected $header = array();
 
-  public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
+  public function __construct(SelectInterface $query, DatabaseConnection $connection) {
     parent::__construct($query, $connection);
 
     // Add convenience tag to mark that this is an extended query. We have to
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index 496a043a76a61b0211da64a5a6e630c8a4327b71..b1d545b6e6d70d17d1424f159c4a72640b0ddef5 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * System monitoring and logging for administrators.
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 92d244a9fbaccdbaba945f2d83843fc471357e29..e7dea9ed4fbd74482376cd5a1e85a7fe2f453a52 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,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Default implementation of the field storage API.
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 773de3d072dc03c2d76b5a94ac2be11301832196..1ceac670c12f627482354961fa446e5f65566292 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\Database\Database;
+
 /**
  * @file
  * Tests for field_sql_storage.module.
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 57607cd8270327b5cd9f17309556297b6f0f9ec4..be9366fa804c9e241a656a40757be4cb02ccb108 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Query\AlterableInterface;
+
 /**
  * @file
  * The core module that allows content to be submitted to the site.
@@ -3260,7 +3262,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');
 }
 
@@ -3271,7 +3273,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');
 }
 
diff --git a/core/modules/node/node.test b/core/modules/node/node.test
index 2e9b075d3303feb470b550300f255cd4acd2cc1f..b52a8d9c26065fc9a2a6786029f1ecf1427e0cdd 100644
--- a/core/modules/node/node.test
+++ b/core/modules/node/node.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Tests for node.module.
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index a5fb606a109ab126fc18e2d78f3b9a18ec94745e..0ad11710737203557b5344a402e37fe92b975aeb 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * Global variable that holds information about the tests being run.
  *
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 831ea859ec5c1d64f1513d6fc434fb0b78ca8cd4..9221b0bf33ee86895bb84306ee0df09156e96d8b 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Provides testing functionality.
diff --git a/core/modules/simpletest/tests/database_test.test b/core/modules/simpletest/tests/database_test.test
index 6e55fbdf0f8ace853818c6a6090ecf2fcacd3894..32396a4cabb85c300f6435c3b079df1cc4a7323c 100644
--- a/core/modules/simpletest/tests/database_test.test
+++ b/core/modules/simpletest/tests/database_test.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * Dummy class for fetching into a class.
  *
diff --git a/core/modules/simpletest/tests/schema.test b/core/modules/simpletest/tests/schema.test
index 8945117cbbdba4b13b70f9fd50ffbb4fce8a1460..ca3d70e5c93c694c126b339b79592eb1d3a30917 100644
--- a/core/modules/simpletest/tests/schema.test
+++ b/core/modules/simpletest/tests/schema.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\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 29793b257c35f8f73cd9b62ab88f4e23b81bbca2..257043e055b4db59125df239f987c505980fc54d 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * Perform end-to-end tests of the upgrade path.
  */
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 01579643634057e26b3d9e0f270961400f8a32b0..14c6eb5127d999833ff4be90c566c334cb37bf98 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Install, update and uninstall functions for the system module.
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 12797edbd633020ea0d4cf245e9d7644bf969a4f..aa39688953de834a846640c0f44a487c9bad4056 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\Database\Database;
+
 /**
  * @file
  * Tests for system.module.