summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngie Byron <webchick@24967.no-reply.drupal.org>2010-11-29 04:45:11 +0000
committerAngie Byron <webchick@24967.no-reply.drupal.org>2010-11-29 04:45:11 +0000
commit1a685474e698ce3e90dbae87f6a1f83966d9ef63 (patch)
tree309dd1ee9c5321635ef2a676373d324153fe9e1e
parent4e90d24dd9ff1474bf679f70a351dee371e87b51 (diff)
downloadbrdo-1a685474e698ce3e90dbae87f6a1f83966d9ef63.tar.gz
brdo-1a685474e698ce3e90dbae87f6a1f83966d9ef63.tar.bz2
#851136 by Crell, chx, Damien Tournoud: Make the database autoloading more robust.
-rw-r--r--includes/bootstrap.inc1
-rw-r--r--includes/database/database.inc132
-rw-r--r--includes/database/pgsql/query.inc92
-rw-r--r--includes/database/schema.inc2
-rw-r--r--includes/database/select.inc6
-rw-r--r--includes/database/sqlite/query.inc10
-rw-r--r--includes/install.core.inc1
-rw-r--r--includes/install.inc20
-rw-r--r--includes/theme.maintenance.inc1
-rw-r--r--modules/simpletest/drupal_web_test_case.php2
10 files changed, 66 insertions, 201 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 9060a0e20..1e446f01b 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -2244,7 +2244,6 @@ function _drupal_bootstrap_database() {
// The database autoload routine comes first so that we can load the database
// system without hitting the database. That is especially important during
// the install or upgrade process.
- spl_autoload_register('db_autoload');
spl_autoload_register('drupal_autoload_class');
spl_autoload_register('drupal_autoload_interface');
}
diff --git a/includes/database/database.inc b/includes/database/database.inc
index 98dafae8a..c85e35a10 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -648,13 +648,20 @@ abstract class DatabaseConnection extends PDO {
*
* @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) {
+ public function getDriverClass($class, array $files = array(), $use_autoload = FALSE) {
if (empty($this->driverClasses[$class])) {
- $this->driverClasses[$class] = $class . '_' . $this->driver();
- if (!class_exists($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;
}
}
@@ -681,7 +688,7 @@ abstract class DatabaseConnection extends PDO {
* @see SelectQuery
*/
public function select($table, $alias = NULL, array $options = array()) {
- $class = $this->getDriverClass('SelectQuery');
+ $class = $this->getDriverClass('SelectQuery', array('query.inc', 'select.inc'));
return new $class($table, $alias, $this, $options);
}
@@ -697,7 +704,7 @@ abstract class DatabaseConnection extends PDO {
* @see InsertQuery
*/
public function insert($table, array $options = array()) {
- $class = $this->getDriverClass('InsertQuery');
+ $class = $this->getDriverClass('InsertQuery', array('query.inc'));
return new $class($this, $table, $options);
}
@@ -713,7 +720,7 @@ abstract class DatabaseConnection extends PDO {
* @see MergeQuery
*/
public function merge($table, array $options = array()) {
- $class = $this->getDriverClass('MergeQuery');
+ $class = $this->getDriverClass('MergeQuery', array('query.inc'));
return new $class($this, $table, $options);
}
@@ -730,7 +737,7 @@ abstract class DatabaseConnection extends PDO {
* @see UpdateQuery
*/
public function update($table, array $options = array()) {
- $class = $this->getDriverClass('UpdateQuery');
+ $class = $this->getDriverClass('UpdateQuery', array('query.inc'));
return new $class($this, $table, $options);
}
@@ -746,7 +753,7 @@ abstract class DatabaseConnection extends PDO {
* @see DeleteQuery
*/
public function delete($table, array $options = array()) {
- $class = $this->getDriverClass('DeleteQuery');
+ $class = $this->getDriverClass('DeleteQuery', array('query.inc'));
return new $class($this, $table, $options);
}
@@ -762,7 +769,7 @@ abstract class DatabaseConnection extends PDO {
* @see TruncateQuery
*/
public function truncate($table, array $options = array()) {
- $class = $this->getDriverClass('TruncateQuery');
+ $class = $this->getDriverClass('TruncateQuery', array('query.inc'));
return new $class($this, $table, $options);
}
@@ -776,7 +783,7 @@ abstract class DatabaseConnection extends PDO {
*/
public function schema() {
if (empty($this->schema)) {
- $class = $this->getDriverClass('DatabaseSchema');
+ $class = $this->getDriverClass('DatabaseSchema', array('schema.inc'));
if (class_exists($class)) {
$this->schema = new $class($this);
}
@@ -1581,6 +1588,34 @@ abstract class Database {
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;
+ }
+ }
+ }
+ }
}
/**
@@ -2109,82 +2144,6 @@ class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface {
}
/**
- * Autoload callback for the database system.
- */
-function db_autoload($class) {
- static $base_path = '';
- static $checked = array();
-
- static $files = array(
- 'query.inc' => array(
- 'QueryPlaceholderInterface',
- 'QueryConditionInterface', 'DatabaseCondition',
- 'Query', 'DeleteQuery', 'InsertQuery', 'UpdateQuery', 'MergeQuery', 'TruncateQuery',
- 'QueryAlterableInterface',
- ),
- 'select.inc' => array('QueryAlterableInterface', 'SelectQueryInterface', 'SelectQuery', 'SelectQueryExtender'),
- 'database.inc' => array('DatabaseConnection'),
- 'log.inc' => array('DatabaseLog'),
- 'prefetch.inc' => array('DatabaseStatementPrefetch'),
- 'schema.inc' => array('DatabaseSchema'),
- );
-
- // If a class doesn't exist, it may get checked a second time
- // by class_exists(). If so, just bail out now.
- if (isset($checked[$class])) {
- return;
- }
- $checked[$class] = TRUE;
-
- if (empty($base_path)) {
- $base_path = dirname(realpath(__FILE__));
- }
-
- // If there is an underscore in the class name, we know it's a
- // driver-specific file so check for those. If not, it's a generic.
- // Note that we use require_once here instead of require because of a
- // quirk in class_exists(). By default, class_exists() will try to
- // autoload a class if it's not found. However, we cannot tell
- // at this point whether or not the class is going to exist, only
- // the file that it would be in if it does exist. That means we may
- // try to include a file that was already included by another
- // autoload call, which would break. Using require_once() neatly
- // avoids that issue.
- if (strpos($class, '_') !== FALSE) {
- list($base, $driver) = explode('_', $class);
-
- // Drivers have an extra file, and may put their SelectQuery implementation
- // in the main query file since it's so small.
- $driver_files = $files;
- $driver_files['query.inc'][] = 'SelectQuery';
- $driver_files['install.inc'] = array('DatabaseTasks');
-
- foreach ($driver_files as $file => $classes) {
- if (in_array($base, $classes)) {
- $filename = "{$base_path}/{$driver}/{$file}";
- // We might end up looking in a file that doesn't exist, so check that.
- if (file_exists($filename)) {
- require_once $filename;
- // If the class now exists, we're done. Otherwise keep searching in
- // additional files.
- if (class_exists($class, FALSE) || interface_exists($class, FALSE)) {
- return;
- }
- }
- }
- }
- }
- else {
- foreach ($files as $file => $classes) {
- if (in_array($class, $classes)) {
- require_once $base_path . '/' . $file;
- return;
- }
- }
- }
-}
-
-/**
* The following utility functions are simply convenience wrappers.
*
* They should never, ever have any database-specific code in them.
@@ -2915,4 +2874,3 @@ function db_ignore_slave() {
$_SESSION['ignore_slave_server'] = REQUEST_TIME + $duration;
}
}
-
diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc
index 2214d668a..c475a0011 100644
--- a/includes/database/pgsql/query.inc
+++ b/includes/database/pgsql/query.inc
@@ -208,95 +208,3 @@ class UpdateQuery_pgsql extends UpdateQuery {
return $stmt->rowCount();
}
}
-
-class SelectQuery_pgsql extends SelectQuery {
-
- public function orderRandom() {
- $alias = $this->addExpression('RANDOM()', 'random_field');
- $this->orderBy($alias);
- return $this;
- }
-
- /**
- * Overrides SelectQuery::orderBy().
- *
- * PostgreSQL adheres strictly to the SQL-92 standard and requires that when
- * using DISTINCT or GROUP BY conditions, fields and expressions that are
- * ordered on also need to be selected. This is a best effort implementation
- * to handle the cases that can be automated by adding the field if it is not
- * yet selected.
- *
- * @code
- * $query = db_select('node', 'n');
- * $query->join('node_revision', 'nr', 'n.vid = nr.vid');
- * $query
- * ->distinct()
- * ->fields('n')
- * ->orderBy('timestamp');
- * @endcode
- *
- * In this query, it is not possible (without relying on the schema) to know
- * whether timestamp belongs to node_revisions and needs to be added or
- * belongs to node and is already selected. Queries like this will need to be
- * corrected in the original query by adding an explicit call to
- * SelectQuery::addField() or SelectQuery::fields().
- *
- * Since this has a small performance impact, both by the additional
- * processing in this function and in the database that needs to return the
- * additional fields, this is done as an override instead of implementing it
- * directly in SelectQuery::orderBy().
- */
- public function orderBy($field, $direction = 'ASC') {
- // Call parent function to order on this.
- $return = parent::orderBy($field, $direction);
-
- // If there is a table alias specified, split it up.
- if (strpos($field, '.') !== FALSE) {
- list($table, $table_field) = explode('.', $field);
- }
- // Figure out if the field has already been added.
- foreach ($this->fields as $existing_field) {
- if (!empty($table)) {
- // If table alias is given, check if field and table exists.
- if ($existing_field['table'] == $table && $existing_field['field'] == $table_field) {
- return $return;
- }
- }
- else {
- // If there is no table, simply check if the field exists as a field or
- // an aliased field.
- if ($existing_field['alias'] == $field) {
- return $return;
- }
- }
- }
-
- // Also check expression aliases.
- foreach ($this->expressions as $expression) {
- if ($expression['alias'] == $field) {
- return $return;
- }
- }
-
- // If a table loads all fields, it can not be added again. It would
- // result in an ambigious alias error because that field would be loaded
- // twice: Once through table_alias.* and once directly. If the field
- // actually belongs to a different table, it must be added manually.
- foreach ($this->tables as $table) {
- if (!empty($table['all_fields'])) {
- return $return;
- }
- }
-
- // If $field contains an characters which are not allowed in a field name
- // it is considered an expression, these can't be handeld automatically
- // either.
- if ($this->connection->escapeField($field) != $field) {
- return $return;
- }
-
- // This is a case that can be handled automatically, add the field.
- $this->addField(NULL, $field);
- return $return;
- }
-}
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index 187f9e6b8..36c7964c6 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -6,6 +6,8 @@
* Generic Database schema code.
*/
+require_once dirname(__FILE__) . '/query.inc';
+
/**
* @defgroup schemaapi Schema API
* @{
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 7780fc5cd..b0d0eb275 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -6,6 +6,8 @@
* @{
*/
+require_once dirname(__FILE__) . '/query.inc';
+
/**
* Interface for extendable query objects.
*
@@ -642,7 +644,9 @@ class SelectQueryExtender implements SelectQueryInterface {
/* Implementations of QueryExtendableInterface. */
public function extend($extender_name) {
- $class = $this->connection->getDriverClass($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);
}
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index ec2b57a2c..158da3d0a 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -12,16 +12,6 @@
*/
/**
- * SQLite specific query builder for SELECT statements.
- */
-class SelectQuery_sqlite extends SelectQuery {
- public function forUpdate($set = TRUE) {
- // SQLite does not support FOR UPDATE so nothing to do.
- return $this;
- }
-}
-
-/**
* SQLite specific implementation of InsertQuery.
*
* We ignore all the default fields and use the clever SQLite syntax:
diff --git a/includes/install.core.inc b/includes/install.core.inc
index 5b01eb634..6a8c6f440 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -289,7 +289,6 @@ function install_begin_request(&$install_state) {
// Initialize the database system. Note that the connection
// won't be initialized until it is actually requested.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
- spl_autoload_register('db_autoload');
// Verify the last completed task in the database, if there is one.
$task = install_verify_completed_task();
diff --git a/includes/install.inc b/includes/install.inc
index 2c9810a08..1b7d7a796 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -254,7 +254,6 @@ function drupal_get_database_types() {
// Because we have no registry yet, we need to also include the install.inc
// file for the driver explicitly.
require_once DRUPAL_ROOT . '/includes/database/database.inc';
- spl_autoload_register('db_autoload');
foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
if (file_exists($file->uri . '/database.inc') && file_exists($file->uri . '/install.inc')) {
$drivers[$file->filename] = $file->uri;
@@ -262,8 +261,7 @@ function drupal_get_database_types() {
}
foreach ($drivers as $driver => $file) {
- $class = 'DatabaseTasks_' . $driver;
- $installer = new $class();
+ $installer = db_installer_object($driver);
if ($installer->installable()) {
$databases[$driver] = $installer;
}
@@ -1248,8 +1246,18 @@ function install_profile_info($profile, $locale = 'en') {
* encoding.
*/
function db_run_tasks($driver) {
- $task_class = 'DatabaseTasks_' . $driver;
- $DatabaseTasks = new $task_class();
- $DatabaseTasks->runTasks();
+ db_installer_object($driver)->runTasks();
return TRUE;
}
+
+/**
+ * Returns a database installer object.
+ *
+ * @param $driver
+ * The name of the driver.
+ */
+function db_installer_object($driver) {
+ Database::loadDriverFile($driver, array('install.inc'));
+ $task_class = 'DatabaseTasks_' . $driver;
+ return new $task_class();
+}
diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc
index 7cc03126f..4950d8278 100644
--- a/includes/theme.maintenance.inc
+++ b/includes/theme.maintenance.inc
@@ -41,7 +41,6 @@ function _drupal_maintenance_theme() {
// to work. See _drupal_log_error().
if (!class_exists('Database', FALSE)) {
require_once DRUPAL_ROOT . '/includes/database/database.inc';
- spl_autoload_register('db_autoload');
}
// We use the default theme as the maintenance theme. If a default theme
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index c5c63d8c5..e50adda62 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -611,8 +611,6 @@ class DrupalUnitTestCase extends DrupalTestCase {
// Store necessary current values before switching to the test environment.
$this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
- spl_autoload_register('db_autoload');
-
// Reset all statics so that test is performed with a clean environment.
drupal_static_reset();