diff --git a/core/includes/Drupal/Database/Connection.php b/core/includes/Drupal/Database/Connection.php
new file mode 100644
index 0000000..9706afc
--- /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 0000000..8ec1b15
--- /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 0000000..be6e4a4
--- /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 0000000..12fb5c3
--- /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/Drupal/Database/DatabaseLog.php b/core/includes/Drupal/Database/DatabaseLog.php
new file mode 100644
index 0000000..99a0e5a
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseLog.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace Drupal\Database;
+
+/**
+ * Database query logger.
+ *
+ * We log queries in a separate object rather than in the connection object
+ * because we want to be able to see all queries sent to a given database, not
+ * database target. If we logged the queries in each connection object we
+ * would not be able to track what queries went to which target.
+ *
+ * Every connection has one and only one logging object on it for all targets
+ * and logging keys.
+ */
+class DatabaseLog {
+
+  /**
+   * Cache of logged queries. This will only be used if the query logger is enabled.
+   *
+   * The structure for the logging array is as follows:
+   *
+   * array(
+   *   $logging_key = array(
+   *     array(query => '', args => array(), caller => '', target => '', time => 0),
+   *     array(query => '', args => array(), caller => '', target => '', time => 0),
+   *   ),
+   * );
+   *
+   * @var array
+   */
+  protected $queryLog = array();
+
+  /**
+   * The connection key for which this object is logging.
+   *
+   * @var string
+   */
+  protected $connectionKey = 'default';
+
+  /**
+   * Constructor.
+   *
+   * @param $key
+   *   The database connection key for which to enable logging.
+   */
+  public function __construct($key = 'default') {
+    $this->connectionKey = $key;
+  }
+
+  /**
+   * Begin logging queries to the specified connection and logging key.
+   *
+   * If the specified logging key is already running this method does nothing.
+   *
+   * @param $logging_key
+   *   The identification key for this log request. By specifying different
+   *   logging keys we are able to start and stop multiple logging runs
+   *   simultaneously without them colliding.
+   */
+  public function start($logging_key) {
+    if (empty($this->queryLog[$logging_key])) {
+      $this->clear($logging_key);
+    }
+  }
+
+  /**
+   * Retrieve the query log for the specified logging key so far.
+   *
+   * @param $logging_key
+   *   The logging key to fetch.
+   * @return
+   *   An indexed array of all query records for this logging key.
+   */
+  public function get($logging_key) {
+    return $this->queryLog[$logging_key];
+  }
+
+  /**
+   * Empty the query log for the specified logging key.
+   *
+   * This method does not stop logging, it simply clears the log. To stop
+   * logging, use the end() method.
+   *
+   * @param $logging_key
+   *   The logging key to empty.
+   */
+  public function clear($logging_key) {
+    $this->queryLog[$logging_key] = array();
+  }
+
+  /**
+   * Stop logging for the specified logging key.
+   *
+   * @param $logging_key
+   *   The logging key to stop.
+   */
+  public function end($logging_key) {
+    unset($this->queryLog[$logging_key]);
+  }
+
+  /**
+   * Log a query to all active logging keys.
+   *
+   * @param $statement
+   *   The prepared statement object to log.
+   * @param $args
+   *   The arguments passed to the statement object.
+   * @param $time
+   *   The time in milliseconds the query took to execute.
+   */
+  public function log(DatabaseStatementInterface $statement, $args, $time) {
+    foreach (array_keys($this->queryLog) as $key) {
+      $this->queryLog[$key][] = array(
+        'query' => $statement->getQueryString(),
+        'args' => $args,
+        'target' => $statement->dbh->getTarget(),
+        'caller' => $this->findCaller(),
+        'time' => $time,
+      );
+    }
+  }
+
+  /**
+   * Determine the routine that called this query.
+   *
+   * We define "the routine that called this query" as the first entry in
+   * the call stack that is not inside includes/database. That makes the
+   * climbing logic very simple, and handles the variable stack depth caused
+   * by the query builders.
+   *
+   * @link http://www.php.net/debug_backtrace
+   * @return
+   *   This method returns a stack trace entry similar to that generated by
+   *   debug_backtrace(). However, it flattens the trace entry and the trace
+   *   entry before it so that we get the function and args of the function that
+   *   called into the database system, not the function and args of the
+   *   database call itself.
+   */
+  public function findCaller() {
+    $stack = debug_backtrace();
+    $stack_count = count($stack);
+    for ($i = 0; $i < $stack_count; ++$i) {
+      if (strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
+        return array(
+          'file' => $stack[$i]['file'],
+          'line' => $stack[$i]['line'],
+          'function' => $stack[$i + 1]['function'],
+          'class' => isset($stack[$i + 1]['class']) ? $stack[$i + 1]['class'] : NULL,
+          'type' => isset($stack[$i + 1]['type']) ? $stack[$i + 1]['type'] : NULL,
+          'args' => $stack[$i + 1]['args'],
+        );
+      }
+    }
+  }
+}
diff --git a/core/includes/Drupal/Database/DatabaseSchema.php b/core/includes/Drupal/Database/DatabaseSchema.php
new file mode 100644
index 0000000..70f5f6c
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseSchema.php
@@ -0,0 +1,697 @@
+<?php
+
+namespace Drupal\Database;
+
+use Drupal\Database\Query\PlaceholderInterface;
+
+/**
+ * @defgroup schemaapi Schema API
+ * @{
+ * API to handle database schemas.
+ *
+ * A Drupal schema definition is an array structure representing one or
+ * more tables and their related keys and indexes. A schema is defined by
+ * hook_schema(), which usually lives in a modulename.install file.
+ *
+ * By implementing hook_schema() and specifying the tables your module
+ * declares, you can easily create and drop these tables on all
+ * supported database engines. You don't have to deal with the
+ * different SQL dialects for table creation and alteration of the
+ * supported database engines.
+ *
+ * hook_schema() should return an array with a key for each table that
+ * the module defines.
+ *
+ * The following keys are defined:
+ *   - 'description': A string in non-markup plain text describing this table
+ *     and its purpose. References to other tables should be enclosed in
+ *     curly-brackets. For example, the node_revisions table
+ *     description field might contain "Stores per-revision title and
+ *     body data for each {node}."
+ *   - 'fields': An associative array ('fieldname' => specification)
+ *     that describes the table's database columns. The specification
+ *     is also an array. The following specification parameters are defined:
+ *     - 'description': A string in non-markup plain text describing this field
+ *       and its purpose. References to other tables should be enclosed in
+ *       curly-brackets. For example, the node table vid field
+ *       description might contain "Always holds the largest (most
+ *       recent) {node_revision}.vid value for this nid."
+ *     - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int',
+ *       'float', 'numeric', or 'serial'. Most types just map to the according
+ *       database engine specific datatypes. Use 'serial' for auto incrementing
+ *       fields. This will expand to 'INT auto_increment' on MySQL.
+ *     - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to
+ *       use a record type not included in the officially supported list
+ *       of types above, you can specify a type for each database
+ *       backend. In this case, you can leave out the type parameter,
+ *       but be advised that your schema will fail to load on backends that
+ *       do not have a type specified. A possible solution can be to
+ *       use the "text" type as a fallback.
+ *     - 'serialize': A boolean indicating whether the field will be stored as
+ *       a serialized string.
+ *     - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
+ *       'big'. This is a hint about the largest value the field will
+ *       store and determines which of the database engine specific
+ *       datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs. BIGINT).
+ *       'normal', the default, selects the base type (e.g. on MySQL,
+ *       INT, VARCHAR, BLOB, etc.).
+ *       Not all sizes are available for all data types. See
+ *       DatabaseSchema::getFieldTypeMap() for possible combinations.
+ *     - 'not null': If true, no NULL values will be allowed in this
+ *       database column. Defaults to false.
+ *     - 'default': The field's default value. The PHP type of the
+ *       value matters: '', '0', and 0 are all different. If you
+ *       specify '0' as the default value for a type 'int' field it
+ *       will not work because '0' is a string containing the
+ *       character "zero", not an integer.
+ *     - 'length': The maximal length of a type 'char', 'varchar' or 'text'
+ *       field. Ignored for other field types.
+ *     - 'unsigned': A boolean indicating whether a type 'int', 'float'
+ *       and 'numeric' only is signed or unsigned. Defaults to
+ *       FALSE. Ignored for other field types.
+ *     - 'precision', 'scale': For type 'numeric' fields, indicates
+ *       the precision (total number of significant digits) and scale
+ *       (decimal digits right of the decimal point). Both values are
+ *       mandatory. Ignored for other field types.
+ *     All parameters apart from 'type' are optional except that type
+ *     'numeric' columns must specify 'precision' and 'scale'.
+ *  - 'primary key': An array of one or more key column specifiers (see below)
+ *    that form the primary key.
+ *  - 'unique keys': An associative array of unique keys ('keyname' =>
+ *    specification). Each specification is an array of one or more
+ *    key column specifiers (see below) that form a unique key on the table.
+ *  - 'foreign keys': An associative array of relations ('my_relation' =>
+ *    specification). Each specification is an array containing the name of
+ *    the referenced table ('table'), and an array of column mappings
+ *    ('columns'). Column mappings are defined by key pairs ('source_column' =>
+ *    'referenced_column').
+ *  - 'indexes':  An associative array of indexes ('indexname' =>
+ *    specification). Each specification is an array of one or more
+ *    key column specifiers (see below) that form an index on the
+ *    table.
+ *
+ * A key column specifier is either a string naming a column or an
+ * array of two elements, column name and length, specifying a prefix
+ * of the named column.
+ *
+ * As an example, here is a SUBSET of the schema definition for
+ * Drupal's 'node' table. It show four fields (nid, vid, type, and
+ * title), the primary key on field 'nid', a unique key named 'vid' on
+ * field 'vid', and two indexes, one named 'nid' on field 'nid' and
+ * one named 'node_title_type' on the field 'title' and the first four
+ * bytes of the field 'type':
+ *
+ * @code
+ * $schema['node'] = array(
+ *   'description' => 'The base table for nodes.',
+ *   'fields' => array(
+ *     'nid'       => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
+ *     'vid'       => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE,'default' => 0),
+ *     'type'      => array('type' => 'varchar','length' => 32,'not null' => TRUE, 'default' => ''),
+ *     'language'  => array('type' => 'varchar','length' => 12,'not null' => TRUE,'default' => ''),
+ *     'title'     => array('type' => 'varchar','length' => 255,'not null' => TRUE, 'default' => ''),
+ *     'uid'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'status'    => array('type' => 'int', 'not null' => TRUE, 'default' => 1),
+ *     'created'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'changed'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'comment'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'promote'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'moderate'  => array('type' => 'int', 'not null' => TRUE,'default' => 0),
+ *     'sticky'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *     'tnid'      => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+ *     'translate' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+ *   ),
+ *   'indexes' => array(
+ *     'node_changed'        => array('changed'),
+ *     'node_created'        => array('created'),
+ *     'node_moderate'       => array('moderate'),
+ *     'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
+ *     'node_status_type'    => array('status', 'type', 'nid'),
+ *     'node_title_type'     => array('title', array('type', 4)),
+ *     'node_type'           => array(array('type', 4)),
+ *     'uid'                 => array('uid'),
+ *     'tnid'                => array('tnid'),
+ *     'translate'           => array('translate'),
+ *   ),
+ *   'unique keys' => array(
+ *     'vid' => array('vid'),
+ *   ),
+ *   'foreign keys' => array(
+ *     'node_revision' => array(
+ *       'table' => 'node_revision',
+ *       'columns' => array('vid' => 'vid'),
+ *      ),
+ *     'node_author' => array(
+ *       'table' => 'users',
+ *       'columns' => array('uid' => 'uid'),
+ *      ),
+ *    ),
+ *   'primary key' => array('nid'),
+ * );
+ * @endcode
+ *
+ * @see drupal_install_schema()
+ */
+
+abstract class DatabaseSchema implements PlaceholderInterface {
+
+  protected $connection;
+
+  /**
+   * The placeholder counter.
+   */
+  protected $placeholder = 0;
+
+  /**
+   * Definition of prefixInfo array structure.
+   *
+   * Rather than redefining DatabaseSchema::getPrefixInfo() for each driver,
+   * by defining the defaultSchema variable only MySQL has to re-write the
+   * method.
+   *
+   * @see DatabaseSchema::getPrefixInfo()
+   */
+  protected $defaultSchema = 'public';
+
+  /**
+   * A unique identifier for this query object.
+   */
+  protected $uniqueIdentifier;
+
+  public function __construct($connection) {
+    $this->uniqueIdentifier = uniqid('', TRUE);
+    $this->connection = $connection;
+  }
+
+  /**
+   * Implements the magic __clone function.
+   */
+  public function __clone() {
+    $this->uniqueIdentifier = uniqid('', TRUE);
+  }
+
+  /**
+   * Implements PlaceHolderInterface::uniqueIdentifier().
+   */
+  public function uniqueIdentifier() {
+    return $this->uniqueIdentifier;
+  }
+
+  /**
+   * Implements PlaceHolderInterface::nextPlaceholder().
+   */
+  public function nextPlaceholder() {
+    return $this->placeholder++;
+  }
+
+  /**
+   * Get information about the table name and schema from the prefix.
+   *
+   * @param
+   *   Name of table to look prefix up for. Defaults to 'default' because thats
+   *   default key for prefix.
+   * @param $add_prefix
+   *   Boolean that indicates whether the given table name should be prefixed.
+   *
+   * @return
+   *   A keyed array with information about the schema, table name and prefix.
+   */
+  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
+    $info = array(
+      'schema' => $this->defaultSchema,
+      'prefix' => $this->connection->tablePrefix($table),
+    );
+    if ($add_prefix) {
+      $table = $info['prefix'] . $table;
+    }
+    // If the prefix contains a period in it, then that means the prefix also
+    // contains a schema reference in which case we will change the schema key
+    // to the value before the period in the prefix. Everything after the dot
+    // will be prefixed onto the front of the table.
+    if (($pos = strpos($table, '.')) !== FALSE) {
+      // Grab everything before the period.
+      $info['schema'] = substr($table, 0, $pos);
+      // Grab everything after the dot.
+      $info['table'] = substr($table, ++$pos);
+    }
+    else {
+      $info['table'] = $table;
+    }
+    return $info;
+  }
+
+  /**
+   * Create names for indexes, primary keys and constraints.
+   *
+   * This prevents using {} around non-table names like indexes and keys.
+   */
+  function prefixNonTable($table) {
+    $args = func_get_args();
+    $info = $this->getPrefixInfo($table);
+    $args[0] = $info['table'];
+    return implode('_', $args);
+  }
+
+  /**
+   * Build a condition to match a table name against a standard information_schema.
+   *
+   * The information_schema is a SQL standard that provides information about the
+   * database server and the databases, schemas, tables, columns and users within
+   * it. This makes information_schema a useful tool to use across the drupal
+   * database drivers and is used by a few different functions. The function below
+   * describes the conditions to be meet when querying information_schema.tables
+   * for drupal tables or information associated with drupal tables. Even though
+   * this is the standard method, not all databases follow standards and so this
+   * method should be overwritten by a database driver if the database provider
+   * uses alternate methods. Because information_schema.tables is used in a few
+   * different functions, a database driver will only need to override this function
+   * to make all the others work. For example see
+   * core/includes/databases/mysql/schema.inc.
+   *
+   * @param $table_name
+   *   The name of the table in question.
+   * @param $operator
+   *   The operator to apply on the 'table' part of the condition.
+   * @param $add_prefix
+   *   Boolean to indicate whether the table name needs to be prefixed.
+   *
+   * @return QueryConditionInterface
+   *   A DatabaseCondition object.
+   */
+  protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
+    $info = $this->connection->getConnectionOptions();
+
+    // Retrive the table name and schema
+    $table_info = $this->getPrefixInfo($table_name, $add_prefix);
+
+    $condition = new DatabaseCondition('AND');
+    $condition->condition('table_catalog', $info['database']);
+    $condition->condition('table_schema', $table_info['schema']);
+    $condition->condition('table_name', $table_info['table'], $operator);
+    return $condition;
+  }
+
+  /**
+   * Check if a table exists.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   *
+   * @return
+   *   TRUE if the given table exists, otherwise FALSE.
+   */
+  public function tableExists($table) {
+    $condition = $this->buildTableNameCondition($table);
+    $condition->compile($this->connection, $this);
+    // Normally, we would heartily discourage the use of string
+    // concatenation for conditionals like this however, we
+    // couldn't use db_select() here because it would prefix
+    // information_schema.tables and the query would fail.
+    // Don't use {} around information_schema.tables table.
+    return (bool) $this->connection->query("SELECT 1 FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
+  }
+
+  /**
+   * Find all tables that are like the specified base table name.
+   *
+   * @param $table_expression
+   *   An SQL expression, for example "simpletest%" (without the quotes).
+   *   BEWARE: this is not prefixed, the caller should take care of that.
+   *
+   * @return
+   *   Array, both the keys and the values are the matching tables.
+   */
+  public function findTables($table_expression) {
+    $condition = $this->buildTableNameCondition($table_expression, 'LIKE', FALSE);
+
+    $condition->compile($this->connection, $this);
+    // Normally, we would heartily discourage the use of string
+    // concatenation for conditionals like this however, we
+    // couldn't use db_select() here because it would prefix
+    // information_schema.tables and the query would fail.
+    // Don't use {} around information_schema.tables table.
+    return $this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0);
+  }
+
+  /**
+   * Check if a column exists in the given table.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   * @param $name
+   *   The name of the column.
+   *
+   * @return
+   *   TRUE if the given column exists, otherwise FALSE.
+   */
+  public function fieldExists($table, $column) {
+    $condition = $this->buildTableNameCondition($table);
+    $condition->condition('column_name', $column);
+    $condition->compile($this->connection, $this);
+    // Normally, we would heartily discourage the use of string
+    // concatenation for conditionals like this however, we
+    // couldn't use db_select() here because it would prefix
+    // information_schema.tables and the query would fail.
+    // Don't use {} around information_schema.columns table.
+    return (bool) $this->connection->query("SELECT 1 FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
+  }
+
+  /**
+   * Returns a mapping of Drupal schema field names to DB-native field types.
+   *
+   * Because different field types do not map 1:1 between databases, Drupal has
+   * its own normalized field type names. This function returns a driver-specific
+   * mapping table from Drupal names to the native names for each database.
+   *
+   * @return array
+   *   An array of Schema API field types to driver-specific field types.
+   */
+  abstract public function getFieldTypeMap();
+
+  /**
+   * Rename a table.
+   *
+   * @param $table
+   *   The table to be renamed.
+   * @param $new_name
+   *   The new name for the table.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If a table with the specified new name already exists.
+   */
+  abstract public function renameTable($table, $new_name);
+
+  /**
+   * Drop a table.
+   *
+   * @param $table
+   *   The table to be dropped.
+   *
+   * @return
+   *   TRUE if the table was successfully dropped, FALSE if there was no table
+   *   by that name to begin with.
+   */
+  abstract public function dropTable($table);
+
+  /**
+   * Add a new field to a table.
+   *
+   * @param $table
+   *   Name of the table to be altered.
+   * @param $field
+   *   Name of the field to be added.
+   * @param $spec
+   *   The field specification array, as taken from a schema definition.
+   *   The specification may also contain the key 'initial', the newly
+   *   created field will be set to the value of the key in all rows.
+   *   This is most useful for creating NOT NULL columns with no default
+   *   value in existing tables.
+   * @param $keys_new
+   *   Optional keys and indexes specification to be created on the
+   *   table along with adding the field. The format is the same as a
+   *   table specification but without the 'fields' element. If you are
+   *   adding a type 'serial' field, you MUST specify at least one key
+   *   or index including it in this array. See db_change_field() for more
+   *   explanation why.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified table already has a field by that name.
+   */
+  abstract public function addField($table, $field, $spec, $keys_new = array());
+
+  /**
+   * Drop a field.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be dropped.
+   *
+   * @return
+   *   TRUE if the field was successfully dropped, FALSE if there was no field
+   *   by that name to begin with.
+   */
+  abstract public function dropField($table, $field);
+
+  /**
+   * Set the default value for a field.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be altered.
+   * @param $default
+   *   Default value to be set. NULL for 'default NULL'.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table or field doesn't exist.
+   */
+  abstract public function fieldSetDefault($table, $field, $default);
+
+  /**
+   * Set a field to have no default value.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $field
+   *   The field to be altered.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table or field doesn't exist.
+   */
+  abstract public function fieldSetNoDefault($table, $field);
+
+  /**
+   * Checks if an index exists in the given table.
+   *
+   * @param $table
+   *   The name of the table in drupal (no prefixing).
+   * @param $name
+   *   The name of the index in drupal (no prefixing).
+   *
+   * @return
+   *   TRUE if the given index exists, otherwise FALSE.
+   */
+  abstract public function indexExists($table, $name);
+
+  /**
+   * Add a primary key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $fields
+   *   Fields for the primary key.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified table already has a primary key.
+   */
+  abstract public function addPrimaryKey($table, $fields);
+
+  /**
+   * Drop the primary key.
+   *
+   * @param $table
+   *   The table to be altered.
+   *
+   * @return
+   *   TRUE if the primary key was successfully dropped, FALSE if there was no
+   *   primary key on this table to begin with.
+   */
+  abstract public function dropPrimaryKey($table);
+
+  /**
+   * Add a unique key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the key.
+   * @param $fields
+   *   An array of field names.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified table already has a key by that name.
+   */
+  abstract public function addUniqueKey($table, $name, $fields);
+
+  /**
+   * Drop a unique key.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the key.
+   *
+   * @return
+   *   TRUE if the key was successfully dropped, FALSE if there was no key by
+   *   that name to begin with.
+   */
+  abstract public function dropUniqueKey($table, $name);
+
+  /**
+   * Add an index.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the index.
+   * @param $fields
+   *   An array of field names.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified table already has an index by that name.
+   */
+  abstract public function addIndex($table, $name, $fields);
+
+  /**
+   * Drop an index.
+   *
+   * @param $table
+   *   The table to be altered.
+   * @param $name
+   *   The name of the index.
+   *
+   * @return
+   *   TRUE if the index was successfully dropped, FALSE if there was no index
+   *   by that name to begin with.
+   */
+  abstract public function dropIndex($table, $name);
+
+  /**
+   * Change a field definition.
+   *
+   * IMPORTANT NOTE: To maintain database portability, you have to explicitly
+   * recreate all indices and primary keys that are using the changed field.
+   *
+   * That means that you have to drop all affected keys and indexes with
+   * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
+   * To recreate the keys and indices, pass the key definitions as the
+   * optional $keys_new argument directly to db_change_field().
+   *
+   * For example, suppose you have:
+   * @code
+   * $schema['foo'] = array(
+   *   'fields' => array(
+   *     'bar' => array('type' => 'int', 'not null' => TRUE)
+   *   ),
+   *   'primary key' => array('bar')
+   * );
+   * @endcode
+   * and you want to change foo.bar to be type serial, leaving it as the
+   * primary key. The correct sequence is:
+   * @code
+   * db_drop_primary_key('foo');
+   * db_change_field('foo', 'bar', 'bar',
+   *   array('type' => 'serial', 'not null' => TRUE),
+   *   array('primary key' => array('bar')));
+   * @endcode
+   *
+   * The reasons for this are due to the different database engines:
+   *
+   * On PostgreSQL, changing a field definition involves adding a new field
+   * and dropping an old one which* causes any indices, primary keys and
+   * sequences (from serial-type fields) that use the changed field to be dropped.
+   *
+   * On MySQL, all type 'serial' fields must be part of at least one key
+   * or index as soon as they are created. You cannot use
+   * db_add_{primary_key,unique_key,index}() for this purpose because
+   * the ALTER TABLE command will fail to add the column without a key
+   * or index specification. The solution is to use the optional
+   * $keys_new argument to create the key or index at the same time as
+   * field.
+   *
+   * You could use db_add_{primary_key,unique_key,index}() in all cases
+   * unless you are converting a field to be type serial. You can use
+   * the $keys_new argument in all cases.
+   *
+   * @param $table
+   *   Name of the table.
+   * @param $field
+   *   Name of the field to change.
+   * @param $field_new
+   *   New name for the field (set to the same as $field if you don't want to change the name).
+   * @param $spec
+   *   The field specification for the new field.
+   * @param $keys_new
+   *   Optional keys and indexes specification to be created on the
+   *   table along with changing the field. The format is the same as a
+   *   table specification but without the 'fields' element.
+   *
+   * @throws DatabaseSchemaObjectDoesNotExistException
+   *   If the specified table or source field doesn't exist.
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified destination field already exists.
+   */
+  abstract public function changeField($table, $field, $field_new, $spec, $keys_new = array());
+
+  /**
+   * Create a new table from a Drupal table definition.
+   *
+   * @param $name
+   *   The name of the table to create.
+   * @param $table
+   *   A Schema API table definition array.
+   *
+   * @throws DatabaseSchemaObjectExistsException
+   *   If the specified table already exists.
+   */
+  public function createTable($name, $table) {
+    if ($this->tableExists($name)) {
+      throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
+    }
+    $statements = $this->createTableSql($name, $table);
+    foreach ($statements as $statement) {
+      $this->connection->query($statement);
+    }
+  }
+
+  /**
+   * Return an array of field names from an array of key/index column specifiers.
+   *
+   * This is usually an identity function but if a key/index uses a column prefix
+   * specification, this function extracts just the name.
+   *
+   * @param $fields
+   *   An array of key/index column specifiers.
+   *
+   * @return
+   *   An array of field names.
+   */
+  public function fieldNames($fields) {
+    $return = array();
+    foreach ($fields as $field) {
+      if (is_array($field)) {
+        $return[] = $field[0];
+      }
+      else {
+        $return[] = $field;
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Prepare a table or column comment for database query.
+   *
+   * @param $comment
+   *   The comment string to prepare.
+   * @param $length
+   *   Optional upper limit on the returned string length.
+   *
+   * @return
+   *   The prepared comment.
+   */
+  public function prepareComment($comment, $length = NULL) {
+    return $this->connection->quote($comment);
+  }
+}
diff --git a/core/includes/Drupal/Database/DatabaseSchemaObjectDoesNotExistException.php b/core/includes/Drupal/Database/DatabaseSchemaObjectDoesNotExistException.php
new file mode 100644
index 0000000..28ed22b
--- /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 0000000..1a96b16
--- /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 0000000..19020f9
--- /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 0000000..fee3ffd
--- /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 0000000..37d3056
--- /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/Drupal/Database/DatabaseStatementPrefetch.php b/core/includes/Drupal/Database/DatabaseStatementPrefetch.php
new file mode 100644
index 0000000..5c0419a
--- /dev/null
+++ b/core/includes/Drupal/Database/DatabaseStatementPrefetch.php
@@ -0,0 +1,495 @@
+<?php
+
+namespace Drupal\Database;
+
+use Drupal\Database\Connection;
+use Iterator;
+use PDO;
+
+/**
+ * An implementation of DatabaseStatementInterface that prefetches all data.
+ *
+ * This class behaves very similar to a PDOStatement but as it always fetches
+ * every row it is possible to manipulate those results.
+ */
+class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface {
+
+  /**
+   * The query string.
+   *
+   * @var string
+   */
+  protected $queryString;
+
+  /**
+   * Driver-specific options. Can be used by child classes.
+   *
+   * @var Array
+   */
+  protected $driverOptions;
+
+  /**
+   * Reference to the database connection object for this statement.
+   *
+   * The name $dbh is inherited from PDOStatement.
+   *
+   * @var DatabaseConnection
+   */
+  public $dbh;
+
+  /**
+   * Main data store.
+   *
+   * @var Array
+   */
+  protected $data = array();
+
+  /**
+   * The current row, retrieved in PDO::FETCH_ASSOC format.
+   *
+   * @var Array
+   */
+  protected $currentRow = NULL;
+
+  /**
+   * The key of the current row.
+   *
+   * @var int
+   */
+  protected $currentKey = NULL;
+
+  /**
+   * The list of column names in this result set.
+   *
+   * @var Array
+   */
+  protected $columnNames = NULL;
+
+  /**
+   * The number of rows affected by the last query.
+   *
+   * @var int
+   */
+  protected $rowCount = NULL;
+
+  /**
+   * The number of rows in this result set.
+   *
+   * @var int
+   */
+  protected $resultRowCount = 0;
+
+  /**
+   * Holds the current fetch style (which will be used by the next fetch).
+   * @see PDOStatement::fetch()
+   *
+   * @var int
+   */
+  protected $fetchStyle = PDO::FETCH_OBJ;
+
+  /**
+   * Holds supplementary current fetch options (which will be used by the next fetch).
+   *
+   * @var Array
+   */
+  protected $fetchOptions = array(
+    'class' => 'stdClass',
+    'constructor_args' => array(),
+    'object' => NULL,
+    'column' => 0,
+  );
+
+  /**
+   * Holds the default fetch style.
+   *
+   * @var int
+   */
+  protected $defaultFetchStyle = PDO::FETCH_OBJ;
+
+  /**
+   * Holds supplementary default fetch options.
+   *
+   * @var Array
+   */
+  protected $defaultFetchOptions = array(
+    'class' => 'stdClass',
+    'constructor_args' => array(),
+    'object' => NULL,
+    'column' => 0,
+  );
+
+  public function __construct(Connection $connection, $query, array $driver_options = array()) {
+    $this->dbh = $connection;
+    $this->queryString = $query;
+    $this->driverOptions = $driver_options;
+  }
+
+  /**
+   * 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()) {
+    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);
+    }
+
+    // Prepare the query.
+    $statement = $this->getStatement($this->queryString, $args);
+    if (!$statement) {
+      $this->throwPDOException();
+    }
+
+    $return = $statement->execute($args);
+    if (!$return) {
+      $this->throwPDOException();
+    }
+
+    // Fetch all the data from the reply, in order to release any lock
+    // as soon as possible.
+    $this->rowCount = $statement->rowCount();
+    $this->data = $statement->fetchAll(PDO::FETCH_ASSOC);
+    // Destroy the statement as soon as possible. See
+    // DatabaseConnection_sqlite::PDOPrepare() for explanation.
+    unset($statement);
+
+    $this->resultRowCount = count($this->data);
+
+    if ($this->resultRowCount) {
+      $this->columnNames = array_keys($this->data[0]);
+    }
+    else {
+      $this->columnNames = array();
+    }
+
+    if (!empty($logger)) {
+      $query_end = microtime(TRUE);
+      $logger->log($this, $args, $query_end - $query_start);
+    }
+
+    // Initialize the first row in $this->currentRow.
+    $this->next();
+
+    return $return;
+  }
+
+  /**
+   * Throw a PDO Exception based on the last PDO error.
+   */
+  protected function throwPDOException() {
+    $error_info = $this->dbh->errorInfo();
+    // We rebuild a message formatted in the same way as PDO.
+    $exception = new PDOException("SQLSTATE[" . $error_info[0] . "]: General error " . $error_info[1] . ": " . $error_info[2]);
+    $exception->errorInfo = $error_info;
+    throw $exception;
+  }
+
+  /**
+   * Grab a PDOStatement object from a given query and its arguments.
+   *
+   * Some drivers (including SQLite) will need to perform some preparation
+   * themselves to get the statement right.
+   *
+   * @param $query
+   *   The query.
+   * @param array $args
+   *   An array of arguments.
+   * @return PDOStatement
+   *   A PDOStatement object.
+   */
+  protected function getStatement($query, &$args = array()) {
+    return $this->dbh->prepare($query);
+  }
+
+  /**
+   * Return the object's SQL query string.
+   */
+  public function getQueryString() {
+    return $this->queryString;
+  }
+
+  /**
+   * @see PDOStatement::setFetchMode()
+   */
+  public function setFetchMode($fetchStyle, $a2 = NULL, $a3 = NULL) {
+    $this->defaultFetchStyle = $fetchStyle;
+    switch ($fetchStyle) {
+      case PDO::FETCH_CLASS:
+        $this->defaultFetchOptions['class'] = $a2;
+        if ($a3) {
+          $this->defaultFetchOptions['constructor_args'] = $a3;
+        }
+        break;
+      case PDO::FETCH_COLUMN:
+        $this->defaultFetchOptions['column'] = $a2;
+        break;
+      case PDO::FETCH_INTO:
+        $this->defaultFetchOptions['object'] = $a2;
+        break;
+    }
+
+    // Set the values for the next fetch.
+    $this->fetchStyle = $this->defaultFetchStyle;
+    $this->fetchOptions = $this->defaultFetchOptions;
+  }
+
+  /**
+   * Return the current row formatted according to the current fetch style.
+   *
+   * This is the core method of this class. It grabs the value at the current
+   * array position in $this->data and format it according to $this->fetchStyle
+   * and $this->fetchMode.
+   *
+   * @return
+   *  The current row formatted as requested.
+   */
+  public function current() {
+    if (isset($this->currentRow)) {
+      switch ($this->fetchStyle) {
+        case PDO::FETCH_ASSOC:
+          return $this->currentRow;
+        case PDO::FETCH_BOTH:
+          // PDO::FETCH_BOTH returns an array indexed by both the column name
+          // and the column number.
+          return $this->currentRow + array_values($this->currentRow);
+        case PDO::FETCH_NUM:
+          return array_values($this->currentRow);
+        case PDO::FETCH_LAZY:
+          // We do not do lazy as everything is fetched already. Fallback to
+          // PDO::FETCH_OBJ.
+        case PDO::FETCH_OBJ:
+          return (object) $this->currentRow;
+        case PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE:
+          $class_name = array_unshift($this->currentRow);
+          // Deliberate no break.
+        case PDO::FETCH_CLASS:
+          if (!isset($class_name)) {
+            $class_name = $this->fetchOptions['class'];
+          }
+          if (count($this->fetchOptions['constructor_args'])) {
+            $reflector = new ReflectionClass($class_name);
+            $result = $reflector->newInstanceArgs($this->fetchOptions['constructor_args']);
+          }
+          else {
+            $result = new $class_name();
+          }
+          foreach ($this->currentRow as $k => $v) {
+            $result->$k = $v;
+          }
+          return $result;
+        case PDO::FETCH_INTO:
+          foreach ($this->currentRow as $k => $v) {
+            $this->fetchOptions['object']->$k = $v;
+          }
+          return $this->fetchOptions['object'];
+        case PDO::FETCH_COLUMN:
+          if (isset($this->columnNames[$this->fetchOptions['column']])) {
+            return $this->currentRow[$k][$this->columnNames[$this->fetchOptions['column']]];
+          }
+          else {
+            return;
+          }
+      }
+    }
+  }
+
+  /* Implementations of Iterator. */
+
+  public function key() {
+    return $this->currentKey;
+  }
+
+  public function rewind() {
+    // Nothing to do: our DatabaseStatement can't be rewound.
+  }
+
+  public function next() {
+    if (!empty($this->data)) {
+      $this->currentRow = reset($this->data);
+      $this->currentKey = key($this->data);
+      unset($this->data[$this->currentKey]);
+    }
+    else {
+      $this->currentRow = NULL;
+    }
+  }
+
+  public function valid() {
+    return isset($this->currentRow);
+  }
+
+  /* Implementations of DatabaseStatementInterface. */
+
+  public function rowCount() {
+    return $this->rowCount;
+  }
+
+  public function fetch($fetch_style = NULL, $cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = NULL) {
+    if (isset($this->currentRow)) {
+      // Set the fetch parameter.
+      $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
+      $this->fetchOptions = $this->defaultFetchOptions;
+
+      // Grab the row in the format specified above.
+      $return = $this->current();
+      // Advance the cursor.
+      $this->next();
+
+      // Reset the fetch parameters to the value stored using setFetchMode().
+      $this->fetchStyle = $this->defaultFetchStyle;
+      $this->fetchOptions = $this->defaultFetchOptions;
+      return $return;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  public function fetchColumn($index = 0) {
+    if (isset($this->currentRow) && isset($this->columnNames[$index])) {
+      // We grab the value directly from $this->data, and format it.
+      $return = $this->currentRow[$this->columnNames[$index]];
+      $this->next();
+      return $return;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  public function fetchField($index = 0) {
+    return $this->fetchColumn($index);
+  }
+
+  public function fetchObject($class_name = NULL, $constructor_args = array()) {
+    if (isset($this->currentRow)) {
+      if (!isset($class_name)) {
+        // Directly cast to an object to avoid a function call.
+        $result = (object) $this->currentRow;
+      }
+      else {
+        $this->fetchStyle = PDO::FETCH_CLASS;
+        $this->fetchOptions = array('constructor_args' => $constructor_args);
+        // Grab the row in the format specified above.
+        $result = $this->current();
+        // Reset the fetch parameters to the value stored using setFetchMode().
+        $this->fetchStyle = $this->defaultFetchStyle;
+        $this->fetchOptions = $this->defaultFetchOptions;
+      }
+
+      $this->next();
+
+      return $result;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  public function fetchAssoc() {
+    if (isset($this->currentRow)) {
+      $result = $this->currentRow;
+      $this->next();
+      return $result;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  public function fetchAll($fetch_style = NULL, $fetch_column = NULL, $constructor_args = NULL) {
+    $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
+    $this->fetchOptions = $this->defaultFetchOptions;
+    if (isset($fetch_column)) {
+      $this->fetchOptions['column'] = $fetch_column;
+    }
+    if (isset($constructor_args)) {
+      $this->fetchOptions['constructor_args'] = $constructor_args;
+    }
+
+    $result = array();
+    // Traverse the array as PHP would have done.
+    while (isset($this->currentRow)) {
+      // Grab the row in the format specified above.
+      $result[] = $this->current();
+      $this->next();
+    }
+
+    // Reset the fetch parameters to the value stored using setFetchMode().
+    $this->fetchStyle = $this->defaultFetchStyle;
+    $this->fetchOptions = $this->defaultFetchOptions;
+    return $result;
+  }
+
+  public function fetchCol($index = 0) {
+    if (isset($this->columnNames[$index])) {
+      $column = $this->columnNames[$index];
+      $result = array();
+      // Traverse the array as PHP would have done.
+      while (isset($this->currentRow)) {
+        $result[] = $this->currentRow[$this->columnNames[$index]];
+        $this->next();
+      }
+      return $result;
+    }
+    else {
+      return array();
+    }
+  }
+
+  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
+    if (!isset($this->columnNames[$key_index]) || !isset($this->columnNames[$value_index]))
+      return array();
+
+    $key = $this->columnNames[$key_index];
+    $value = $this->columnNames[$value_index];
+
+    $result = array();
+    // Traverse the array as PHP would have done.
+    while (isset($this->currentRow)) {
+      $result[$this->currentRow[$key]] = $this->currentRow[$value];
+      $this->next();
+    }
+    return $result;
+  }
+
+  public function fetchAllAssoc($key, $fetch_style = NULL) {
+    $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
+    $this->fetchOptions = $this->defaultFetchOptions;
+
+    $result = array();
+    // Traverse the array as PHP would have done.
+    while (isset($this->currentRow)) {
+      // Grab the row in its raw PDO::FETCH_ASSOC format.
+      $row = $this->currentRow;
+      // Grab the row in the format specified above.
+      $result_row = $this->current();
+      $result[$this->currentRow[$key]] = $result_row;
+      $this->next();
+    }
+
+    // Reset the fetch parameters to the value stored using setFetchMode().
+    $this->fetchStyle = $this->defaultFetchStyle;
+    $this->fetchOptions = $this->defaultFetchOptions;
+    return $result;
+  }
+
+}
diff --git a/core/includes/Drupal/Database/DatabaseTransactionCommitFailedException.php b/core/includes/Drupal/Database/DatabaseTransactionCommitFailedException.php
new file mode 100644
index 0000000..0df9490
--- /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 0000000..8e38d8b
--- /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 0000000..857ebe1
--- /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 0000000..25d749d
--- /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 0000000..452632e
--- /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/Drupal/Database/Driver/mysql/Connection.php b/core/includes/Drupal/Database/Driver/mysql/Connection.php
new file mode 100644
index 0000000..1f82247
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Connection.php
@@ -0,0 +1,202 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Connection as DatabaseConnection;
+
+use PDO;
+
+/**
+ * @ingroup database
+ * @{
+ */
+
+class Connection extends DatabaseConnection {
+
+  /**
+   * Flag to indicate if we have registered the nextID cleanup function.
+   *
+   * @var boolean
+   */
+  protected $shutdownRegistered = FALSE;
+
+  public function __construct(array $connection_options = array()) {
+    // This driver defaults to transaction support, except if explicitly passed FALSE.
+    $this->transactionSupport = !isset($connection_options['transactions']) || ($connection_options['transactions'] !== FALSE);
+
+    // MySQL never supports transactional DDL.
+    $this->transactionalDDLSupport = FALSE;
+
+    $this->connectionOptions = $connection_options;
+
+    // The DSN should use either a socket or a host/port.
+    if (isset($connection_options['unix_socket'])) {
+      $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
+    }
+    else {
+      // Default to TCP connection on port 3306.
+      $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
+    }
+    $dsn .= ';dbname=' . $connection_options['database'];
+    // Allow PDO options to be overridden.
+    $connection_options += array(
+      'pdo' => array(),
+    );
+    $connection_options['pdo'] += array(
+      // So we don't have to mess around with cursors and unbuffered queries by default.
+      PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
+      // Because MySQL's prepared statements skip the query cache, because it's dumb.
+      PDO::ATTR_EMULATE_PREPARES => TRUE,
+      // Force column names to lower case.
+      PDO::ATTR_CASE => PDO::CASE_LOWER,
+    );
+
+    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
+
+    // Force MySQL to use the UTF-8 character set. Also set the collation, if a
+    // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
+    // for UTF-8.
+    if (!empty($connection_options['collation'])) {
+      $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
+    }
+    else {
+      $this->exec('SET NAMES utf8');
+    }
+
+    // Set MySQL init_commands if not already defined.  Default Drupal's MySQL
+    // behavior to conform more closely to SQL standards.  This allows Drupal
+    // to run almost seamlessly on many different kinds of database systems.
+    // These settings force MySQL to behave the same as postgresql, or sqlite
+    // in regards to syntax interpretation and invalid data handling.  See
+    // http://drupal.org/node/344575 for further discussion. Also, as MySQL 5.5
+    // changed the meaning of TRADITIONAL we need to spell out the modes one by
+    // one.
+    $connection_options += array(
+      'init_commands' => array(),
+    );
+    $connection_options['init_commands'] += array(
+      'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
+    );
+    // Set connection options.
+    $this->exec(implode('; ', $connection_options['init_commands']));
+  }
+
+  public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
+    return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
+  }
+
+  public function queryTemporary($query, array $args = array(), array $options = array()) {
+    $tablename = $this->generateTemporaryTableName();
+    $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY SELECT', $query), $args, $options);
+    return $tablename;
+  }
+
+  public function driver() {
+    return 'mysql';
+  }
+
+  public function databaseType() {
+    return 'mysql';
+  }
+
+  public function mapConditionOperator($operator) {
+    // We don't want to override any of the defaults.
+    return NULL;
+  }
+
+  public function nextId($existing_id = 0) {
+    $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
+    // This should only happen after an import or similar event.
+    if ($existing_id >= $new_id) {
+      // If we INSERT a value manually into the sequences table, on the next
+      // INSERT, MySQL will generate a larger value. However, there is no way
+      // of knowing whether this value already exists in the table. MySQL
+      // provides an INSERT IGNORE which would work, but that can mask problems
+      // other than duplicate keys. Instead, we use INSERT ... ON DUPLICATE KEY
+      // UPDATE in such a way that the UPDATE does not do anything. This way,
+      // duplicate keys do not generate errors but everything else does.
+      $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
+      $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
+    }
+    if (!$this->shutdownRegistered) {
+      // Use register_shutdown_function() here to keep the database system
+      // independent of Drupal.
+      register_shutdown_function(array($this, 'nextIdDelete'));
+      $shutdownRegistered = TRUE;
+    }
+    return $new_id;
+  }
+
+  public function nextIdDelete() {
+    // While we want to clean up the table to keep it up from occupying too
+    // much storage and memory, we must keep the highest value in the table
+    // because InnoDB  uses an in-memory auto-increment counter as long as the
+    // server runs. When the server is stopped and restarted, InnoDB
+    // reinitializes the counter for each table for the first INSERT to the
+    // table based solely on values from the table so deleting all values would
+    // be a problem in this case. Also, TRUNCATE resets the auto increment
+    // counter.
+    try {
+      $max_id = $this->query('SELECT MAX(value) FROM {sequences}')->fetchField();
+      // We know we are using MySQL here, no need for the slower db_delete().
+      $this->query('DELETE FROM {sequences} WHERE value < :value', array(':value' => $max_id));
+    }
+    // During testing, this function is called from shutdown with the
+    // simpletest prefix stored in $this->connection, and those tables are gone
+    // by the time shutdown is called so we need to ignore the database
+    // errors. There is no problem with completely ignoring errors here: if
+    // these queries fail, the sequence will work just fine, just use a bit
+    // more database storage and memory.
+    catch (PDOException $e) {
+    }
+  }
+
+  /**
+   * Overridden to work around issues to MySQL not supporting transactional DDL.
+   */
+  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 (!PDO::commit()) {
+          throw new DatabaseTransactionCommitFailedException();
+        }
+      }
+      else {
+        // Attempt to release this savepoint in the standard way.
+        try {
+          $this->query('RELEASE SAVEPOINT ' . $name);
+        }
+        catch (PDOException $e) {
+          // However, in MySQL (InnoDB), savepoints are automatically committed
+          // when tables are altered or created (DDL transactions are not
+          // supported). This can cause exceptions due to trying to release
+          // savepoints which no longer exist.
+          //
+          // To avoid exceptions when no actual error has occurred, we silently
+          // succeed for MySQL error code 1305 ("SAVEPOINT does not exist").
+          if ($e->errorInfo[1] == '1305') {
+            // If one SAVEPOINT was released automatically, then all were.
+            // Therefore, we keep just the topmost transaction.
+            $this->transactionLayers = array('drupal_transaction' => 'drupal_transaction');
+          }
+          else {
+            throw $e;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+/**
+ * @} End of "ingroup database".
+ */
diff --git a/core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php b/core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php
new file mode 100644
index 0000000..41b92f3
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/DatabaseSchema.php
@@ -0,0 +1,529 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\DatabaseSchema as DatabaseDatabaseSchema;
+
+/**
+ * @ingroup schemaapi
+ * @{
+ */
+
+class DatabaseSchema extends DatabaseDatabaseSchema {
+
+  /**
+   * Maximum length of a table comment in MySQL.
+   */
+  const COMMENT_MAX_TABLE = 60;
+
+  /**
+   * Maximum length of a column comment in MySQL.
+   */
+  const COMMENT_MAX_COLUMN = 255;
+
+  /**
+   * Get information about the table and database name from the prefix.
+   *
+   * @return
+   *   A keyed array with information about the database, table name and prefix.
+   */
+  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
+    $info = array('prefix' => $this->connection->tablePrefix($table));
+    if ($add_prefix) {
+      $table = $info['prefix'] . $table;
+    }
+    if (($pos = strpos($table, '.')) !== FALSE) {
+      $info['database'] = substr($table, 0, $pos);
+      $info['table'] = substr($table, ++$pos);
+    }
+    else {
+      $db_info = Database::getConnectionInfo();
+      $info['database'] = $db_info['default']['database'];
+      $info['table'] = $table;
+    }
+    return $info;
+  }
+
+  /**
+   * Build a condition to match a table name against a standard information_schema.
+   *
+   * MySQL uses databases like schemas rather than catalogs so when we build
+   * a condition to query the information_schema.tables, we set the default
+   * database as the schema unless specified otherwise, and exclude table_catalog
+   * from the condition criteria.
+   */
+  protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
+    $info = $this->connection->getConnectionOptions();
+
+    $table_info = $this->getPrefixInfo($table_name, $add_prefix);
+
+    $condition = new DatabaseCondition('AND');
+    $condition->condition('table_schema', $table_info['database']);
+    $condition->condition('table_name', $table_info['table'], $operator);
+    return $condition;
+  }
+
+  /**
+   * Generate SQL to create a new table from a Drupal schema definition.
+   *
+   * @param $name
+   *   The name of the table to create.
+   * @param $table
+   *   A Schema API table definition array.
+   * @return
+   *   An array of SQL statements to create the table.
+   */
+  protected function createTableSql($name, $table) {
+    $info = $this->connection->getConnectionOptions();
+
+    // Provide defaults if needed.
+    $table += array(
+      'mysql_engine' => 'InnoDB',
+      'mysql_character_set' => 'utf8',
+    );
+
+    $sql = "CREATE TABLE {" . $name . "} (\n";
+
+    // Add the SQL statement for each field.
+    foreach ($table['fields'] as $field_name => $field) {
+      $sql .= $this->createFieldSql($field_name, $this->processField($field)) . ", \n";
+    }
+
+    // Process keys & indexes.
+    $keys = $this->createKeysSql($table);
+    if (count($keys)) {
+      $sql .= implode(", \n", $keys) . ", \n";
+    }
+
+    // Remove the last comma and space.
+    $sql = substr($sql, 0, -3) . "\n) ";
+
+    $sql .= 'ENGINE = ' . $table['mysql_engine'] . ' DEFAULT CHARACTER SET ' . $table['mysql_character_set'];
+    // By default, MySQL uses the default collation for new tables, which is
+    // 'utf8_general_ci' for utf8. If an alternate collation has been set, it
+    // needs to be explicitly specified.
+    // @see DatabaseConnection_mysql
+    if (!empty($info['collation'])) {
+      $sql .= ' COLLATE ' . $info['collation'];
+    }
+
+    // Add table comment.
+    if (!empty($table['description'])) {
+      $sql .= ' COMMENT ' . $this->prepareComment($table['description'], self::COMMENT_MAX_TABLE);
+    }
+
+    return array($sql);
+  }
+
+  /**
+   * Create an SQL string for a field to be used in table creation or alteration.
+   *
+   * Before passing a field out of a schema definition into this function it has
+   * to be processed by _db_process_field().
+   *
+   * @param $name
+   *   Name of the field.
+   * @param $spec
+   *   The field specification, as per the schema data structure format.
+   */
+  protected function createFieldSql($name, $spec) {
+    $sql = "`" . $name . "` " . $spec['mysql_type'];
+
+    if (in_array($spec['mysql_type'], array('VARCHAR', 'CHAR', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'TEXT')) && isset($spec['length'])) {
+      $sql .= '(' . $spec['length'] . ')';
+    }
+    elseif (isset($spec['precision']) && isset($spec['scale'])) {
+      $sql .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
+    }
+
+    if (!empty($spec['unsigned'])) {
+      $sql .= ' unsigned';
+    }
+
+    if (isset($spec['not null'])) {
+      if ($spec['not null']) {
+        $sql .= ' NOT NULL';
+      }
+      else {
+        $sql .= ' NULL';
+      }
+    }
+
+    if (!empty($spec['auto_increment'])) {
+      $sql .= ' auto_increment';
+    }
+
+    // $spec['default'] can be NULL, so we explicitly check for the key here.
+    if (array_key_exists('default', $spec)) {
+      if (is_string($spec['default'])) {
+        $spec['default'] = "'" . $spec['default'] . "'";
+      }
+      elseif (!isset($spec['default'])) {
+        $spec['default'] = 'NULL';
+      }
+      $sql .= ' DEFAULT ' . $spec['default'];
+    }
+
+    if (empty($spec['not null']) && !isset($spec['default'])) {
+      $sql .= ' DEFAULT NULL';
+    }
+
+    // Add column comment.
+    if (!empty($spec['description'])) {
+      $sql .= ' COMMENT ' . $this->prepareComment($spec['description'], self::COMMENT_MAX_COLUMN);
+    }
+
+    return $sql;
+  }
+
+  /**
+   * Set database-engine specific properties for a field.
+   *
+   * @param $field
+   *   A field description array, as specified in the schema documentation.
+   */
+  protected function processField($field) {
+
+    if (!isset($field['size'])) {
+      $field['size'] = 'normal';
+    }
+
+    // Set the correct database-engine specific datatype.
+    // In case one is already provided, force it to uppercase.
+    if (isset($field['mysql_type'])) {
+      $field['mysql_type'] = drupal_strtoupper($field['mysql_type']);
+    }
+    else {
+      $map = $this->getFieldTypeMap();
+      $field['mysql_type'] = $map[$field['type'] . ':' . $field['size']];
+    }
+
+    if (isset($field['type']) && $field['type'] == 'serial') {
+      $field['auto_increment'] = TRUE;
+    }
+
+    return $field;
+  }
+
+  public function getFieldTypeMap() {
+    // Put :normal last so it gets preserved by array_flip. This makes
+    // it much easier for modules (such as schema.module) to map
+    // database types back into schema types.
+    // $map does not use drupal_static as its value never changes.
+    static $map = array(
+      'varchar:normal'  => 'VARCHAR',
+      'char:normal'     => 'CHAR',
+
+      'text:tiny'       => 'TINYTEXT',
+      'text:small'      => 'TINYTEXT',
+      'text:medium'     => 'MEDIUMTEXT',
+      'text:big'        => 'LONGTEXT',
+      'text:normal'     => 'TEXT',
+
+      'serial:tiny'     => 'TINYINT',
+      'serial:small'    => 'SMALLINT',
+      'serial:medium'   => 'MEDIUMINT',
+      'serial:big'      => 'BIGINT',
+      'serial:normal'   => 'INT',
+
+      'int:tiny'        => 'TINYINT',
+      'int:small'       => 'SMALLINT',
+      'int:medium'      => 'MEDIUMINT',
+      'int:big'         => 'BIGINT',
+      'int:normal'      => 'INT',
+
+      'float:tiny'      => 'FLOAT',
+      'float:small'     => 'FLOAT',
+      'float:medium'    => 'FLOAT',
+      'float:big'       => 'DOUBLE',
+      'float:normal'    => 'FLOAT',
+
+      'numeric:normal'  => 'DECIMAL',
+
+      'blob:big'        => 'LONGBLOB',
+      'blob:normal'     => 'BLOB',
+    );
+    return $map;
+  }
+
+  protected function createKeysSql($spec) {
+    $keys = array();
+
+    if (!empty($spec['primary key'])) {
+      $keys[] = 'PRIMARY KEY (' . $this->createKeysSqlHelper($spec['primary key']) . ')';
+    }
+    if (!empty($spec['unique keys'])) {
+      foreach ($spec['unique keys'] as $key => $fields) {
+        $keys[] = 'UNIQUE KEY `' . $key . '` (' . $this->createKeysSqlHelper($fields) . ')';
+      }
+    }
+    if (!empty($spec['indexes'])) {
+      foreach ($spec['indexes'] as $index => $fields) {
+        $keys[] = 'INDEX `' . $index . '` (' . $this->createKeysSqlHelper($fields) . ')';
+      }
+    }
+
+    return $keys;
+  }
+
+  protected function createKeySql($fields) {
+    $return = array();
+    foreach ($fields as $field) {
+      if (is_array($field)) {
+        $return[] = '`' . $field[0] . '`(' . $field[1] . ')';
+      }
+      else {
+        $return[] = '`' . $field . '`';
+      }
+    }
+    return implode(', ', $return);
+  }
+
+  protected function createKeysSqlHelper($fields) {
+    $return = array();
+    foreach ($fields as $field) {
+      if (is_array($field)) {
+        $return[] = '`' . $field[0] . '`(' . $field[1] . ')';
+      }
+      else {
+        $return[] = '`' . $field . '`';
+      }
+    }
+    return implode(', ', $return);
+  }
+
+  public function renameTable($table, $new_name) {
+    if (!$this->tableExists($table)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
+    }
+    if ($this->tableExists($new_name)) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
+    }
+
+    $info = $this->getPrefixInfo($new_name);
+    return $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO `' . $info['table'] . '`');
+  }
+
+  public function dropTable($table) {
+    if (!$this->tableExists($table)) {
+      return FALSE;
+    }
+
+    $this->connection->query('DROP TABLE {' . $table . '}');
+    return TRUE;
+  }
+
+  public function addField($table, $field, $spec, $keys_new = array()) {
+    if (!$this->tableExists($table)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
+    }
+    if ($this->fieldExists($table, $field)) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
+    }
+
+    $fixnull = FALSE;
+    if (!empty($spec['not null']) && !isset($spec['default'])) {
+      $fixnull = TRUE;
+      $spec['not null'] = FALSE;
+    }
+    $query = 'ALTER TABLE {' . $table . '} ADD ';
+    $query .= $this->createFieldSql($field, $this->processField($spec));
+    if ($keys_sql = $this->createKeysSql($keys_new)) {
+      $query .= ', ADD ' . implode(', ADD ', $keys_sql);
+    }
+    $this->connection->query($query);
+    if (isset($spec['initial'])) {
+      $this->connection->update($table)
+        ->fields(array($field => $spec['initial']))
+        ->execute();
+    }
+    if ($fixnull) {
+      $spec['not null'] = TRUE;
+      $this->changeField($table, $field, $field, $spec);
+    }
+  }
+
+  public function dropField($table, $field) {
+    if (!$this->fieldExists($table, $field)) {
+      return FALSE;
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`');
+    return TRUE;
+  }
+
+  public function fieldSetDefault($table, $field, $default) {
+    if (!$this->fieldExists($table, $field)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+    }
+
+    if (!isset($default)) {
+      $default = 'NULL';
+    }
+    else {
+      $default = is_string($default) ? "'$default'" : $default;
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` SET DEFAULT ' . $default);
+  }
+
+  public function fieldSetNoDefault($table, $field) {
+    if (!$this->fieldExists($table, $field)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
+  }
+
+  public function indexExists($table, $name) {
+    // Returns one row for each column in the index. Result is string or FALSE.
+    // Details at http://dev.mysql.com/doc/refman/5.0/en/show-index.html
+    $row = $this->connection->query('SHOW INDEX FROM {' . $table . "} WHERE key_name = '$name'")->fetchAssoc();
+    return isset($row['key_name']);
+  }
+
+  public function addPrimaryKey($table, $fields) {
+    if (!$this->tableExists($table)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
+    }
+    if ($this->indexExists($table, 'PRIMARY')) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
+  }
+
+  public function dropPrimaryKey($table) {
+    if (!$this->indexExists($table, 'PRIMARY')) {
+      return FALSE;
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP PRIMARY KEY');
+    return TRUE;
+  }
+
+  public function addUniqueKey($table, $name, $fields) {
+    if (!$this->tableExists($table)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+    }
+    if ($this->indexExists($table, $name)) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
+  }
+
+  public function dropUniqueKey($table, $name) {
+    if (!$this->indexExists($table, $name)) {
+      return FALSE;
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY `' . $name . '`');
+    return TRUE;
+  }
+
+  public function addIndex($table, $name, $fields) {
+    if (!$this->tableExists($table)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
+    }
+    if ($this->indexExists($table, $name)) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
+  }
+
+  public function dropIndex($table, $name) {
+    if (!$this->indexExists($table, $name)) {
+      return FALSE;
+    }
+
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX `' . $name . '`');
+    return TRUE;
+  }
+
+  public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
+    if (!$this->fieldExists($table, $field)) {
+      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
+    }
+    if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
+      throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
+    }
+
+    $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec));
+    if ($keys_sql = $this->createKeysSql($keys_new)) {
+      $sql .= ', ADD ' . implode(', ADD ', $keys_sql);
+    }
+    $this->connection->query($sql);
+  }
+
+  public function prepareComment($comment, $length = NULL) {
+    // Work around a bug in some versions of PDO, see http://bugs.php.net/bug.php?id=41125
+    $comment = str_replace("'", '’', $comment);
+
+    // Truncate comment to maximum comment length.
+    if (isset($length)) {
+      // Add table prefixes before truncating.
+      $comment = truncate_utf8($this->connection->prefixTables($comment), $length, TRUE, TRUE);
+    }
+
+    return $this->connection->quote($comment);
+  }
+
+  /**
+   * Retrieve a table or column comment.
+   */
+  public function getComment($table, $column = NULL) {
+    $condition = $this->buildTableNameCondition($table);
+    if (isset($column)) {
+      $condition->condition('column_name', $column);
+      $condition->compile($this->connection, $this);
+      // Don't use {} around information_schema.columns table.
+      return $this->connection->query("SELECT column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
+    }
+    $condition->compile($this->connection, $this);
+    // Don't use {} around information_schema.tables table.
+    $comment = $this->connection->query("SELECT table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
+    // Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379
+    return preg_replace('/; InnoDB free:.*$/', '', $comment);
+  }
+
+  public function tableExists($table) {
+    // The information_schema table is very slow to query under MySQL 5.0.
+    // Instead, we try to select from the table in question.  If it fails,
+    // the most likely reason is that it does not exist. That is dramatically
+    // faster than using information_schema.
+    // @link http://bugs.mysql.com/bug.php?id=19588
+    // @todo: This override should be removed once we require a version of MySQL
+    // that has that bug fixed.
+    try {
+      $this->connection->queryRange("SELECT 1 FROM {" . $table . "}", 0, 1);
+      return TRUE;
+    }
+    catch (Exception $e) {
+      return FALSE;
+    }
+  }
+
+  public function fieldExists($table, $column) {
+    // The information_schema table is very slow to query under MySQL 5.0.
+    // Instead, we try to select from the table and field in question. If it
+    // fails, the most likely reason is that it does not exist. That is
+    // dramatically faster than using information_schema.
+    // @link http://bugs.mysql.com/bug.php?id=19588
+    // @todo: This override should be removed once we require a version of MySQL
+    // that has that bug fixed.
+    try {
+      $this->connection->queryRange("SELECT $column FROM {" . $table . "}", 0, 1);
+      return TRUE;
+    }
+    catch (Exception $e) {
+      return FALSE;
+    }
+  }
+
+}
+
+/**
+ * @} End of "ingroup schemaapi".
+ */
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 0000000..5d04ea9
--- /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/Drupal/Database/Driver/mysql/Insert.php b/core/includes/Drupal/Database/Driver/mysql/Insert.php
new file mode 100644
index 0000000..ff58f3b
--- /dev/null
+++ b/core/includes/Drupal/Database/Driver/mysql/Insert.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\Database\Driver\mysql;
+
+use Drupal\Database\Query\Insert as QueryInsert;
+
+class Insert extends QueryInsert {
+
+  public function execute() {
+    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)) {
+      $max_placeholder = 0;
+      $values = array();
+      foreach ($this->insertValues as $insert_values) {
+        foreach ($insert_values as $value) {
+          $values[':db_insert_placeholder_' . $max_placeholder++] = $value;
+        }
+      }
+    }
+    else {
+      $values = $this->fromQuery->getArguments();
+    }
+
+    $last_insert_id = $this->connection->query((string) $this, $values, $this->queryOptions);
+
+    // Re-initialize the values array so that we can re-use this query.
+    $this->insertValues = array();
+
+    return $last_insert_id;
+  }
+
+  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 we're selecting from a SelectQuery, finish building the query and
+    // pass it back, as any remaining options are irrelevant.
+    if (!empty($this->fromQuery)) {
+      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+    }
+
+    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+
+    $max_placeholder = 0;
+    $values = array();
+    if (count($this->insertValues)) {
+      foreach ($this->insertValues as $insert_values) {
+        $placeholders = array();
+
+        // Default fields aren't really placeholders, but this is the most convenient
+        // way to handle them.
+        $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
+
+        $new_placeholder = $max_placeholder + count($insert_values);
+        for ($i = $max_placeholder; $i < $new_placeholder; ++$i) {
+          $placeholders[] = ':db_insert_placeholder_' . $i;
+        }
+        $max_placeholder = $new_placeholder;
+        $values[] = '(' . implode(', ', $placeholders) . ')';
+      }
+    }
+    else {
+      // If there are no values, then this is a default-only query. We still need to handle that.
+      $placeholders = array_fill(0, count($this->defaultFields), 'default');
+      $values[] = '(' . implode(', ', $placeholders) . ')';
+    }
+
+    $query .= implode(', ', $values);
+
+    return $query;
+  }
+}
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 0000000..1d75cf2
--- /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 0000000..35ef1d5
--- /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 0000000..57e3fb0
--- /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 0000000..40c49cd
--- /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 0000000..6b82267
--- /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 0000000..9d3a23f
--- /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 0000000..5d173dd
--- /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 0000000..1864841
--- /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 0000000..ef0f78b
--- /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 0000000..6a30abf
--- /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 0000000..5200fd2
--- /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 0000000..2ff7267
--- /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 0000000..edc24d9
--- /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 0000000..d33498d
--- /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 0000000..2fea041
--- /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 0000000..509a30d
--- /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 0000000..21cfb8e
--- /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 0000000..6f5c78d
--- /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 0000000..ea96bba
--- /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 0000000..b023778
--- /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 0000000..59f4a29
--- /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 0000000..f1d32ab
--- /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 0000000..e2b34f5
--- /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 0026cb0..4da73db 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 9da67ac..25b5c59 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 dcf0d1e..aa1f444 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.
@@ -172,2105 +175,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.
  *
  * They should never, ever have any database-specific code in them.
diff --git a/core/includes/database/log.inc b/core/includes/database/log.inc
deleted file mode 100644
index ec27ef8..0000000
--- a/core/includes/database/log.inc
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-
-/**
- * @file
- * Logging classes for the database layer.
- */
-
-/**
- * Database query logger.
- *
- * We log queries in a separate object rather than in the connection object
- * because we want to be able to see all queries sent to a given database, not
- * database target. If we logged the queries in each connection object we
- * would not be able to track what queries went to which target.
- *
- * Every connection has one and only one logging object on it for all targets
- * and logging keys.
- */
-class DatabaseLog {
-
-  /**
-   * Cache of logged queries. This will only be used if the query logger is enabled.
-   *
-   * The structure for the logging array is as follows:
-   *
-   * array(
-   *   $logging_key = array(
-   *     array(query => '', args => array(), caller => '', target => '', time => 0),
-   *     array(query => '', args => array(), caller => '', target => '', time => 0),
-   *   ),
-   * );
-   *
-   * @var array
-   */
-  protected $queryLog = array();
-
-  /**
-   * The connection key for which this object is logging.
-   *
-   * @var string
-   */
-  protected $connectionKey = 'default';
-
-  /**
-   * Constructor.
-   *
-   * @param $key
-   *   The database connection key for which to enable logging.
-   */
-  public function __construct($key = 'default') {
-    $this->connectionKey = $key;
-  }
-
-  /**
-   * Begin logging queries to the specified connection and logging key.
-   *
-   * If the specified logging key is already running this method does nothing.
-   *
-   * @param $logging_key
-   *   The identification key for this log request. By specifying different
-   *   logging keys we are able to start and stop multiple logging runs
-   *   simultaneously without them colliding.
-   */
-  public function start($logging_key) {
-    if (empty($this->queryLog[$logging_key])) {
-      $this->clear($logging_key);
-    }
-  }
-
-  /**
-   * Retrieve the query log for the specified logging key so far.
-   *
-   * @param $logging_key
-   *   The logging key to fetch.
-   * @return
-   *   An indexed array of all query records for this logging key.
-   */
-  public function get($logging_key) {
-    return $this->queryLog[$logging_key];
-  }
-
-  /**
-   * Empty the query log for the specified logging key.
-   *
-   * This method does not stop logging, it simply clears the log. To stop
-   * logging, use the end() method.
-   *
-   * @param $logging_key
-   *   The logging key to empty.
-   */
-  public function clear($logging_key) {
-    $this->queryLog[$logging_key] = array();
-  }
-
-  /**
-   * Stop logging for the specified logging key.
-   *
-   * @param $logging_key
-   *   The logging key to stop.
-   */
-  public function end($logging_key) {
-    unset($this->queryLog[$logging_key]);
-  }
-
-  /**
-   * Log a query to all active logging keys.
-   *
-   * @param $statement
-   *   The prepared statement object to log.
-   * @param $args
-   *   The arguments passed to the statement object.
-   * @param $time
-   *   The time in milliseconds the query took to execute.
-   */
-  public function log(DatabaseStatementInterface $statement, $args, $time) {
-    foreach (array_keys($this->queryLog) as $key) {
-      $this->queryLog[$key][] = array(
-        'query' => $statement->getQueryString(),
-        'args' => $args,
-        'target' => $statement->dbh->getTarget(),
-        'caller' => $this->findCaller(),
-        'time' => $time,
-      );
-    }
-  }
-
-  /**
-   * Determine the routine that called this query.
-   *
-   * We define "the routine that called this query" as the first entry in
-   * the call stack that is not inside includes/database. That makes the
-   * climbing logic very simple, and handles the variable stack depth caused
-   * by the query builders.
-   *
-   * @link http://www.php.net/debug_backtrace
-   * @return
-   *   This method returns a stack trace entry similar to that generated by
-   *   debug_backtrace(). However, it flattens the trace entry and the trace
-   *   entry before it so that we get the function and args of the function that
-   *   called into the database system, not the function and args of the
-   *   database call itself.
-   */
-  public function findCaller() {
-    $stack = debug_backtrace();
-    $stack_count = count($stack);
-    for ($i = 0; $i < $stack_count; ++$i) {
-      if (strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) {
-        return array(
-          'file' => $stack[$i]['file'],
-          'line' => $stack[$i]['line'],
-          'function' => $stack[$i + 1]['function'],
-          'class' => isset($stack[$i + 1]['class']) ? $stack[$i + 1]['class'] : NULL,
-          'type' => isset($stack[$i + 1]['type']) ? $stack[$i + 1]['type'] : NULL,
-          'args' => $stack[$i + 1]['args'],
-        );
-      }
-    }
-  }
-}
diff --git a/core/includes/database/mysql/database.inc b/core/includes/database/mysql/database.inc
deleted file mode 100644
index a57f7dd..0000000
--- a/core/includes/database/mysql/database.inc
+++ /dev/null
@@ -1,201 +0,0 @@
-<?php
-
-/**
- * @file
- * Database interface code for MySQL database servers.
- */
-
-/**
- * @ingroup database
- * @{
- */
-
-class DatabaseConnection_mysql extends DatabaseConnection {
-
-  /**
-   * Flag to indicate if we have registered the nextID cleanup function.
-   *
-   * @var boolean
-   */
-  protected $shutdownRegistered = FALSE;
-
-  public function __construct(array $connection_options = array()) {
-    // This driver defaults to transaction support, except if explicitly passed FALSE.
-    $this->transactionSupport = !isset($connection_options['transactions']) || ($connection_options['transactions'] !== FALSE);
-
-    // MySQL never supports transactional DDL.
-    $this->transactionalDDLSupport = FALSE;
-
-    $this->connectionOptions = $connection_options;
-
-    // The DSN should use either a socket or a host/port.
-    if (isset($connection_options['unix_socket'])) {
-      $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
-    }
-    else {
-      // Default to TCP connection on port 3306.
-      $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
-    }
-    $dsn .= ';dbname=' . $connection_options['database'];
-    // Allow PDO options to be overridden.
-    $connection_options += array(
-      'pdo' => array(),
-    );
-    $connection_options['pdo'] += array(
-      // So we don't have to mess around with cursors and unbuffered queries by default.
-      PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
-      // Because MySQL's prepared statements skip the query cache, because it's dumb.
-      PDO::ATTR_EMULATE_PREPARES => TRUE,
-      // Force column names to lower case.
-      PDO::ATTR_CASE => PDO::CASE_LOWER,
-    );
-
-    parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
-
-    // Force MySQL to use the UTF-8 character set. Also set the collation, if a
-    // certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
-    // for UTF-8.
-    if (!empty($connection_options['collation'])) {
-      $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
-    }
-    else {
-      $this->exec('SET NAMES utf8');
-    }
-
-    // Set MySQL init_commands if not already defined.  Default Drupal's MySQL
-    // behavior to conform more closely to SQL standards.  This allows Drupal
-    // to run almost seamlessly on many different kinds of database systems.
-    // These settings force MySQL to behave the same as postgresql, or sqlite
-    // in regards to syntax interpretation and invalid data handling.  See
-    // http://drupal.org/node/344575 for further discussion. Also, as MySQL 5.5
-    // changed the meaning of TRADITIONAL we need to spell out the modes one by
-    // one.
-    $connection_options += array(
-      'init_commands' => array(),
-    );
-    $connection_options['init_commands'] += array(
-      'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
-    );
-    // Set connection options.
-    $this->exec(implode('; ', $connection_options['init_commands']));
-  }
-
-  public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
-    return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
-  }
-
-  public function queryTemporary($query, array $args = array(), array $options = array()) {
-    $tablename = $this->generateTemporaryTableName();
-    $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY SELECT', $query), $args, $options);
-    return $tablename;
-  }
-
-  public function driver() {
-    return 'mysql';
-  }
-
-  public function databaseType() {
-    return 'mysql';
-  }
-
-  public function mapConditionOperator($operator) {
-    // We don't want to override any of the defaults.
-    return NULL;
-  }
-
-  public function nextId($existing_id = 0) {
-    $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
-    // This should only happen after an import or similar event.
-    if ($existing_id >= $new_id) {
-      // If we INSERT a value manually into the sequences table, on the next
-      // INSERT, MySQL will generate a larger value. However, there is no way
-      // of knowing whether this value already exists in the table. MySQL
-      // provides an INSERT IGNORE which would work, but that can mask problems
-      // other than duplicate keys. Instead, we use INSERT ... ON DUPLICATE KEY
-      // UPDATE in such a way that the UPDATE does not do anything. This way,
-      // duplicate keys do not generate errors but everything else does.
-      $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
-      $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
-    }
-    if (!$this->shutdownRegistered) {
-      // Use register_shutdown_function() here to keep the database system
-      // independent of Drupal.
-      register_shutdown_function(array($this, 'nextIdDelete'));
-      $shutdownRegistered = TRUE;
-    }
-    return $new_id;
-  }
-
-  public function nextIdDelete() {
-    // While we want to clean up the table to keep it up from occupying too
-    // much storage and memory, we must keep the highest value in the table
-    // because InnoDB  uses an in-memory auto-increment counter as long as the
-    // server runs. When the server is stopped and restarted, InnoDB
-    // reinitializes the counter for each table for the first INSERT to the
-    // table based solely on values from the table so deleting all values would
-    // be a problem in this case. Also, TRUNCATE resets the auto increment
-    // counter.
-    try {
-      $max_id = $this->query('SELECT MAX(value) FROM {sequences}')->fetchField();
-      // We know we are using MySQL here, no need for the slower db_delete().
-      $this->query('DELETE FROM {sequences} WHERE value < :value', array(':value' => $max_id));
-    }
-    // During testing, this function is called from shutdown with the
-    // simpletest prefix stored in $this->connection, and those tables are gone
-    // by the time shutdown is called so we need to ignore the database
-    // errors. There is no problem with completely ignoring errors here: if
-    // these queries fail, the sequence will work just fine, just use a bit
-    // more database storage and memory.
-    catch (PDOException $e) {
-    }
-  }
-
-  /**
-   * Overridden to work around issues to MySQL not supporting transactional DDL.
-   */
-  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 (!PDO::commit()) {
-          throw new DatabaseTransactionCommitFailedException();
-        }
-      }
-      else {
-        // Attempt to release this savepoint in the standard way.
-        try {
-          $this->query('RELEASE SAVEPOINT ' . $name);
-        }
-        catch (PDOException $e) {
-          // However, in MySQL (InnoDB), savepoints are automatically committed
-          // when tables are altered or created (DDL transactions are not
-          // supported). This can cause exceptions due to trying to release
-          // savepoints which no longer exist.
-          //
-          // To avoid exceptions when no actual error has occurred, we silently
-          // succeed for MySQL error code 1305 ("SAVEPOINT does not exist").
-          if ($e->errorInfo[1] == '1305') {
-            // If one SAVEPOINT was released automatically, then all were.
-            // Therefore, we keep just the topmost transaction.
-            $this->transactionLayers = array('drupal_transaction' => 'drupal_transaction');
-          }
-          else {
-            throw $e;
-          }
-        }
-      }
-    }
-  }
-}
-
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/mysql/query.inc b/core/includes/database/mysql/query.inc
deleted file mode 100644
index 888b6a5..0000000
--- a/core/includes/database/mysql/query.inc
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-/**
- * @ingroup database
- * @{
- */
-
-/**
- * @file
- * Query code for MySQL embedded database engine.
- */
-
-
-class InsertQuery_mysql extends InsertQuery {
-
-  public function execute() {
-    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)) {
-      $max_placeholder = 0;
-      $values = array();
-      foreach ($this->insertValues as $insert_values) {
-        foreach ($insert_values as $value) {
-          $values[':db_insert_placeholder_' . $max_placeholder++] = $value;
-        }
-      }
-    }
-    else {
-      $values = $this->fromQuery->getArguments();
-    }
-
-    $last_insert_id = $this->connection->query((string) $this, $values, $this->queryOptions);
-
-    // Re-initialize the values array so that we can re-use this query.
-    $this->insertValues = array();
-
-    return $last_insert_id;
-  }
-
-  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 we're selecting from a SelectQuery, finish building the query and
-    // pass it back, as any remaining options are irrelevant.
-    if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
-    }
-
-    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
-
-    $max_placeholder = 0;
-    $values = array();
-    if (count($this->insertValues)) {
-      foreach ($this->insertValues as $insert_values) {
-        $placeholders = array();
-
-        // Default fields aren't really placeholders, but this is the most convenient
-        // way to handle them.
-        $placeholders = array_pad($placeholders, count($this->defaultFields), 'default');
-
-        $new_placeholder = $max_placeholder + count($insert_values);
-        for ($i = $max_placeholder; $i < $new_placeholder; ++$i) {
-          $placeholders[] = ':db_insert_placeholder_' . $i;
-        }
-        $max_placeholder = $new_placeholder;
-        $values[] = '(' . implode(', ', $placeholders) . ')';
-      }
-    }
-    else {
-      // If there are no values, then this is a default-only query. We still need to handle that.
-      $placeholders = array_fill(0, count($this->defaultFields), 'default');
-      $values[] = '(' . implode(', ', $placeholders) . ')';
-    }
-
-    $query .= implode(', ', $values);
-
-    return $query;
-  }
-}
-
-class TruncateQuery_mysql extends TruncateQuery {
-  public function __toString() {
-    // TRUNCATE is actually a DDL statement on MySQL, and DDL statements are
-    // not transactional, and result in an implicit COMMIT. When we are in a
-    // transaction, fallback to the slower, but transactional, DELETE.
-    if ($this->connection->inTransaction()) {
-      // Create a comment string to prepend to the query.
-      $comments = $this->connection->makeComment($this->comments);
-      return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}';
-    }
-    else {
-      return parent::__toString();
-    }
-  }
-}
-
-/**
- * @} End of "ingroup database".
- */
diff --git a/core/includes/database/mysql/schema.inc b/core/includes/database/mysql/schema.inc
deleted file mode 100644
index 4e88fa1..0000000
--- a/core/includes/database/mysql/schema.inc
+++ /dev/null
@@ -1,531 +0,0 @@
-<?php
-
-/**
- * @file
- * Database schema code for MySQL database servers.
- */
-
-
-/**
- * @ingroup schemaapi
- * @{
- */
-
-class DatabaseSchema_mysql extends DatabaseSchema {
-
-  /**
-   * Maximum length of a table comment in MySQL.
-   */
-  const COMMENT_MAX_TABLE = 60;
-
-  /**
-   * Maximum length of a column comment in MySQL.
-   */
-  const COMMENT_MAX_COLUMN = 255;
-
-  /**
-   * Get information about the table and database name from the prefix.
-   *
-   * @return
-   *   A keyed array with information about the database, table name and prefix.
-   */
-  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
-    $info = array('prefix' => $this->connection->tablePrefix($table));
-    if ($add_prefix) {
-      $table = $info['prefix'] . $table;
-    }
-    if (($pos = strpos($table, '.')) !== FALSE) {
-      $info['database'] = substr($table, 0, $pos);
-      $info['table'] = substr($table, ++$pos);
-    }
-    else {
-      $db_info = Database::getConnectionInfo();
-      $info['database'] = $db_info['default']['database'];
-      $info['table'] = $table;
-    }
-    return $info;
-  }
-
-  /**
-   * Build a condition to match a table name against a standard information_schema.
-   *
-   * MySQL uses databases like schemas rather than catalogs so when we build
-   * a condition to query the information_schema.tables, we set the default
-   * database as the schema unless specified otherwise, and exclude table_catalog
-   * from the condition criteria.
-   */
-  protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
-    $info = $this->connection->getConnectionOptions();
-
-    $table_info = $this->getPrefixInfo($table_name, $add_prefix);
-
-    $condition = new DatabaseCondition('AND');
-    $condition->condition('table_schema', $table_info['database']);
-    $condition->condition('table_name', $table_info['table'], $operator);
-    return $condition;
-  }
-
-  /**
-   * Generate SQL to create a new table from a Drupal schema definition.
-   *
-   * @param $name
-   *   The name of the table to create.
-   * @param $table
-   *   A Schema API table definition array.
-   * @return
-   *   An array of SQL statements to create the table.
-   */
-  protected function createTableSql($name, $table) {
-    $info = $this->connection->getConnectionOptions();
-
-    // Provide defaults if needed.
-    $table += array(
-      'mysql_engine' => 'InnoDB',
-      'mysql_character_set' => 'utf8',
-    );
-
-    $sql = "CREATE TABLE {" . $name . "} (\n";
-
-    // Add the SQL statement for each field.
-    foreach ($table['fields'] as $field_name => $field) {
-      $sql .= $this->createFieldSql($field_name, $this->processField($field)) . ", \n";
-    }
-
-    // Process keys & indexes.
-    $keys = $this->createKeysSql($table);
-    if (count($keys)) {
-      $sql .= implode(", \n", $keys) . ", \n";
-    }
-
-    // Remove the last comma and space.
-    $sql = substr($sql, 0, -3) . "\n) ";
-
-    $sql .= 'ENGINE = ' . $table['mysql_engine'] . ' DEFAULT CHARACTER SET ' . $table['mysql_character_set'];
-    // By default, MySQL uses the default collation for new tables, which is
-    // 'utf8_general_ci' for utf8. If an alternate collation has been set, it
-    // needs to be explicitly specified.
-    // @see DatabaseConnection_mysql
-    if (!empty($info['collation'])) {
-      $sql .= ' COLLATE ' . $info['collation'];
-    }
-
-    // Add table comment.
-    if (!empty($table['description'])) {
-      $sql .= ' COMMENT ' . $this->prepareComment($table['description'], self::COMMENT_MAX_TABLE);
-    }
-
-    return array($sql);
-  }
-
-  /**
-   * Create an SQL string for a field to be used in table creation or alteration.
-   *
-   * Before passing a field out of a schema definition into this function it has
-   * to be processed by _db_process_field().
-   *
-   * @param $name
-   *   Name of the field.
-   * @param $spec
-   *   The field specification, as per the schema data structure format.
-   */
-  protected function createFieldSql($name, $spec) {
-    $sql = "`" . $name . "` " . $spec['mysql_type'];
-
-    if (in_array($spec['mysql_type'], array('VARCHAR', 'CHAR', 'TINYTEXT', 'MEDIUMTEXT', 'LONGTEXT', 'TEXT')) && isset($spec['length'])) {
-      $sql .= '(' . $spec['length'] . ')';
-    }
-    elseif (isset($spec['precision']) && isset($spec['scale'])) {
-      $sql .= '(' . $spec['precision'] . ', ' . $spec['scale'] . ')';
-    }
-
-    if (!empty($spec['unsigned'])) {
-      $sql .= ' unsigned';
-    }
-
-    if (isset($spec['not null'])) {
-      if ($spec['not null']) {
-        $sql .= ' NOT NULL';
-      }
-      else {
-        $sql .= ' NULL';
-      }
-    }
-
-    if (!empty($spec['auto_increment'])) {
-      $sql .= ' auto_increment';
-    }
-
-    // $spec['default'] can be NULL, so we explicitly check for the key here.
-    if (array_key_exists('default', $spec)) {
-      if (is_string($spec['default'])) {
-        $spec['default'] = "'" . $spec['default'] . "'";
-      }
-      elseif (!isset($spec['default'])) {
-        $spec['default'] = 'NULL';
-      }
-      $sql .= ' DEFAULT ' . $spec['default'];
-    }
-
-    if (empty($spec['not null']) && !isset($spec['default'])) {
-      $sql .= ' DEFAULT NULL';
-    }
-
-    // Add column comment.
-    if (!empty($spec['description'])) {
-      $sql .= ' COMMENT ' . $this->prepareComment($spec['description'], self::COMMENT_MAX_COLUMN);
-    }
-
-    return $sql;
-  }
-
-  /**
-   * Set database-engine specific properties for a field.
-   *
-   * @param $field
-   *   A field description array, as specified in the schema documentation.
-   */
-  protected function processField($field) {
-
-    if (!isset($field['size'])) {
-      $field['size'] = 'normal';
-    }
-
-    // Set the correct database-engine specific datatype.
-    // In case one is already provided, force it to uppercase.
-    if (isset($field['mysql_type'])) {
-      $field['mysql_type'] = drupal_strtoupper($field['mysql_type']);
-    }
-    else {
-      $map = $this->getFieldTypeMap();
-      $field['mysql_type'] = $map[$field['type'] . ':' . $field['size']];
-    }
-
-    if (isset($field['type']) && $field['type'] == 'serial') {
-      $field['auto_increment'] = TRUE;
-    }
-
-    return $field;
-  }
-
-  public function getFieldTypeMap() {
-    // Put :normal last so it gets preserved by array_flip. This makes
-    // it much easier for modules (such as schema.module) to map
-    // database types back into schema types.
-    // $map does not use drupal_static as its value never changes.
-    static $map = array(
-      'varchar:normal'  => 'VARCHAR',
-      'char:normal'     => 'CHAR',
-
-      'text:tiny'       => 'TINYTEXT',
-      'text:small'      => 'TINYTEXT',
-      'text:medium'     => 'MEDIUMTEXT',
-      'text:big'        => 'LONGTEXT',
-      'text:normal'     => 'TEXT',
-
-      'serial:tiny'     => 'TINYINT',
-      'serial:small'    => 'SMALLINT',
-      'serial:medium'   => 'MEDIUMINT',
-      'serial:big'      => 'BIGINT',
-      'serial:normal'   => 'INT',
-
-      'int:tiny'        => 'TINYINT',
-      'int:small'       => 'SMALLINT',
-      'int:medium'      => 'MEDIUMINT',
-      'int:big'         => 'BIGINT',
-      'int:normal'      => 'INT',
-
-      'float:tiny'      => 'FLOAT',
-      'float:small'     => 'FLOAT',
-      'float:medium'    => 'FLOAT',
-      'float:big'       => 'DOUBLE',
-      'float:normal'    => 'FLOAT',
-
-      'numeric:normal'  => 'DECIMAL',
-
-      'blob:big'        => 'LONGBLOB',
-      'blob:normal'     => 'BLOB',
-    );
-    return $map;
-  }
-
-  protected function createKeysSql($spec) {
-    $keys = array();
-
-    if (!empty($spec['primary key'])) {
-      $keys[] = 'PRIMARY KEY (' . $this->createKeysSqlHelper($spec['primary key']) . ')';
-    }
-    if (!empty($spec['unique keys'])) {
-      foreach ($spec['unique keys'] as $key => $fields) {
-        $keys[] = 'UNIQUE KEY `' . $key . '` (' . $this->createKeysSqlHelper($fields) . ')';
-      }
-    }
-    if (!empty($spec['indexes'])) {
-      foreach ($spec['indexes'] as $index => $fields) {
-        $keys[] = 'INDEX `' . $index . '` (' . $this->createKeysSqlHelper($fields) . ')';
-      }
-    }
-
-    return $keys;
-  }
-
-  protected function createKeySql($fields) {
-    $return = array();
-    foreach ($fields as $field) {
-      if (is_array($field)) {
-        $return[] = '`' . $field[0] . '`(' . $field[1] . ')';
-      }
-      else {
-        $return[] = '`' . $field . '`';
-      }
-    }
-    return implode(', ', $return);
-  }
-
-  protected function createKeysSqlHelper($fields) {
-    $return = array();
-    foreach ($fields as $field) {
-      if (is_array($field)) {
-        $return[] = '`' . $field[0] . '`(' . $field[1] . ')';
-      }
-      else {
-        $return[] = '`' . $field . '`';
-      }
-    }
-    return implode(', ', $return);
-  }
-
-  public function renameTable($table, $new_name) {
-    if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename %table to %table_new: table %table doesn't exist.", array('%table' => $table, '%table_new' => $new_name)));
-    }
-    if ($this->tableExists($new_name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename %table to %table_new: table %table_new already exists.", array('%table' => $table, '%table_new' => $new_name)));
-    }
-
-    $info = $this->getPrefixInfo($new_name);
-    return $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO `' . $info['table'] . '`');
-  }
-
-  public function dropTable($table) {
-    if (!$this->tableExists($table)) {
-      return FALSE;
-    }
-
-    $this->connection->query('DROP TABLE {' . $table . '}');
-    return TRUE;
-  }
-
-  public function addField($table, $field, $spec, $keys_new = array()) {
-    if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add field %table.%field: table doesn't exist.", array('%field' => $field, '%table' => $table)));
-    }
-    if ($this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add field %table.%field: field already exists.", array('%field' => $field, '%table' => $table)));
-    }
-
-    $fixnull = FALSE;
-    if (!empty($spec['not null']) && !isset($spec['default'])) {
-      $fixnull = TRUE;
-      $spec['not null'] = FALSE;
-    }
-    $query = 'ALTER TABLE {' . $table . '} ADD ';
-    $query .= $this->createFieldSql($field, $this->processField($spec));
-    if ($keys_sql = $this->createKeysSql($keys_new)) {
-      $query .= ', ADD ' . implode(', ADD ', $keys_sql);
-    }
-    $this->connection->query($query);
-    if (isset($spec['initial'])) {
-      $this->connection->update($table)
-        ->fields(array($field => $spec['initial']))
-        ->execute();
-    }
-    if ($fixnull) {
-      $spec['not null'] = TRUE;
-      $this->changeField($table, $field, $field, $spec);
-    }
-  }
-
-  public function dropField($table, $field) {
-    if (!$this->fieldExists($table, $field)) {
-      return FALSE;
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`');
-    return TRUE;
-  }
-
-  public function fieldSetDefault($table, $field, $default) {
-    if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot set default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
-    }
-
-    if (!isset($default)) {
-      $default = 'NULL';
-    }
-    else {
-      $default = is_string($default) ? "'$default'" : $default;
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` SET DEFAULT ' . $default);
-  }
-
-  public function fieldSetNoDefault($table, $field) {
-    if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
-  }
-
-  public function indexExists($table, $name) {
-    // Returns one row for each column in the index. Result is string or FALSE.
-    // Details at http://dev.mysql.com/doc/refman/5.0/en/show-index.html
-    $row = $this->connection->query('SHOW INDEX FROM {' . $table . "} WHERE key_name = '$name'")->fetchAssoc();
-    return isset($row['key_name']);
-  }
-
-  public function addPrimaryKey($table, $fields) {
-    if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add primary key to table %table: table doesn't exist.", array('%table' => $table)));
-    }
-    if ($this->indexExists($table, 'PRIMARY')) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
-  }
-
-  public function dropPrimaryKey($table) {
-    if (!$this->indexExists($table, 'PRIMARY')) {
-      return FALSE;
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP PRIMARY KEY');
-    return TRUE;
-  }
-
-  public function addUniqueKey($table, $name, $fields) {
-    if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add unique key %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
-    }
-    if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
-  }
-
-  public function dropUniqueKey($table, $name) {
-    if (!$this->indexExists($table, $name)) {
-      return FALSE;
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY `' . $name . '`');
-    return TRUE;
-  }
-
-  public function addIndex($table, $name, $fields) {
-    if (!$this->tableExists($table)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot add index %name to table %table: table doesn't exist.", array('%table' => $table, '%name' => $name)));
-    }
-    if ($this->indexExists($table, $name)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
-  }
-
-  public function dropIndex($table, $name) {
-    if (!$this->indexExists($table, $name)) {
-      return FALSE;
-    }
-
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX `' . $name . '`');
-    return TRUE;
-  }
-
-  public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
-    if (!$this->fieldExists($table, $field)) {
-      throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot change the definition of field %table.%name: field doesn't exist.", array('%table' => $table, '%name' => $field)));
-    }
-    if (($field != $field_new) && $this->fieldExists($table, $field_new)) {
-      throw new DatabaseSchemaObjectExistsException(t("Cannot rename field %table.%name to %name_new: target field already exists.", array('%table' => $table, '%name' => $field, '%name_new' => $field_new)));
-    }
-
-    $sql = 'ALTER TABLE {' . $table . '} CHANGE `' . $field . '` ' . $this->createFieldSql($field_new, $this->processField($spec));
-    if ($keys_sql = $this->createKeysSql($keys_new)) {
-      $sql .= ', ADD ' . implode(', ADD ', $keys_sql);
-    }
-    $this->connection->query($sql);
-  }
-
-  public function prepareComment($comment, $length = NULL) {
-    // Work around a bug in some versions of PDO, see http://bugs.php.net/bug.php?id=41125
-    $comment = str_replace("'", '’', $comment);
-
-    // Truncate comment to maximum comment length.
-    if (isset($length)) {
-      // Add table prefixes before truncating.
-      $comment = truncate_utf8($this->connection->prefixTables($comment), $length, TRUE, TRUE);
-    }
-
-    return $this->connection->quote($comment);
-  }
-
-  /**
-   * Retrieve a table or column comment.
-   */
-  public function getComment($table, $column = NULL) {
-    $condition = $this->buildTableNameCondition($table);
-    if (isset($column)) {
-      $condition->condition('column_name', $column);
-      $condition->compile($this->connection, $this);
-      // Don't use {} around information_schema.columns table.
-      return $this->connection->query("SELECT column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
-    }
-    $condition->compile($this->connection, $this);
-    // Don't use {} around information_schema.tables table.
-    $comment = $this->connection->query("SELECT table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
-    // Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379
-    return preg_replace('/; InnoDB free:.*$/', '', $comment);
-  }
-
-  public function tableExists($table) {
-    // The information_schema table is very slow to query under MySQL 5.0.
-    // Instead, we try to select from the table in question.  If it fails,
-    // the most likely reason is that it does not exist. That is dramatically
-    // faster than using information_schema.
-    // @link http://bugs.mysql.com/bug.php?id=19588
-    // @todo: This override should be removed once we require a version of MySQL
-    // that has that bug fixed.
-    try {
-      $this->connection->queryRange("SELECT 1 FROM {" . $table . "}", 0, 1);
-      return TRUE;
-    }
-    catch (Exception $e) {
-      return FALSE;
-    }
-  }
-
-  public function fieldExists($table, $column) {
-    // The information_schema table is very slow to query under MySQL 5.0.
-    // Instead, we try to select from the table and field in question. If it
-    // fails, the most likely reason is that it does not exist. That is
-    // dramatically faster than using information_schema.
-    // @link http://bugs.mysql.com/bug.php?id=19588
-    // @todo: This override should be removed once we require a version of MySQL
-    // that has that bug fixed.
-    try {
-      $this->connection->queryRange("SELECT $column FROM {" . $table . "}", 0, 1);
-      return TRUE;
-    }
-    catch (Exception $e) {
-      return FALSE;
-    }
-  }
-
-}
-
-/**
- * @} End of "ingroup schemaapi".
- */
diff --git a/core/includes/database/pgsql/install.inc b/core/includes/database/pgsql/install.inc
index c350634..9268687 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/prefetch.inc b/core/includes/database/prefetch.inc
deleted file mode 100644
index 4f2b19d..0000000
--- a/core/includes/database/prefetch.inc
+++ /dev/null
@@ -1,507 +0,0 @@
-<?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.
- */
-
-/**
- * @ingroup database
- * @{
- */
-
-/**
- * An implementation of DatabaseStatementInterface that prefetches all data.
- *
- * This class behaves very similar to a PDOStatement but as it always fetches
- * every row it is possible to manipulate those results.
- */
-class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface {
-
-  /**
-   * The query string.
-   *
-   * @var string
-   */
-  protected $queryString;
-
-  /**
-   * Driver-specific options. Can be used by child classes.
-   *
-   * @var Array
-   */
-  protected $driverOptions;
-
-  /**
-   * Reference to the database connection object for this statement.
-   *
-   * The name $dbh is inherited from PDOStatement.
-   *
-   * @var DatabaseConnection
-   */
-  public $dbh;
-
-  /**
-   * Main data store.
-   *
-   * @var Array
-   */
-  protected $data = array();
-
-  /**
-   * The current row, retrieved in PDO::FETCH_ASSOC format.
-   *
-   * @var Array
-   */
-  protected $currentRow = NULL;
-
-  /**
-   * The key of the current row.
-   *
-   * @var int
-   */
-  protected $currentKey = NULL;
-
-  /**
-   * The list of column names in this result set.
-   *
-   * @var Array
-   */
-  protected $columnNames = NULL;
-
-  /**
-   * The number of rows affected by the last query.
-   *
-   * @var int
-   */
-  protected $rowCount = NULL;
-
-  /**
-   * The number of rows in this result set.
-   *
-   * @var int
-   */
-  protected $resultRowCount = 0;
-
-  /**
-   * Holds the current fetch style (which will be used by the next fetch).
-   * @see PDOStatement::fetch()
-   *
-   * @var int
-   */
-  protected $fetchStyle = PDO::FETCH_OBJ;
-
-  /**
-   * Holds supplementary current fetch options (which will be used by the next fetch).
-   *
-   * @var Array
-   */
-  protected $fetchOptions = array(
-    'class' => 'stdClass',
-    'constructor_args' => array(),
-    'object' => NULL,
-    'column' => 0,
-  );
-
-  /**
-   * Holds the default fetch style.
-   *
-   * @var int
-   */
-  protected $defaultFetchStyle = PDO::FETCH_OBJ;
-
-  /**
-   * Holds supplementary default fetch options.
-   *
-   * @var Array
-   */
-  protected $defaultFetchOptions = array(
-    'class' => 'stdClass',
-    'constructor_args' => array(),
-    'object' => NULL,
-    'column' => 0,
-  );
-
-  public function __construct(DatabaseConnection $connection, $query, array $driver_options = array()) {
-    $this->dbh = $connection;
-    $this->queryString = $query;
-    $this->driverOptions = $driver_options;
-  }
-
-  /**
-   * 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()) {
-    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);
-    }
-
-    // Prepare the query.
-    $statement = $this->getStatement($this->queryString, $args);
-    if (!$statement) {
-      $this->throwPDOException();
-    }
-
-    $return = $statement->execute($args);
-    if (!$return) {
-      $this->throwPDOException();
-    }
-
-    // Fetch all the data from the reply, in order to release any lock
-    // as soon as possible.
-    $this->rowCount = $statement->rowCount();
-    $this->data = $statement->fetchAll(PDO::FETCH_ASSOC);
-    // Destroy the statement as soon as possible. See
-    // DatabaseConnection_sqlite::PDOPrepare() for explanation.
-    unset($statement);
-
-    $this->resultRowCount = count($this->data);
-
-    if ($this->resultRowCount) {
-      $this->columnNames = array_keys($this->data[0]);
-    }
-    else {
-      $this->columnNames = array();
-    }
-
-    if (!empty($logger)) {
-      $query_end = microtime(TRUE);
-      $logger->log($this, $args, $query_end - $query_start);
-    }
-
-    // Initialize the first row in $this->currentRow.
-    $this->next();
-
-    return $return;
-  }
-
-  /**
-   * Throw a PDO Exception based on the last PDO error.
-   */
-  protected function throwPDOException() {
-    $error_info = $this->dbh->errorInfo();
-    // We rebuild a message formatted in the same way as PDO.
-    $exception = new PDOException("SQLSTATE[" . $error_info[0] . "]: General error " . $error_info[1] . ": " . $error_info[2]);
-    $exception->errorInfo = $error_info;
-    throw $exception;
-  }
-
-  /**
-   * Grab a PDOStatement object from a given query and its arguments.
-   *
-   * Some drivers (including SQLite) will need to perform some preparation
-   * themselves to get the statement right.
-   *
-   * @param $query
-   *   The query.
-   * @param array $args
-   *   An array of arguments.
-   * @return PDOStatement
-   *   A PDOStatement object.
-   */
-  protected function getStatement($query, &$args = array()) {
-    return $this->dbh->prepare($query);
-  }
-
-  /**
-   * Return the object's SQL query string.
-   */
-  public function getQueryString() {
-    return $this->queryString;
-  }
-
-  /**
-   * @see PDOStatement::setFetchMode()
-   */
-  public function setFetchMode($fetchStyle, $a2 = NULL, $a3 = NULL) {
-    $this->defaultFetchStyle = $fetchStyle;
-    switch ($fetchStyle) {
-      case PDO::FETCH_CLASS:
-        $this->defaultFetchOptions['class'] = $a2;
-        if ($a3) {
-          $this->defaultFetchOptions['constructor_args'] = $a3;
-        }
-        break;
-      case PDO::FETCH_COLUMN:
-        $this->defaultFetchOptions['column'] = $a2;
-        break;
-      case PDO::FETCH_INTO:
-        $this->defaultFetchOptions['object'] = $a2;
-        break;
-    }
-
-    // Set the values for the next fetch.
-    $this->fetchStyle = $this->defaultFetchStyle;
-    $this->fetchOptions = $this->defaultFetchOptions;
-  }
-
-  /**
-   * Return the current row formatted according to the current fetch style.
-   *
-   * This is the core method of this class. It grabs the value at the current
-   * array position in $this->data and format it according to $this->fetchStyle
-   * and $this->fetchMode.
-   *
-   * @return
-   *  The current row formatted as requested.
-   */
-  public function current() {
-    if (isset($this->currentRow)) {
-      switch ($this->fetchStyle) {
-        case PDO::FETCH_ASSOC:
-          return $this->currentRow;
-        case PDO::FETCH_BOTH:
-          // PDO::FETCH_BOTH returns an array indexed by both the column name
-          // and the column number.
-          return $this->currentRow + array_values($this->currentRow);
-        case PDO::FETCH_NUM:
-          return array_values($this->currentRow);
-        case PDO::FETCH_LAZY:
-          // We do not do lazy as everything is fetched already. Fallback to
-          // PDO::FETCH_OBJ.
-        case PDO::FETCH_OBJ:
-          return (object) $this->currentRow;
-        case PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE:
-          $class_name = array_unshift($this->currentRow);
-          // Deliberate no break.
-        case PDO::FETCH_CLASS:
-          if (!isset($class_name)) {
-            $class_name = $this->fetchOptions['class'];
-          }
-          if (count($this->fetchOptions['constructor_args'])) {
-            $reflector = new ReflectionClass($class_name);
-            $result = $reflector->newInstanceArgs($this->fetchOptions['constructor_args']);
-          }
-          else {
-            $result = new $class_name();
-          }
-          foreach ($this->currentRow as $k => $v) {
-            $result->$k = $v;
-          }
-          return $result;
-        case PDO::FETCH_INTO:
-          foreach ($this->currentRow as $k => $v) {
-            $this->fetchOptions['object']->$k = $v;
-          }
-          return $this->fetchOptions['object'];
-        case PDO::FETCH_COLUMN:
-          if (isset($this->columnNames[$this->fetchOptions['column']])) {
-            return $this->currentRow[$k][$this->columnNames[$this->fetchOptions['column']]];
-          }
-          else {
-            return;
-          }
-      }
-    }
-  }
-
-  /* Implementations of Iterator. */
-
-  public function key() {
-    return $this->currentKey;
-  }
-
-  public function rewind() {
-    // Nothing to do: our DatabaseStatement can't be rewound.
-  }
-
-  public function next() {
-    if (!empty($this->data)) {
-      $this->currentRow = reset($this->data);
-      $this->currentKey = key($this->data);
-      unset($this->data[$this->currentKey]);
-    }
-    else {
-      $this->currentRow = NULL;
-    }
-  }
-
-  public function valid() {
-    return isset($this->currentRow);
-  }
-
-  /* Implementations of DatabaseStatementInterface. */
-
-  public function rowCount() {
-    return $this->rowCount;
-  }
-
-  public function fetch($fetch_style = NULL, $cursor_orientation = PDO::FETCH_ORI_NEXT, $cursor_offset = NULL) {
-    if (isset($this->currentRow)) {
-      // Set the fetch parameter.
-      $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
-      $this->fetchOptions = $this->defaultFetchOptions;
-
-      // Grab the row in the format specified above.
-      $return = $this->current();
-      // Advance the cursor.
-      $this->next();
-
-      // Reset the fetch parameters to the value stored using setFetchMode().
-      $this->fetchStyle = $this->defaultFetchStyle;
-      $this->fetchOptions = $this->defaultFetchOptions;
-      return $return;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  public function fetchColumn($index = 0) {
-    if (isset($this->currentRow) && isset($this->columnNames[$index])) {
-      // We grab the value directly from $this->data, and format it.
-      $return = $this->currentRow[$this->columnNames[$index]];
-      $this->next();
-      return $return;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  public function fetchField($index = 0) {
-    return $this->fetchColumn($index);
-  }
-
-  public function fetchObject($class_name = NULL, $constructor_args = array()) {
-    if (isset($this->currentRow)) {
-      if (!isset($class_name)) {
-        // Directly cast to an object to avoid a function call.
-        $result = (object) $this->currentRow;
-      }
-      else {
-        $this->fetchStyle = PDO::FETCH_CLASS;
-        $this->fetchOptions = array('constructor_args' => $constructor_args);
-        // Grab the row in the format specified above.
-        $result = $this->current();
-        // Reset the fetch parameters to the value stored using setFetchMode().
-        $this->fetchStyle = $this->defaultFetchStyle;
-        $this->fetchOptions = $this->defaultFetchOptions;
-      }
-
-      $this->next();
-
-      return $result;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  public function fetchAssoc() {
-    if (isset($this->currentRow)) {
-      $result = $this->currentRow;
-      $this->next();
-      return $result;
-    }
-    else {
-      return FALSE;
-    }
-  }
-
-  public function fetchAll($fetch_style = NULL, $fetch_column = NULL, $constructor_args = NULL) {
-    $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
-    $this->fetchOptions = $this->defaultFetchOptions;
-    if (isset($fetch_column)) {
-      $this->fetchOptions['column'] = $fetch_column;
-    }
-    if (isset($constructor_args)) {
-      $this->fetchOptions['constructor_args'] = $constructor_args;
-    }
-
-    $result = array();
-    // Traverse the array as PHP would have done.
-    while (isset($this->currentRow)) {
-      // Grab the row in the format specified above.
-      $result[] = $this->current();
-      $this->next();
-    }
-
-    // Reset the fetch parameters to the value stored using setFetchMode().
-    $this->fetchStyle = $this->defaultFetchStyle;
-    $this->fetchOptions = $this->defaultFetchOptions;
-    return $result;
-  }
-
-  public function fetchCol($index = 0) {
-    if (isset($this->columnNames[$index])) {
-      $column = $this->columnNames[$index];
-      $result = array();
-      // Traverse the array as PHP would have done.
-      while (isset($this->currentRow)) {
-        $result[] = $this->currentRow[$this->columnNames[$index]];
-        $this->next();
-      }
-      return $result;
-    }
-    else {
-      return array();
-    }
-  }
-
-  public function fetchAllKeyed($key_index = 0, $value_index = 1) {
-    if (!isset($this->columnNames[$key_index]) || !isset($this->columnNames[$value_index]))
-      return array();
-
-    $key = $this->columnNames[$key_index];
-    $value = $this->columnNames[$value_index];
-
-    $result = array();
-    // Traverse the array as PHP would have done.
-    while (isset($this->currentRow)) {
-      $result[$this->currentRow[$key]] = $this->currentRow[$value];
-      $this->next();
-    }
-    return $result;
-  }
-
-  public function fetchAllAssoc($key, $fetch_style = NULL) {
-    $this->fetchStyle = isset($fetch_style) ? $fetch_style : $this->defaultFetchStyle;
-    $this->fetchOptions = $this->defaultFetchOptions;
-
-    $result = array();
-    // Traverse the array as PHP would have done.
-    while (isset($this->currentRow)) {
-      // Grab the row in its raw PDO::FETCH_ASSOC format.
-      $row = $this->currentRow;
-      // Grab the row in the format specified above.
-      $result_row = $this->current();
-      $result[$this->currentRow[$key]] = $result_row;
-      $this->next();
-    }
-
-    // Reset the fetch parameters to the value stored using setFetchMode().
-    $this->fetchStyle = $this->defaultFetchStyle;
-    $this->fetchOptions = $this->defaultFetchOptions;
-    return $result;
-  }
-
-}
-
-/**
- * @} End of "ingroup database".
- */
-
diff --git a/core/includes/database/query.inc b/core/includes/database/query.inc
deleted file mode 100644
index 0effeda..0000000
--- 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/schema.inc b/core/includes/database/schema.inc
deleted file mode 100644
index 27934dc..0000000
--- a/core/includes/database/schema.inc
+++ /dev/null
@@ -1,723 +0,0 @@
-<?php
-
-/**
- * @file
- * Generic Database schema code.
- */
-
-require_once __DIR__ . '/query.inc';
-
-/**
- * @defgroup schemaapi Schema API
- * @{
- * API to handle database schemas.
- *
- * A Drupal schema definition is an array structure representing one or
- * more tables and their related keys and indexes. A schema is defined by
- * hook_schema(), which usually lives in a modulename.install file.
- *
- * By implementing hook_schema() and specifying the tables your module
- * declares, you can easily create and drop these tables on all
- * supported database engines. You don't have to deal with the
- * different SQL dialects for table creation and alteration of the
- * supported database engines.
- *
- * hook_schema() should return an array with a key for each table that
- * the module defines.
- *
- * The following keys are defined:
- *   - 'description': A string in non-markup plain text describing this table
- *     and its purpose. References to other tables should be enclosed in
- *     curly-brackets. For example, the node_revisions table
- *     description field might contain "Stores per-revision title and
- *     body data for each {node}."
- *   - 'fields': An associative array ('fieldname' => specification)
- *     that describes the table's database columns. The specification
- *     is also an array. The following specification parameters are defined:
- *     - 'description': A string in non-markup plain text describing this field
- *       and its purpose. References to other tables should be enclosed in
- *       curly-brackets. For example, the node table vid field
- *       description might contain "Always holds the largest (most
- *       recent) {node_revision}.vid value for this nid."
- *     - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int',
- *       'float', 'numeric', or 'serial'. Most types just map to the according
- *       database engine specific datatypes. Use 'serial' for auto incrementing
- *       fields. This will expand to 'INT auto_increment' on MySQL.
- *     - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to
- *       use a record type not included in the officially supported list
- *       of types above, you can specify a type for each database
- *       backend. In this case, you can leave out the type parameter,
- *       but be advised that your schema will fail to load on backends that
- *       do not have a type specified. A possible solution can be to
- *       use the "text" type as a fallback.
- *     - 'serialize': A boolean indicating whether the field will be stored as
- *       a serialized string.
- *     - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
- *       'big'. This is a hint about the largest value the field will
- *       store and determines which of the database engine specific
- *       datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs. BIGINT).
- *       'normal', the default, selects the base type (e.g. on MySQL,
- *       INT, VARCHAR, BLOB, etc.).
- *       Not all sizes are available for all data types. See
- *       DatabaseSchema::getFieldTypeMap() for possible combinations.
- *     - 'not null': If true, no NULL values will be allowed in this
- *       database column. Defaults to false.
- *     - 'default': The field's default value. The PHP type of the
- *       value matters: '', '0', and 0 are all different. If you
- *       specify '0' as the default value for a type 'int' field it
- *       will not work because '0' is a string containing the
- *       character "zero", not an integer.
- *     - 'length': The maximal length of a type 'char', 'varchar' or 'text'
- *       field. Ignored for other field types.
- *     - 'unsigned': A boolean indicating whether a type 'int', 'float'
- *       and 'numeric' only is signed or unsigned. Defaults to
- *       FALSE. Ignored for other field types.
- *     - 'precision', 'scale': For type 'numeric' fields, indicates
- *       the precision (total number of significant digits) and scale
- *       (decimal digits right of the decimal point). Both values are
- *       mandatory. Ignored for other field types.
- *     All parameters apart from 'type' are optional except that type
- *     'numeric' columns must specify 'precision' and 'scale'.
- *  - 'primary key': An array of one or more key column specifiers (see below)
- *    that form the primary key.
- *  - 'unique keys': An associative array of unique keys ('keyname' =>
- *    specification). Each specification is an array of one or more
- *    key column specifiers (see below) that form a unique key on the table.
- *  - 'foreign keys': An associative array of relations ('my_relation' =>
- *    specification). Each specification is an array containing the name of
- *    the referenced table ('table'), and an array of column mappings
- *    ('columns'). Column mappings are defined by key pairs ('source_column' =>
- *    'referenced_column').
- *  - 'indexes':  An associative array of indexes ('indexname' =>
- *    specification). Each specification is an array of one or more
- *    key column specifiers (see below) that form an index on the
- *    table.
- *
- * A key column specifier is either a string naming a column or an
- * array of two elements, column name and length, specifying a prefix
- * of the named column.
- *
- * As an example, here is a SUBSET of the schema definition for
- * Drupal's 'node' table. It show four fields (nid, vid, type, and
- * title), the primary key on field 'nid', a unique key named 'vid' on
- * field 'vid', and two indexes, one named 'nid' on field 'nid' and
- * one named 'node_title_type' on the field 'title' and the first four
- * bytes of the field 'type':
- *
- * @code
- * $schema['node'] = array(
- *   'description' => 'The base table for nodes.',
- *   'fields' => array(
- *     'nid'       => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
- *     'vid'       => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE,'default' => 0),
- *     'type'      => array('type' => 'varchar','length' => 32,'not null' => TRUE, 'default' => ''),
- *     'language'  => array('type' => 'varchar','length' => 12,'not null' => TRUE,'default' => ''),
- *     'title'     => array('type' => 'varchar','length' => 255,'not null' => TRUE, 'default' => ''),
- *     'uid'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'status'    => array('type' => 'int', 'not null' => TRUE, 'default' => 1),
- *     'created'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'changed'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'comment'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'promote'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'moderate'  => array('type' => 'int', 'not null' => TRUE,'default' => 0),
- *     'sticky'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *     'tnid'      => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
- *     'translate' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
- *   ),
- *   'indexes' => array(
- *     'node_changed'        => array('changed'),
- *     'node_created'        => array('created'),
- *     'node_moderate'       => array('moderate'),
- *     'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
- *     'node_status_type'    => array('status', 'type', 'nid'),
- *     'node_title_type'     => array('title', array('type', 4)),
- *     'node_type'           => array(array('type', 4)),
- *     'uid'                 => array('uid'),
- *     'tnid'                => array('tnid'),
- *     'translate'           => array('translate'),
- *   ),
- *   'unique keys' => array(
- *     'vid' => array('vid'),
- *   ),
- *   'foreign keys' => array(
- *     'node_revision' => array(
- *       'table' => 'node_revision',
- *       'columns' => array('vid' => 'vid'),
- *      ),
- *     'node_author' => array(
- *       'table' => 'users',
- *       'columns' => array('uid' => 'uid'),
- *      ),
- *    ),
- *   'primary key' => array('nid'),
- * );
- * @endcode
- *
- * @see drupal_install_schema()
- */
-
-abstract class DatabaseSchema implements QueryPlaceholderInterface {
-
-  protected $connection;
-
-  /**
-   * The placeholder counter.
-   */
-  protected $placeholder = 0;
-
-  /**
-   * Definition of prefixInfo array structure.
-   *
-   * Rather than redefining DatabaseSchema::getPrefixInfo() for each driver,
-   * by defining the defaultSchema variable only MySQL has to re-write the
-   * method.
-   *
-   * @see DatabaseSchema::getPrefixInfo()
-   */
-  protected $defaultSchema = 'public';
-
-  /**
-   * A unique identifier for this query object.
-   */
-  protected $uniqueIdentifier;
-
-  public function __construct($connection) {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-    $this->connection = $connection;
-  }
-
-  /**
-   * Implements the magic __clone function.
-   */
-  public function __clone() {
-    $this->uniqueIdentifier = uniqid('', TRUE);
-  }
-
-  /**
-   * Implements QueryPlaceHolderInterface::uniqueIdentifier().
-   */
-  public function uniqueIdentifier() {
-    return $this->uniqueIdentifier;
-  }
-
-  /**
-   * Implements QueryPlaceHolderInterface::nextPlaceholder().
-   */
-  public function nextPlaceholder() {
-    return $this->placeholder++;
-  }
-
-  /**
-   * Get information about the table name and schema from the prefix.
-   *
-   * @param
-   *   Name of table to look prefix up for. Defaults to 'default' because thats
-   *   default key for prefix.
-   * @param $add_prefix
-   *   Boolean that indicates whether the given table name should be prefixed.
-   *
-   * @return
-   *   A keyed array with information about the schema, table name and prefix.
-   */
-  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
-    $info = array(
-      'schema' => $this->defaultSchema,
-      'prefix' => $this->connection->tablePrefix($table),
-    );
-    if ($add_prefix) {
-      $table = $info['prefix'] . $table;
-    }
-    // If the prefix contains a period in it, then that means the prefix also
-    // contains a schema reference in which case we will change the schema key
-    // to the value before the period in the prefix. Everything after the dot
-    // will be prefixed onto the front of the table.
-    if (($pos = strpos($table, '.')) !== FALSE) {
-      // Grab everything before the period.
-      $info['schema'] = substr($table, 0, $pos);
-      // Grab everything after the dot.
-      $info['table'] = substr($table, ++$pos);
-    }
-    else {
-      $info['table'] = $table;
-    }
-    return $info;
-  }
-
-  /**
-   * Create names for indexes, primary keys and constraints.
-   *
-   * This prevents using {} around non-table names like indexes and keys.
-   */
-  function prefixNonTable($table) {
-    $args = func_get_args();
-    $info = $this->getPrefixInfo($table);
-    $args[0] = $info['table'];
-    return implode('_', $args);
-  }
-
-  /**
-   * Build a condition to match a table name against a standard information_schema.
-   *
-   * The information_schema is a SQL standard that provides information about the
-   * database server and the databases, schemas, tables, columns and users within
-   * it. This makes information_schema a useful tool to use across the drupal
-   * database drivers and is used by a few different functions. The function below
-   * describes the conditions to be meet when querying information_schema.tables
-   * for drupal tables or information associated with drupal tables. Even though
-   * this is the standard method, not all databases follow standards and so this
-   * method should be overwritten by a database driver if the database provider
-   * uses alternate methods. Because information_schema.tables is used in a few
-   * different functions, a database driver will only need to override this function
-   * to make all the others work. For example see
-   * core/includes/databases/mysql/schema.inc.
-   *
-   * @param $table_name
-   *   The name of the table in question.
-   * @param $operator
-   *   The operator to apply on the 'table' part of the condition.
-   * @param $add_prefix
-   *   Boolean to indicate whether the table name needs to be prefixed.
-   *
-   * @return QueryConditionInterface
-   *   A DatabaseCondition object.
-   */
-  protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
-    $info = $this->connection->getConnectionOptions();
-
-    // Retrive the table name and schema
-    $table_info = $this->getPrefixInfo($table_name, $add_prefix);
-
-    $condition = new DatabaseCondition('AND');
-    $condition->condition('table_catalog', $info['database']);
-    $condition->condition('table_schema', $table_info['schema']);
-    $condition->condition('table_name', $table_info['table'], $operator);
-    return $condition;
-  }
-
-  /**
-   * Check if a table exists.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   *
-   * @return
-   *   TRUE if the given table exists, otherwise FALSE.
-   */
-  public function tableExists($table) {
-    $condition = $this->buildTableNameCondition($table);
-    $condition->compile($this->connection, $this);
-    // Normally, we would heartily discourage the use of string
-    // concatenation for conditionals like this however, we
-    // couldn't use db_select() here because it would prefix
-    // information_schema.tables and the query would fail.
-    // Don't use {} around information_schema.tables table.
-    return (bool) $this->connection->query("SELECT 1 FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
-  }
-
-  /**
-   * Find all tables that are like the specified base table name.
-   *
-   * @param $table_expression
-   *   An SQL expression, for example "simpletest%" (without the quotes).
-   *   BEWARE: this is not prefixed, the caller should take care of that.
-   *
-   * @return
-   *   Array, both the keys and the values are the matching tables.
-   */
-  public function findTables($table_expression) {
-    $condition = $this->buildTableNameCondition($table_expression, 'LIKE', FALSE);
-
-    $condition->compile($this->connection, $this);
-    // Normally, we would heartily discourage the use of string
-    // concatenation for conditionals like this however, we
-    // couldn't use db_select() here because it would prefix
-    // information_schema.tables and the query would fail.
-    // Don't use {} around information_schema.tables table.
-    return $this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0);
-  }
-
-  /**
-   * Check if a column exists in the given table.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   * @param $name
-   *   The name of the column.
-   *
-   * @return
-   *   TRUE if the given column exists, otherwise FALSE.
-   */
-  public function fieldExists($table, $column) {
-    $condition = $this->buildTableNameCondition($table);
-    $condition->condition('column_name', $column);
-    $condition->compile($this->connection, $this);
-    // Normally, we would heartily discourage the use of string
-    // concatenation for conditionals like this however, we
-    // couldn't use db_select() here because it would prefix
-    // information_schema.tables and the query would fail.
-    // Don't use {} around information_schema.columns table.
-    return (bool) $this->connection->query("SELECT 1 FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
-  }
-
-  /**
-   * Returns a mapping of Drupal schema field names to DB-native field types.
-   *
-   * Because different field types do not map 1:1 between databases, Drupal has
-   * its own normalized field type names. This function returns a driver-specific
-   * mapping table from Drupal names to the native names for each database.
-   *
-   * @return array
-   *   An array of Schema API field types to driver-specific field types.
-   */
-  abstract public function getFieldTypeMap();
-
-  /**
-   * Rename a table.
-   *
-   * @param $table
-   *   The table to be renamed.
-   * @param $new_name
-   *   The new name for the table.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If a table with the specified new name already exists.
-   */
-  abstract public function renameTable($table, $new_name);
-
-  /**
-   * Drop a table.
-   *
-   * @param $table
-   *   The table to be dropped.
-   *
-   * @return
-   *   TRUE if the table was successfully dropped, FALSE if there was no table
-   *   by that name to begin with.
-   */
-  abstract public function dropTable($table);
-
-  /**
-   * Add a new field to a table.
-   *
-   * @param $table
-   *   Name of the table to be altered.
-   * @param $field
-   *   Name of the field to be added.
-   * @param $spec
-   *   The field specification array, as taken from a schema definition.
-   *   The specification may also contain the key 'initial', the newly
-   *   created field will be set to the value of the key in all rows.
-   *   This is most useful for creating NOT NULL columns with no default
-   *   value in existing tables.
-   * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
-   *   table along with adding the field. The format is the same as a
-   *   table specification but without the 'fields' element. If you are
-   *   adding a type 'serial' field, you MUST specify at least one key
-   *   or index including it in this array. See db_change_field() for more
-   *   explanation why.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified table already has a field by that name.
-   */
-  abstract public function addField($table, $field, $spec, $keys_new = array());
-
-  /**
-   * Drop a field.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be dropped.
-   *
-   * @return
-   *   TRUE if the field was successfully dropped, FALSE if there was no field
-   *   by that name to begin with.
-   */
-  abstract public function dropField($table, $field);
-
-  /**
-   * Set the default value for a field.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be altered.
-   * @param $default
-   *   Default value to be set. NULL for 'default NULL'.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table or field doesn't exist.
-   */
-  abstract public function fieldSetDefault($table, $field, $default);
-
-  /**
-   * Set a field to have no default value.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $field
-   *   The field to be altered.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table or field doesn't exist.
-   */
-  abstract public function fieldSetNoDefault($table, $field);
-
-  /**
-   * Checks if an index exists in the given table.
-   *
-   * @param $table
-   *   The name of the table in drupal (no prefixing).
-   * @param $name
-   *   The name of the index in drupal (no prefixing).
-   *
-   * @return
-   *   TRUE if the given index exists, otherwise FALSE.
-   */
-  abstract public function indexExists($table, $name);
-
-  /**
-   * Add a primary key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $fields
-   *   Fields for the primary key.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified table already has a primary key.
-   */
-  abstract public function addPrimaryKey($table, $fields);
-
-  /**
-   * Drop the primary key.
-   *
-   * @param $table
-   *   The table to be altered.
-   *
-   * @return
-   *   TRUE if the primary key was successfully dropped, FALSE if there was no
-   *   primary key on this table to begin with.
-   */
-  abstract public function dropPrimaryKey($table);
-
-  /**
-   * Add a unique key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the key.
-   * @param $fields
-   *   An array of field names.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified table already has a key by that name.
-   */
-  abstract public function addUniqueKey($table, $name, $fields);
-
-  /**
-   * Drop a unique key.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the key.
-   *
-   * @return
-   *   TRUE if the key was successfully dropped, FALSE if there was no key by
-   *   that name to begin with.
-   */
-  abstract public function dropUniqueKey($table, $name);
-
-  /**
-   * Add an index.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the index.
-   * @param $fields
-   *   An array of field names.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified table already has an index by that name.
-   */
-  abstract public function addIndex($table, $name, $fields);
-
-  /**
-   * Drop an index.
-   *
-   * @param $table
-   *   The table to be altered.
-   * @param $name
-   *   The name of the index.
-   *
-   * @return
-   *   TRUE if the index was successfully dropped, FALSE if there was no index
-   *   by that name to begin with.
-   */
-  abstract public function dropIndex($table, $name);
-
-  /**
-   * Change a field definition.
-   *
-   * IMPORTANT NOTE: To maintain database portability, you have to explicitly
-   * recreate all indices and primary keys that are using the changed field.
-   *
-   * That means that you have to drop all affected keys and indexes with
-   * db_drop_{primary_key,unique_key,index}() before calling db_change_field().
-   * To recreate the keys and indices, pass the key definitions as the
-   * optional $keys_new argument directly to db_change_field().
-   *
-   * For example, suppose you have:
-   * @code
-   * $schema['foo'] = array(
-   *   'fields' => array(
-   *     'bar' => array('type' => 'int', 'not null' => TRUE)
-   *   ),
-   *   'primary key' => array('bar')
-   * );
-   * @endcode
-   * and you want to change foo.bar to be type serial, leaving it as the
-   * primary key. The correct sequence is:
-   * @code
-   * db_drop_primary_key('foo');
-   * db_change_field('foo', 'bar', 'bar',
-   *   array('type' => 'serial', 'not null' => TRUE),
-   *   array('primary key' => array('bar')));
-   * @endcode
-   *
-   * The reasons for this are due to the different database engines:
-   *
-   * On PostgreSQL, changing a field definition involves adding a new field
-   * and dropping an old one which* causes any indices, primary keys and
-   * sequences (from serial-type fields) that use the changed field to be dropped.
-   *
-   * On MySQL, all type 'serial' fields must be part of at least one key
-   * or index as soon as they are created. You cannot use
-   * db_add_{primary_key,unique_key,index}() for this purpose because
-   * the ALTER TABLE command will fail to add the column without a key
-   * or index specification. The solution is to use the optional
-   * $keys_new argument to create the key or index at the same time as
-   * field.
-   *
-   * You could use db_add_{primary_key,unique_key,index}() in all cases
-   * unless you are converting a field to be type serial. You can use
-   * the $keys_new argument in all cases.
-   *
-   * @param $table
-   *   Name of the table.
-   * @param $field
-   *   Name of the field to change.
-   * @param $field_new
-   *   New name for the field (set to the same as $field if you don't want to change the name).
-   * @param $spec
-   *   The field specification for the new field.
-   * @param $keys_new
-   *   Optional keys and indexes specification to be created on the
-   *   table along with changing the field. The format is the same as a
-   *   table specification but without the 'fields' element.
-   *
-   * @throws DatabaseSchemaObjectDoesNotExistException
-   *   If the specified table or source field doesn't exist.
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified destination field already exists.
-   */
-  abstract public function changeField($table, $field, $field_new, $spec, $keys_new = array());
-
-  /**
-   * Create a new table from a Drupal table definition.
-   *
-   * @param $name
-   *   The name of the table to create.
-   * @param $table
-   *   A Schema API table definition array.
-   *
-   * @throws DatabaseSchemaObjectExistsException
-   *   If the specified table already exists.
-   */
-  public function createTable($name, $table) {
-    if ($this->tableExists($name)) {
-      throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
-    }
-    $statements = $this->createTableSql($name, $table);
-    foreach ($statements as $statement) {
-      $this->connection->query($statement);
-    }
-  }
-
-  /**
-   * Return an array of field names from an array of key/index column specifiers.
-   *
-   * This is usually an identity function but if a key/index uses a column prefix
-   * specification, this function extracts just the name.
-   *
-   * @param $fields
-   *   An array of key/index column specifiers.
-   *
-   * @return
-   *   An array of field names.
-   */
-  public function fieldNames($fields) {
-    $return = array();
-    foreach ($fields as $field) {
-      if (is_array($field)) {
-        $return[] = $field[0];
-      }
-      else {
-        $return[] = $field;
-      }
-    }
-    return $return;
-  }
-
-  /**
-   * Prepare a table or column comment for database query.
-   *
-   * @param $comment
-   *   The comment string to prepare.
-   * @param $length
-   *   Optional upper limit on the returned string length.
-   *
-   * @return
-   *   The prepared comment.
-   */
-  public function prepareComment($comment, $length = NULL) {
-    return $this->connection->quote($comment);
-  }
-}
-
-/**
- * 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/database/select.inc b/core/includes/database/select.inc
deleted file mode 100644
index 9bc6b92..0000000
--- 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 8d7f22d..925c9ae 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 a5d3e6b..2c71e0b 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 @@ class PagerDefault extends SelectQueryExtender {
    *   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 8961f7a..66a647e 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 7873cdb..799b0c7 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 496a043..b1d545b 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 92d244a..e7dea9e 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 773de3d..1ceac67 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 57607cd..be9366f 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 2e9b075..b52a8d9 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 a5fb606..0ad1171 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 831ea85..9221b0b 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 6e55fbd..32396a4 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 8945117..ca3d70e 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 29793b2..257043e 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 0157964..14c6eb5 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 12797ed..aa39688 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.
