summaryrefslogtreecommitdiff
path: root/includes/database/database.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/database/database.inc')
-rw-r--r--includes/database/database.inc150
1 files changed, 149 insertions, 1 deletions
diff --git a/includes/database/database.inc b/includes/database/database.inc
index f237de62b..afa772d58 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -146,6 +146,22 @@ abstract class DatabaseConnection extends PDO {
*/
public $lastStatement;
+ /**
+ * The database target this connection is for.
+ *
+ * We need this information for later auditing and logging.
+ *
+ * @var string
+ */
+ protected $target = NULL;
+
+ /**
+ * The current database logging object for this connection.
+ *
+ * @var DatabaseLog
+ */
+ protected $logger = NULL;
+
function __construct($dsn, $username, $password, $driver_options = array()) {
$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; // Because the other methods don't seem to work right.
parent::__construct($dsn, $username, $password, $driver_options);
@@ -270,6 +286,55 @@ abstract class DatabaseConnection extends PDO {
}
/**
+ * Tell 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;
+ }
+
+ /**
+ * Associate a logging object with this connection.
+ *
+ * @param $logger
+ * The logging object we want to use.
+ */
+ public function setLogger(DatabaseLog $logger) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Get the current logging object for this connection.
+ *
+ * @return
+ * The current logging object for this connection. If there isn't one,
+ * NULL is returned.
+ */
+ public function getLogger() {
+ return $this->logger;
+ }
+
+ /**
* Create the appropriate sequence name for a given table and serial field.
*
* This information is exposed to all database drivers, although it is only
@@ -680,6 +745,67 @@ abstract class Database {
static protected $activeKey = 'default';
/**
+ * An array of active query log objects.
+ *
+ * @var array
+ */
+ static protected $logs = array();
+
+ /**
+ * Start logging a given logging key on the specified connection.
+ *
+ * @see DatabaseLog
+ * @param $logging_key
+ * The logging key to log.
+ * @param $key
+ * The database connection key for which we want to log.
+ * @return
+ * 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.
+ */
+ 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.
+ foreach (self::$connections[$key] as $connection) {
+ $connection->setLogger(self::$logs[$key]);
+ }
+ }
+ self::$logs[$key]->start($logging_key);
+
+ return self::$logs[$key];
+ }
+
+ /**
+ * Retrieve 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.
+ *
+ * @see DatabaseLog
+ * @param $logging_key
+ * The logging key to log.
+ * @param $key
+ * The database connection key for which we want to log.
+ * @return
+ * The query log for the specified logging key and connection.
+ */
+ 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 active connection object for the specified target.
*
* @return
@@ -864,6 +990,15 @@ abstract class Database {
$driver_class = 'DatabaseConnection_' . $driver;
require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc';
self::$connections[$key][$target] = new $driver_class(self::$databaseInfo[$key][$target]);
+ self::$connections[$key][$target]->setTarget($target);
+
+ // 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])) {
+ foreach (self::$logs[$key] as $log) {
+ self::$connections[$key][$target]->setLogger($log);
+ }
+ }
// We need to pass around the simpletest database prefix in the request
// and we put that in the user_agent header.
@@ -1069,7 +1204,20 @@ class DatabaseStatement extends PDOStatement {
}
}
$this->dbh->lastStatement = $this;
- return parent::execute($args);
+
+ $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;
}
/**