summaryrefslogtreecommitdiff
path: root/includes/database
diff options
context:
space:
mode:
Diffstat (limited to 'includes/database')
-rw-r--r--includes/database/database.inc51
-rw-r--r--includes/database/mysql/database.inc52
-rw-r--r--includes/database/select.inc2
-rw-r--r--includes/database/sqlite/database.inc14
4 files changed, 92 insertions, 27 deletions
diff --git a/includes/database/database.inc b/includes/database/database.inc
index 4cc1a33d7..e08f9074f 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -273,20 +273,25 @@ abstract class DatabaseConnection extends PDO {
protected $schema = NULL;
/**
- * The default prefix used by this database connection.
+ * The prefixes used by this database connection.
*
- * Separated from the other prefixes for performance reasons.
+ * @var array
+ */
+ protected $prefixes = array();
+
+ /**
+ * List of search values for use in prefixTables().
*
- * @var string
+ * @var array
*/
- protected $defaultPrefix = '';
+ protected $prefixSearch = array();
/**
- * The non-default prefixes used by this database connection.
+ * List of replacement values for use in prefixTables().
*
* @var array
*/
- protected $prefixes = array();
+ protected $prefixReplace = array();
function __construct($dsn, $username, $password, $driver_options = array()) {
// Initialize and prepare the connection prefix.
@@ -375,7 +380,7 @@ abstract class DatabaseConnection extends PDO {
}
/**
- * Preprocess the prefixes used by this database connection.
+ * Set the list of prefixes used by this database connection.
*
* @param $prefix
* The prefixes, in any of the multiple forms documented in
@@ -383,14 +388,27 @@ abstract class DatabaseConnection extends PDO {
*/
protected function setPrefix($prefix) {
if (is_array($prefix)) {
- $this->defaultPrefix = isset($prefix['default']) ? $prefix['default'] : '';
- unset($prefix['default']);
- $this->prefixes = $prefix;
+ $this->prefixes = $prefix + array('default' => '');
}
else {
- $this->defaultPrefix = $prefix;
- $this->prefixes = array();
+ $this->prefixes = array('default' => $prefix);
}
+
+ // Set up variables for use in prefixTables(). Replace table-specific
+ // prefixes first.
+ $this->prefixSearch = array();
+ $this->prefixReplace = array();
+ foreach ($this->prefixes as $key => $val) {
+ if ($key != 'default') {
+ $this->prefixSearch[] = '{' . $key . '}';
+ $this->prefixReplace[] = $val . $key;
+ }
+ }
+ // Then replace remaining tables with the default prefix.
+ $this->prefixSearch[] = '{';
+ $this->prefixReplace[] = $this->prefixes['default'];
+ $this->prefixSearch[] = '}';
+ $this->prefixReplace[] = '';
}
/**
@@ -408,12 +426,7 @@ abstract class DatabaseConnection extends PDO {
* The properly-prefixed string.
*/
public function prefixTables($sql) {
- // 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 , '}' => ''));
+ return str_replace($this->prefixSearch, $this->prefixReplace, $sql);
}
/**
@@ -427,7 +440,7 @@ abstract class DatabaseConnection extends PDO {
return $this->prefixes[$table];
}
else {
- return $this->defaultPrefix;
+ return $this->prefixes['default'];
}
}
diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc
index 262cc6051..bc31feaaf 100644
--- a/includes/database/mysql/database.inc
+++ b/includes/database/mysql/database.inc
@@ -133,6 +133,58 @@ class DatabaseConnection_mysql extends DatabaseConnection {
catch (PDOException $e) {
}
}
+
+ /**
+ * Overridden to work around issues to MySQL not supporting transactional DDL.
+ */
+ public function popTransaction($name) {
+ if (!$this->supportsTransactions()) {
+ return;
+ }
+ if (!$this->inTransaction()) {
+ throw new DatabaseTransactionNoActiveException();
+ }
+
+ // Commit everything since SAVEPOINT $name.
+ while ($savepoint = array_pop($this->transactionLayers)) {
+ if ($savepoint != $name) {
+ continue;
+ }
+
+ // If there are no more layers left then we should commit.
+ if (empty($this->transactionLayers)) {
+ if (!PDO::commit()) {
+ throw new DatabaseTransactionCommitFailedException();
+ }
+ }
+ else {
+ // Attempt to release this savepoint in the standard way.
+ try {
+ $this->query('RELEASE SAVEPOINT ' . $name);
+ }
+ catch (PDOException $e) {
+ // However, in MySQL (InnoDB), savepoints are automatically committed
+ // when tables are altered or created (DDL transactions are not
+ // supported). This can cause exceptions due to trying to release
+ // savepoints which no longer exist.
+ //
+ // To avoid exceptions when no actual error has occurred, we silently
+ // succeed for PDOExceptions with SQLSTATE 42000 ("Syntax error or
+ // access rule violation") and MySQL error code 1305 ("SAVEPOINT does
+ // not exist").
+ if ($e->getCode() == '42000' && $e->errorInfo[1] == '1305') {
+ // If one SAVEPOINT was released automatically, then all were.
+ // Therefore, we keep just the topmost transaction.
+ $this->transactionLayers = array('drupal_transaction');
+ }
+ else {
+ throw $e;
+ }
+ }
+ break;
+ }
+ }
+ }
}
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 716c2fc3d..53be20adc 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -414,7 +414,7 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
* @param $start
* The first record from the result set to return. If NULL, removes any
* range directives that are set.
- * @param $limit
+ * @param $length
* The number of records to return from the result set.
* @return SelectQueryInterface
* The called object.
diff --git a/includes/database/sqlite/database.inc b/includes/database/sqlite/database.inc
index cf3b9551f..0fc0b5528 100644
--- a/includes/database/sqlite/database.inc
+++ b/includes/database/sqlite/database.inc
@@ -71,12 +71,8 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
));
// Attach one database for each registered prefix.
- $prefixes = &$this->prefixes;
- if (!empty($this->defaultPrefix)) {
- // Add in the default prefix, which is also attached.
- $prefixes[] = &$this->defaultPrefix;
- }
- foreach ($this->prefixes as $table => &$prefix) {
+ $prefixes = $this->prefixes;
+ foreach ($prefixes as $table => &$prefix) {
// Empty prefix means query the main database -- no need to attach anything.
if (!empty($prefix)) {
// Only attach the database once.
@@ -90,6 +86,8 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
$prefix .= '.';
}
}
+ // Regenerate the prefixes replacement table.
+ $this->setPrefix($prefixes);
// Detect support for SAVEPOINT.
$version = $this->query('SELECT sqlite_version()')->fetchField();
@@ -240,7 +238,9 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
// Generate a new temporary table name and protect it from prefixing.
// SQLite requires that temporary tables to be non-qualified.
$tablename = $this->generateTemporaryTableName();
- $this->prefixes[$tablename] = '';
+ $prefixes = $this->prefixes;
+ $prefixes[$tablename] = '';
+ $this->setPrefix($prefixes);
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', $query), $args, $options);
return $tablename;