Verified Commit 617d96e9 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3260007 by mondrake, yogeshmpawar, daffie, andypost: Decouple...

Issue #3260007 by mondrake, yogeshmpawar, daffie, andypost: Decouple Connection from the wrapped PDO connection to allow alternative clients
parent 8ed1f23d
Loading
Loading
Loading
Loading
+42 −32
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@
/**
 * 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.
 * This class provides a Drupal extension for a client database connection.
 * Every database driver implementation must provide a concrete implementation
 * of it to support special handling required by that database.
 * The most common database abstraction layer in PHP is PDO.
 *
 * @see http://php.net/manual/book.pdo.php
 */
@@ -87,9 +87,9 @@ abstract class Connection {
  protected $transactionalDDLSupport = FALSE;

  /**
   * The actual PDO connection.
   * The actual client connection.
   *
   * @var \PDO
   * @var object
   */
  protected $connection;

@@ -219,15 +219,15 @@ abstract class Connection {
  /**
   * Constructs a Connection object.
   *
   * @param \PDO $connection
   *   An object of the PDO class representing a database connection.
   * @param object $connection
   *   An object of the client class representing a database connection.
   * @param array $connection_options
   *   An array of options for the connection. May include the following:
   *   - prefix
   *   - namespace
   *   - Other driver-specific options.
   */
  public function __construct(\PDO $connection, array $connection_options) {
  public function __construct(object $connection, array $connection_options) {
    assert(count($this->identifierQuotes) === 2 && Inspector::assertAllStrings($this->identifierQuotes), '\Drupal\Core\Database\Connection::$identifierQuotes must contain 2 string values');

    // Manage the table prefix.
@@ -246,18 +246,18 @@ public function __construct(\PDO $connection, array $connection_options) {
  }

  /**
   * Opens a PDO connection.
   * Opens a client connection.
   *
   * @param array $connection_options
   *   The database connection settings array.
   *
   * @return \PDO
   *   A \PDO object.
   * @return object
   *   A client connection object.
   */
  public static function open(array &$connection_options = []) {}
  abstract public static function open(array &$connection_options = []);

  /**
   * Ensures that the PDO connection can be garbage collected.
   * Ensures that the client connection can be garbage collected.
   */
  public function __destruct() {
    // Ensure that the circular reference caused by Connection::__construct()
@@ -272,8 +272,8 @@ public function __destruct() {
   * A given query can be customized with a number of option flags in an
   * associative array:
   * - 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
   *   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
@@ -307,11 +307,11 @@ public function __destruct() {
   *   database type. In rare cases, such as creating an SQL function, []
   *   characters might be needed and can be allowed by changing this option to
   *   TRUE.
   * - pdo: By default, queries will execute with the PDO options set on the
   *   connection. In particular cases, it could be necessary to override the
   *   PDO driver options on the statement level. In such case, pass the
   *   required setting as an array here, and they will be passed to the
   *   prepared statement. See https://www.php.net/manual/en/pdo.prepare.php.
   * - pdo: By default, queries will execute with the client connection options
   *   set on the connection. In particular cases, it could be necessary to
   *   override the driver options on the statement level. In such case, pass
   *   the required setting as an array here, and they will be passed to the
   *   prepared statement.
   *
   * @return array
   *   An array of default query options.
@@ -483,7 +483,7 @@ public function getFullQualifiedTableName($table) {
   *   object. Defaults to FALSE.
   *
   * @return \Drupal\Core\Database\StatementInterface
   *   A PDO prepared statement ready for its execute() method.
   *   A prepared statement ready for its execute() method.
   *
   * @throws \InvalidArgumentException
   *   If multiple statements are included in the string, and delimiters are
@@ -712,8 +712,7 @@ protected function filterComment($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.
   * query. All queries executed by Drupal are executed as prepared statements.
   *
   * @param string $query
   *   The query to execute. This is a string containing an SQL query with
@@ -766,6 +765,9 @@ public function query($query, array $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.
      // @todo the block below is deprecated and as of Drupal 11 will be
      //   removed, query() will only return a StatementInterface object.
      // @see https://www.drupal.org/project/drupal/issues/3256524
      switch ($options['return'] ?? Database::RETURN_STATEMENT) {
        case Database::RETURN_STATEMENT:
          return $stmt;
@@ -779,7 +781,7 @@ public function query($query, array $args = [], $options = []) {

        case Database::RETURN_INSERT_ID:
          $sequence_name = $options['sequence_name'] ?? NULL;
          return $this->connection->lastInsertId($sequence_name);
          return $this->lastInsertId($sequence_name);

        case Database::RETURN_NULL:
          return NULL;
@@ -1008,10 +1010,6 @@ public function insert($table, array $options = []) {
   *
   * @throws \Drupal\Core\Database\DatabaseExceptionWrapper
   *   In case of failure.
   *
   * @see \PDO::lastInsertId
   *
   * @internal
   */
  public function lastInsertId(?string $name = NULL): string {
    if (($last_insert_id = $this->connection->lastInsertId($name)) === FALSE) {
@@ -1535,6 +1533,11 @@ abstract public function driver();

  /**
   * Returns the version of the database server.
   *
   * Assumes the client connection is \PDO. Non-PDO based drivers need to
   * override this method.
   *
   * @return string
   */
  public function version() {
    return $this->connection->getAttribute(\PDO::ATTR_SERVER_VERSION);
@@ -1542,6 +1545,11 @@ public function version() {

  /**
   * Returns the version of the database client.
   *
   * Assumes the client connection is \PDO. Non-PDO based drivers need to
   * override this method.
   *
   * @return string
   */
  public function clientVersion() {
    return $this->connection->getAttribute(\PDO::ATTR_CLIENT_VERSION);
@@ -1561,7 +1569,9 @@ public function supportsTransactionalDDL() {
  }

  /**
   * Returns the name of the PDO driver for this connection.
   * Returns the name of the database engine accessed by this driver.
   *
   * @return string
   */
  abstract public function databaseType();

@@ -1600,7 +1610,7 @@ abstract public function mapConditionOperator($operator);
   * 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.
   * the database client's transaction routines.
   *
   * @throws \Drupal\Core\Database\TransactionExplicitCommitNotAllowedException
   *
@@ -1649,7 +1659,7 @@ public function quote($string, $parameter_type = \PDO::PARAM_STR) {
  }

  /**
   * Extracts the SQLSTATE error from the PDOException.
   * Extracts the SQLSTATE error from a PDOException.
   *
   * @param \Exception $e
   *   The exception
+4 −4
Original line number Diff line number Diff line
@@ -390,8 +390,8 @@ final protected static function openConnection($key, $target) {

    $driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection';

    $pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
    $new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
    $client_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
    $new_connection = new $driver_class($client_connection, self::$databaseInfo[$key][$target]);
    $new_connection->setTarget($target);
    $new_connection->setKey($key);

@@ -424,8 +424,8 @@ public static function closeConnection($target = NULL, $key = NULL) {
    else {
      unset(self::$connections[$key]);
    }
    // Force garbage collection to run. This ensures that PDO connection objects
    // and destroyed and results in the connections being closed.
    // Force garbage collection to run. This ensures that client connection
    // objects and results in the connection being being closed are destroyed.
    gc_collect_cycles();
  }

+3 −4
Original line number Diff line number Diff line
@@ -6,9 +6,8 @@
/**
 * Interface for a database exception.
 *
 * All Database exceptions should implement this interface so that they can be
 * caught collectively.  Note that this applies only to Drupal-spawned
 * exceptions.  PDOException will not implement this interface and module
 * developers should account for it separately.
 * Database drivers should catch lower-level database client exceptions and
 * throw exceptions that implement this interface to allow database
 * abstraction in Drupal.
 */
interface DatabaseException { }
+2 −1
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
/**
 * This wrapper class serves only to provide additional debug information.
 *
 * This class will always wrap a PDOException.
 * This class will always wrap a client connection exception, for example
 * \PDOException or \mysqli_sql_exception.
 */
class DatabaseExceptionWrapper extends \RuntimeException implements DatabaseException {

+4 −3
Original line number Diff line number Diff line
@@ -5,9 +5,10 @@
/**
 * Base Database exception handler class.
 *
 * This class handles exceptions thrown by the database layer. Database driver
 * implementation can provide an alternative implementation to support special
 * handling required by that database.
 * This class handles exceptions thrown by the database layer of a PDO-based
 * database connection. Database driver implementations can provide an
 * alternative implementation to support special handling required by that
 * database.
 */
class ExceptionHandler {

Loading