#195416: Table prefixes are now per database connection, update SimpleTest to deal with this.

From: Damien Tournoud <damien@tournoud.net>


---
 bootstrap.inc                       |   37 ++++++++++++
 common.inc                          |    6 +-
 database/database.inc               |  107 ++++++++++++++++++++++++++---------
 database/mysql/database.inc         |    2 +
 database/pgsql/database.inc         |    2 +
 database/sqlite/database.inc        |    2 +
 install.php                         |   23 +++-----
 simpletest/drupal_web_test_case.php |  104 ++++++++++++++++------------------
 default/default.settings.php        |   18 +++---
 9 files changed, 192 insertions(+), 109 deletions(-)

diff --git includes/bootstrap.inc includes/bootstrap.inc
index 280a56a..f814b24 100644
--- includes/bootstrap.inc
+++ includes/bootstrap.inc
@@ -457,7 +457,7 @@ function conf_init() {
   global $base_url, $base_path, $base_root;
 
   // Export the following settings.php variables to the global namespace
-  global $databases, $db_prefix, $cookie_domain, $conf, $installed_profile, $update_free_access;
+  global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access;
   $conf = array();
 
   if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
@@ -527,6 +527,41 @@ function conf_init() {
     ini_set('session.cookie_domain', $cookie_domain);
   }
   session_name('SESS' . md5($session_name));
+
+  // Use the simpletest database prefix passed by the user agent header.
+  if (preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT'])) {
+    // Set the test run id for use in other parts of Drupal.
+    drupal_test_info(array('test_run_id' => $_SERVER['HTTP_USER_AGENT'], 'in_child_site' => TRUE));
+
+    foreach ($databases['default'] as $target => $value) {
+      // Extract the current default database prefix.
+      if (empty($value['prefix'])) {
+        $current_prefix = '';
+      }
+      else if (is_array($value['prefix'])) {
+        $current_prefix = $value['prefix']['default'];
+      }
+      else {
+        $current_prefix = $value['prefix'];
+      }
+
+      // Remove the current database prefix and replace it by our own.
+      $databases['default'][$target]['prefix'] = array(
+        'default' => $current_prefix . $_SERVER['HTTP_USER_AGENT'],
+      );
+    }
+  }
+}
+
+/**
+ * Retrieve (and optionally set) information about the current test being run.
+ */
+function drupal_test_info($value = FALSE) {
+  static $cache;
+  if ($value !== FALSE) {
+    $cache = $value;
+  }
+  return $cache;
 }
 
 /**
diff --git includes/common.inc includes/common.inc
index e48e6a7..bdd7b02 100644
--- includes/common.inc
+++ includes/common.inc
@@ -464,8 +464,6 @@ function drupal_access_denied() {
  *       A string containing the response body that was received.
  */
 function drupal_http_request($url, array $options = array()) {
-  global $db_prefix;
-
   $result = new stdClass();
 
   // Parse the URL and make sure we can handle the schema.
@@ -549,8 +547,8 @@ function drupal_http_request($url, array $options = array()) {
   // user-agent is used to ensure that multiple testing sessions running at the
   // same time won't interfere with each other as they would if the database
   // prefix were stored statically in a file or database variable.
-  if (preg_match("/simpletest\d+/", $db_prefix, $matches)) {
-    $options['headers']['User-Agent'] = $matches[0];
+  if ($test_info = drupal_test_info()) {
+    $options['headers']['User-Agent'] = $test_info['test_run_id'];
   }
 
   foreach ($options['headers'] as $name => $value) {
diff --git includes/database/database.inc includes/database/database.inc
index 94aad52..7ab1141 100644
--- includes/database/database.inc
+++ includes/database/database.inc
@@ -319,6 +319,16 @@ abstract class DatabaseConnection extends PDO {
    */
   protected $schema = NULL;
 
+  /**
+   * The default prefix used by that database connection.
+   */
+  protected $defaultPrefix = NULL;
+
+  /**
+   * The non-default prefixes used by that database connection.
+   */
+  protected $prefixes = array();
+
   function __construct($dsn, $username, $password, $driver_options = array()) {
     // Because the other methods don't seem to work right.
     $driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
@@ -392,6 +402,24 @@ abstract class DatabaseConnection extends PDO {
   }
 
   /**
+   * Preprocess the prefix used by this database connection.
+   *
+   * @param $prefix
+   *   The prefix, in any of the multiple forms documented in default.settings.php.
+   */
+  protected function setPrefix($prefix) {
+    if (is_array($prefix)) {
+      $this->defaultPrefix = isset($prefix['default']) ? $prefix['default'] : '';
+      unset($prefix['default']);
+      $this->prefixes = $prefix;
+    }
+    else {
+      $this->defaultPrefix = $prefix;
+      $this->prefixes = array();
+    }
+  }
+
+  /**
    * Append a database prefix to all tables in a query.
    *
    * Queries sent to Drupal should wrap all table names in curly brackets. This
@@ -405,27 +433,12 @@ abstract class DatabaseConnection extends PDO {
    *   The properly-prefixed string.
    */
   public function prefixTables($sql) {
-    global $db_prefix;
-
-    if (is_array($db_prefix)) {
-      if (array_key_exists('default', $db_prefix)) {
-        $tmp = $db_prefix;
-        unset($tmp['default']);
-        foreach ($tmp as $key => $val) {
-          $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
-        }
-        return strtr($sql, array('{' => $db_prefix['default'] , '}' => ''));
-      }
-      else {
-        foreach ($db_prefix as $key => $val) {
-          $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
-        }
-        return strtr($sql, array('{' => '' , '}' => ''));
-      }
-    }
-    else {
-      return strtr($sql, array('{' => $db_prefix , '}' => ''));
+    // Replace specific table prefixes first.
+    foreach ($this->prefixes as $key => $val) {
+      $sql = strtr($sql, array('{' . $key . '}' => $val . $key));
     }
+    // Then replace remaining tables with the default prefix.
+    return strtr($sql, array('{' => $this->defaultPrefix , '}' => ''));
   }
 
   /**
@@ -1240,6 +1253,20 @@ abstract class Database {
         if (empty($value['driver'])) {
           $databaseInfo[$index][$target] = $databaseInfo[$index][$target][mt_rand(0, count($databaseInfo[$index][$target]) - 1)];
         }
+
+        // Parse the prefix information.
+        if (!isset($databaseInfo[$index][$target]['prefix'])) {
+          // Default to an empty prefix.
+          $databaseInfo[$index][$target]['prefix'] = array(
+            'default' => '',
+          );
+        }
+        else if (!is_array($databaseInfo[$index][$target]['prefix'])) {
+          // Transform the flat form into an array form.
+          $databaseInfo[$index][$target]['prefix'] = array(
+            'default' => $databaseInfo[$index][$target]['prefix'],
+          );
+        }
       }
     }
 
@@ -1286,7 +1313,40 @@ abstract class Database {
     if (!empty(self::$databaseInfo[$key])) {
       return self::$databaseInfo[$key];
     }
+  }
+
+  /**
+   * Rename a connection and its corresponding connection information.
+   *
+   * @param $old_key
+   *   The old connection key.
+   * @param $new_key
+   *   The new connection key.
+   */
+  final public static function renameConnection($old_key, $new_key) {
+    if (empty(self::$databaseInfo)) {
+      self::parseConnectionInfo();
+    }
 
+    if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
+      self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
+      unset(self::$databaseInfo[$old_key]);
+      if (isset(self::$connections[$old_key])) {
+        self::$connections[$new_key] = self::$connections[$old_key];
+        unset(self::$connections[$old_key]);
+      }
+    }
+  }
+
+  /**
+   * Remove a connection and its corresponding connection information.
+   *
+   * @param $key
+   *   The connection key.
+   */
+  final public static function removeConnection($key) {
+    unset(self::$databaseInfo[$key]);
+    unset(self::$connections[$key]);
   }
 
   /**
@@ -1299,7 +1359,6 @@ abstract class Database {
    *   The database target to open.
    */
   final protected static function openConnection($key, $target) {
-    global $db_prefix;
 
     if (empty(self::$databaseInfo)) {
       self::parseConnectionInfo();
@@ -1326,12 +1385,6 @@ abstract class Database {
       if (!empty(self::$logs[$key])) {
         $new_connection->setLogger(self::$logs[$key]);
       }
-
-      // We need to pass around the simpletest database prefix in the request
-      // and we put that in the user_agent header.
-      if (preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT'])) {
-        $db_prefix .= $_SERVER['HTTP_USER_AGENT'];
-      }
       return $new_connection;
     }
     catch (Exception $e) {
diff --git includes/database/mysql/database.inc includes/database/mysql/database.inc
index 47573a2..43755b7 100644
--- includes/database/mysql/database.inc
+++ includes/database/mysql/database.inc
@@ -25,6 +25,8 @@ class DatabaseConnection_mysql extends DatabaseConnection {
       $connection_options['port'] = 3306;
     }
 
+    $this->setPrefix($connection_options['prefix'] ? $connection_options['prefix'] : '');
+
     $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . $connection_options['port'] . ';dbname=' . $connection_options['database'];
     parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
       // So we don't have to mess around with cursors and unbuffered queries by default.
diff --git includes/database/pgsql/database.inc includes/database/pgsql/database.inc
index 292eb89..5e17314 100644
--- includes/database/pgsql/database.inc
+++ includes/database/pgsql/database.inc
@@ -26,6 +26,8 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
       $connection_options['port'] = 5432;
     }
 
+    $this->setPrefix($connection_options['prefix'] ? $connection_options['prefix'] : '');
+
     $dsn = 'pgsql:host=' . $connection_options['host'] . ' dbname=' . $connection_options['database'] . ' port=' . $connection_options['port'];
     parent::__construct($dsn, $connection_options['username'], $connection_options['password'], array(
       // Convert numeric values to strings when fetching.
diff --git includes/database/sqlite/database.inc includes/database/sqlite/database.inc
index 7b97951..474d7e5 100644
--- includes/database/sqlite/database.inc
+++ includes/database/sqlite/database.inc
@@ -25,6 +25,8 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
     // This driver defaults to transaction support, except if explicitly passed FALSE.
     $this->transactionSupport = !isset($connection_options['transactions']) || $connection_options['transactions'] !== FALSE;
 
+    $this->setPrefix($connection_options['prefix'] ? $connection_options['prefix'] : '');
+
     parent::__construct('sqlite:'. $connection_options['database'], '', '', array(
       // Force column names to lower case.
       PDO::ATTR_CASE => PDO::CASE_LOWER,
diff --git install.php install.php
index 6507703..1d5f587 100644
--- install.php
+++ install.php
@@ -177,7 +177,7 @@ function install_verify_drupal() {
  * Verify existing settings.php
  */
 function install_verify_settings() {
-  global $db_prefix, $databases;
+  global $databases;
 
   // Verify existing settings (if any).
   if (!empty($databases)) {
@@ -200,7 +200,7 @@ function install_verify_settings() {
  * Configure and rewrite settings.php.
  */
 function install_change_settings($profile = 'default', $install_locale = '') {
-  global $databases, $db_prefix;
+  global $databases;
 
   $conf_path = './' . conf_path(FALSE, TRUE);
   $settings_file = $conf_path . '/settings.php';
@@ -307,14 +307,14 @@ function install_settings_form(&$form_state, $profile, $install_locale, $setting
     );
 
     // Table prefix
-    $db_prefix = ($profile == 'default') ? 'drupal_' : $profile . '_';
-    $form['advanced_options']['db_prefix'] = array(
+    $prefix = ($profile == 'default') ? 'drupal_' : $profile . '_';
+    $form['advanced_options']['prefix'] = array(
       '#type' => 'textfield',
       '#title' => st('Table prefix'),
       '#default_value' => '',
       '#size' => 45,
       '#maxlength' => 45,
-      '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_name(), '%prefix' => $db_prefix)),
+      '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_name(), '%prefix' => $prefix)),
     );
 
     $form['save'] = array(
@@ -335,7 +335,6 @@ function install_settings_form(&$form_state, $profile, $install_locale, $setting
  * Form API validate for install_settings form.
  */
 function install_settings_form_validate($form, &$form_state) {
-  global $db_url;
   _install_settings_form_validate($form_state['values'], $form_state['values']['settings_file'], $form_state, $form);
 }
 
@@ -345,12 +344,12 @@ function install_settings_form_validate($form, &$form_state) {
 function _install_settings_form_validate($database, $settings_file, &$form_state, $form = NULL) {
   global $databases;
   // Verify the table prefix
-  if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['dprefix'])) {
-    form_set_error('db_prefix', st('The database table prefix you have entered, %db_prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%db_prefix' => $db_prefix)), 'error');
+  if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
+    form_set_error('prefix', st('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%prefix' => $prefix)), 'error');
   }
 
   if (!empty($database['port']) && !is_numeric($database['port'])) {
-    form_set_error('db_port', st('Database port must be a number.'));
+    form_set_error('port', st('Database port must be a number.'));
   }
 
   // Check database type
@@ -384,16 +383,12 @@ function _install_settings_form_validate($database, $settings_file, &$form_state
 function install_settings_form_submit($form, &$form_state) {
   global $profile, $install_locale;
 
-  $database = array_intersect_key($form_state['values']['_database'], array_flip(array('driver', 'database', 'username', 'password', 'host', 'port')));
+  $database = array_intersect_key($form_state['values']['_database'], array_flip(array('driver', 'database', 'username', 'password', 'host', 'port', 'prefix')));
   // Update global settings array and save
   $settings['databases'] = array(
     'value'    => array('default' => array('default' => $database)),
     'required' => TRUE,
   );
-  $settings['db_prefix'] = array(
-    'value'    => $form_state['values']['db_prefix'],
-    'required' => TRUE,
-  );
   drupal_rewrite_settings($settings);
 
   // Continue to install profile step
diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php
index d935e4e..8c8467c 100644
--- modules/simpletest/drupal_web_test_case.php
+++ modules/simpletest/drupal_web_test_case.php
@@ -78,11 +78,11 @@ class DrupalWebTestCase {
   protected $additionalCurlOptions = array();
 
   /**
-   * The original database prefix, before it was changed for testing purposes.
+   * The database prefix of this test run.
    *
    * @var string
    */
-  protected $originalPrefix = NULL;
+  protected $databasePrefix = NULL;
 
   /**
    * The original file directory, before it was changed for testing purposes.
@@ -150,8 +150,6 @@ class DrupalWebTestCase {
    *   is the caller function itself.
    */
   private function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
-    global $db_prefix;
-
     // Convert boolean status to string status.
     if (is_bool($status)) {
       $status = $status ? 'pass' : 'fail';
@@ -165,10 +163,6 @@ class DrupalWebTestCase {
       $caller = $this->getAssertionCall();
     }
 
-    // Switch to non-testing database to store results in.
-    $current_db_prefix = $db_prefix;
-    $db_prefix = $this->originalPrefix;
-
     // Creation assertion array that can be displayed while tests are running.
     $this->assertions[] = $assertion = array(
       'test_id' => $this->testId,
@@ -182,10 +176,10 @@ class DrupalWebTestCase {
     );
 
     // Store assertion for display after the test has completed.
-    db_insert('simpletest')->fields($assertion)->execute();
-
-    // Return to testing prefix.
-    $db_prefix = $current_db_prefix;
+    Database::getConnection('default', 'simpletest_original_default')
+      ->insert('simpletest')
+      ->fields($assertion)
+      ->execute();
     return $status == 'pass' ? TRUE : FALSE;
   }
 
@@ -812,14 +806,26 @@ class DrupalWebTestCase {
    *   List of modules to enable for the duration of the test.
    */
   protected function setUp() {
-    global $db_prefix, $user;
+    global $user;
+
+    // Generate a temporary prefixed database to ensure that tests have a clean starting point.
+    $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
+
+    // Clone the current connection and replace the current prefix.
+    $connection_info = Database::getConnectionInfo('default');
+    Database::renameConnection('default', 'simpletest_original_default');
+    foreach ($connection_info as $target => $value) {
+      $connection_info[$target]['prefix'] = array(
+        'default' => $value['prefix']['default'] . $this->databasePrefix,
+      );
+    }
+    Database::addConnectionInfo('default', 'default', $connection_info['default']);
 
     // Store necessary current values before switching to prefixed database.
-    $this->originalPrefix = $db_prefix;
     $clean_url_original = variable_get('clean_url', 0);
 
-    // Generate temporary prefixed database to ensure that tests have a clean starting point.
-    $db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
+    // Set the simpletest id for use in other parts of Drupal.
+    drupal_test_info(array('test_run_id' => $this->databasePrefix, 'in_child_site' => FALSE));
 
     include_once DRUPAL_ROOT . '/includes/install.inc';
     drupal_install_system();
@@ -860,7 +866,7 @@ class DrupalWebTestCase {
 
     // Use temporary files directory with the same prefix as database.
     $this->originalFileDirectory = file_directory_path();
-    variable_set('file_directory_path', file_directory_path() . '/' . $db_prefix);
+    variable_set('file_directory_path', file_directory_path() . '/' . $this->databasePrefix);
     $directory = file_directory_path();
     file_check_directory($directory, FILE_CREATE_DIRECTORY); // Create the files directory.
     set_time_limit($this->timeLimit);
@@ -872,8 +878,10 @@ class DrupalWebTestCase {
    * setup a clean environment for the current test run.
    */
   protected function preloadRegistry() {
-    db_query('INSERT INTO {registry} SELECT * FROM ' . $this->originalPrefix . 'registry');
-    db_query('INSERT INTO {registry_file} SELECT * FROM ' . $this->originalPrefix . 'registry_file');
+    $original_connection = Database::getConnection('default', 'simpletest_original_default');
+    $this->pass('INSERT INTO {registry} SELECT * FROM ' . $original_connection->prefixTables('{registry}'));
+    db_query('INSERT INTO {registry} SELECT * FROM ' . $original_connection->prefixTables('{registry}'));
+    db_query('INSERT INTO {registry_file} SELECT * FROM ' . $original_connection->prefixTables('{registry_file}'));
   }
 
   /**
@@ -899,44 +907,34 @@ class DrupalWebTestCase {
    * and reset the database prefix.
    */
   protected function tearDown() {
-    global $db_prefix, $user;
-    if (preg_match('/simpletest\d+/', $db_prefix)) {
-      // Delete temporary files directory and reset files directory path.
-      file_unmanaged_delete_recursive(file_directory_path());
-      variable_set('file_directory_path', $this->originalFileDirectory);
-
-      // Remove all prefixed tables (all the tables in the schema).
-      $schema = drupal_get_schema(NULL, TRUE);
-      $ret = array();
-      foreach ($schema as $name => $table) {
-        db_drop_table($ret, $name);
-      }
+    // Get back to the original connection.
+    Database::removeConnection('default');
+    Database::renameConnection('simpletest_original_default', 'default');
 
-      // Return the database prefix to the original.
-      $db_prefix = $this->originalPrefix;
+    // Return the user to the original one.
+    $user = $this->originalUser;
+    drupal_save_session(TRUE);
 
-      // Return the user to the original one.
-      $user = $this->originalUser;
-      drupal_save_session(TRUE);
+    // Ensure that internal logged in variable and cURL options are reset.
+    $this->isLoggedIn = FALSE;
+    $this->additionalCurlOptions = array();
 
-      // Ensure that internal logged in variable and cURL options are reset.
-      $this->isLoggedIn = FALSE;
-      $this->additionalCurlOptions = array();
+    // Reload module list and implementations to ensure that test module hooks
+    // aren't called after tests.
+    module_list(TRUE);
+    module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE);
 
-      // Reload module list and implementations to ensure that test module hooks
-      // aren't called after tests.
-      module_list(TRUE);
-      module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE);
+    // Reset the Field API.
+    field_cache_clear();
 
-      // Reset the Field API.
-      field_cache_clear();
+    // Ensure that the internal logged in variable is reset.
+    $this->_logged_in = FALSE;
 
-      // Rebuild caches.
-      $this->refreshVariables();
+    // Rebuild caches.
+    $this->refreshVariables();
 
-      // Close the CURL handler.
-      $this->curlClose();
-    }
+    // Close the CURL handler.
+    $this->curlClose();
   }
 
   /**
@@ -947,7 +945,7 @@ class DrupalWebTestCase {
    * see the description of $curl_options among the properties.
    */
   protected function curlInitialize() {
-    global $base_url, $db_prefix;
+    global $base_url;
     if (!isset($this->curlHandle)) {
       $this->curlHandle = curl_init();
       $curl_options = $this->additionalCurlOptions + array(
@@ -958,10 +956,8 @@ class DrupalWebTestCase {
         CURLOPT_SSL_VERIFYPEER => FALSE,  // Required to make the tests run on https://
         CURLOPT_SSL_VERIFYHOST => FALSE,  // Required to make the tests run on https://
         CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'),
+        CURLOPT_USERAGENT => $this->databasePrefix,
       );
-      if (preg_match('/simpletest\d+/', $db_prefix, $matches)) {
-        $curl_options[CURLOPT_USERAGENT] = $matches[0];
-      }
       if (!isset($curl_options[CURLOPT_USERPWD]) && ($auth = variable_get('simpletest_httpauth_username', ''))) {
         if ($pass = variable_get('simpletest_httpauth_pass', '')) {
           $auth .= ':' . $pass;
diff --git sites/default/default.settings.php sites/default/default.settings.php
index f8c7ffa..5aa4411 100644
--- sites/default/default.settings.php
+++ sites/default/default.settings.php
@@ -105,30 +105,31 @@
  *   'username' => 'username',
  *   'password' => 'password',
  *   'host' => 'localhost',
+ *   'prefix' => '',
  * );
  *
  * You can optionally set prefixes for some or all database table names
- * by using the $db_prefix setting. If a prefix is specified, the table
+ * by using the 'prefix' setting. If a prefix is specified, the table
  * name will be prepended with its value. Be sure to use valid database
  * characters only, usually alphanumeric and underscore. If no prefixes
  * are desired, leave it as an empty string ''.
  *
- * To have all database names prefixed, set $db_prefix as a string:
+ * To have all database names prefixed, set 'prefix' as a string:
  *
- *   $db_prefix = 'main_';
+ *   'prefix' => 'main_',
  *
- * To provide prefixes for specific tables, set $db_prefix as an array.
+ * To provide prefixes for specific tables, set 'prefix' as an array.
  * The array's keys are the table names and the values are the prefixes.
- * The 'default' element holds the prefix for any tables not specified
- * elsewhere in the array. Example:
+ * The 'default' element is mandatory and holds the prefix for any tables
+ * not specified elsewhere in the array. Example:
  *
- *   $db_prefix = array(
+ *   'prefix' = array(
  *     'default'   => 'main_',
  *     'users'     => 'shared_',
  *     'sessions'  => 'shared_',
  *     'role'      => 'shared_',
  *     'authmap'   => 'shared_',
- *   );
+ *   ),
  *
  * Database configuration format:
  *   $databases['default']['default'] = array(
@@ -151,7 +152,6 @@
  *   );
  */
 $databases = array();
-$db_prefix = '';
 
 /**
  * Access control for update.php script
