summaryrefslogtreecommitdiff
path: root/includes/database/database.inc
diff options
context:
space:
mode:
authorDavid Rothstein <drothstein@gmail.com>2012-12-08 18:31:33 -0500
committerDavid Rothstein <drothstein@gmail.com>2012-12-08 18:31:33 -0500
commitc7e45d937d6ac63b2f4fc5a44ce3567159f86052 (patch)
treee84dd975f5eb7449fd927bd3d81087aff6192d3b /includes/database/database.inc
parentef10c14b7f0ddf5fb949083a34ddef5ebd2928f6 (diff)
downloadbrdo-c7e45d937d6ac63b2f4fc5a44ce3567159f86052.tar.gz
brdo-c7e45d937d6ac63b2f4fc5a44ce3567159f86052.tar.bz2
Issue #843114 by sun, quicksketch, Berdir | c960657: Fixed DatabaseConnection::__construct() and DatabaseConnection_mysql()::__construct() leaks $this (Too many connections).
Diffstat (limited to 'includes/database/database.inc')
-rw-r--r--includes/database/database.inc41
1 files changed, 35 insertions, 6 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()) {