diff options
Diffstat (limited to 'includes/database')
-rw-r--r-- | includes/database/database.inc | 41 | ||||
-rw-r--r-- | includes/database/mysql/database.inc | 17 |
2 files changed, 44 insertions, 14 deletions
diff --git a/includes/database/database.inc b/includes/database/database.inc index cae50fb87..26ce6fcf4 100644 --- a/includes/database/database.inc +++ b/includes/database/database.inc @@ -194,7 +194,7 @@ abstract class DatabaseConnection extends PDO { /** * 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). @@ -303,13 +303,29 @@ abstract class DatabaseConnection extends PDO { // Call PDO::__construct and PDO::setAttribute. parent::__construct($dsn, $username, $password, $driver_options); - // Set a specific PDOStatement class if the driver requires that. + // Set a Statement class, unless the driver opted out. if (!empty($this->statementClass)) { $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array($this->statementClass, array($this))); } } /** + * Destroys this Connection object. + * + * PHP does not destruct an object if it is still referenced in other + * variables. In case of PDO database connection objects, PHP only closes the + * connection when the PDO object is destructed, so any references to this + * object may cause the number of maximum allowed connections to be exceeded. + */ + public function destroy() { + // Destroy all references to this connection by setting them to NULL. + // The Statement class attribute only accepts a new value that presents a + // proper callable, so we reset it to PDOStatement. + $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array())); + $this->schema = NULL; + } + + /** * Returns the default query options for any given query. * * A given query can be customized with a number of option flags in an @@ -1627,8 +1643,8 @@ abstract class Database { */ final public static function removeConnection($key) { if (isset(self::$databaseInfo[$key])) { + self::closeConnection(NULL, $key); unset(self::$databaseInfo[$key]); - unset(self::$connections[$key]); return TRUE; } else { @@ -1694,11 +1710,24 @@ abstract class Database { if (!isset($key)) { $key = self::$activeKey; } - // To close the connection, we need to unset the static variable. + // To close a connection, it needs to be set to NULL and removed from the + // static variable. In all cases, closeConnection() might be called for a + // connection that was not opened yet, in which case the key is not defined + // yet and we just ensure that the connection key is undefined. if (isset($target)) { + if (isset(self::$connections[$key][$target])) { + self::$connections[$key][$target]->destroy(); + self::$connections[$key][$target] = NULL; + } unset(self::$connections[$key][$target]); } else { + if (isset(self::$connections[$key])) { + foreach (self::$connections[$key] as $target => $connection) { + self::$connections[$key][$target]->destroy(); + self::$connections[$key][$target] = NULL; + } + } unset(self::$connections[$key]); } } @@ -1852,8 +1881,8 @@ class DatabaseTransaction { */ protected $name; - public function __construct(DatabaseConnection &$connection, $name = NULL) { - $this->connection = &$connection; + 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()) { diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index 7ad019e58..00d81f473 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -13,11 +13,11 @@ class DatabaseConnection_mysql extends DatabaseConnection { /** - * Flag to indicate if we have registered the nextID cleanup function. + * Flag to indicate if the cleanup function in __destruct() should run. * * @var boolean */ - protected $shutdownRegistered = FALSE; + protected $needsCleanup = FALSE; public function __construct(array $connection_options = array()) { // This driver defaults to transaction support, except if explicitly passed FALSE. @@ -78,6 +78,12 @@ class DatabaseConnection_mysql extends DatabaseConnection { $this->exec(implode('; ', $connection_options['init_commands'])); } + public function __destruct() { + if ($this->needsCleanup) { + $this->nextIdDelete(); + } + } + public function queryRange($query, $from, $count, array $args = array(), array $options = array()) { return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options); } @@ -115,12 +121,7 @@ class DatabaseConnection_mysql extends DatabaseConnection { $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; - } + $this->needsCleanup = TRUE; return $new_id; } |