summaryrefslogtreecommitdiff
path: root/includes/database
diff options
context:
space:
mode:
authorDavid Rothstein <drothstein@gmail.com>2013-12-30 17:23:37 -0500
committerDavid Rothstein <drothstein@gmail.com>2013-12-30 17:23:37 -0500
commit70e0b16715cb81f2a0450335eaf9fba349f44012 (patch)
tree77222cb82bb3a260c1964b61229c59f599fd43e1 /includes/database
parentddba1d97c70a8df07d17be4c83cab459715d8339 (diff)
downloadbrdo-70e0b16715cb81f2a0450335eaf9fba349f44012.tar.gz
brdo-70e0b16715cb81f2a0450335eaf9fba349f44012.tar.bz2
Issue #937284 by chx, chrisdolby, deviantintegral, Berdir, tim.plunkett | hefox: DEADLOCK errors on MergeQuery INSERT due to InnoDB gap locking when condition in SELECT ... FOR UPDATE results in 0 rows.
Diffstat (limited to 'includes/database')
-rw-r--r--includes/database/query.inc76
1 files changed, 32 insertions, 44 deletions
diff --git a/includes/database/query.inc b/includes/database/query.inc
index ce242beb7..8af91c2d7 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -1606,55 +1606,43 @@ class MergeQuery extends Query implements QueryConditionInterface {
}
public function execute() {
- // Wrap multiple queries in a transaction, if the database supports it.
- $transaction = $this->connection->startTransaction();
- try {
- if (!count($this->condition)) {
- throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
- }
- $select = $this->connection->select($this->conditionTable)
- ->condition($this->condition)
- ->forUpdate();
- $select->addExpression('1');
- if (!$select->execute()->fetchField()) {
- try {
- $insert = $this->connection->insert($this->table)->fields($this->insertFields);
- if ($this->defaultFields) {
- $insert->useDefaults($this->defaultFields);
- }
- $insert->execute();
- return MergeQuery::STATUS_INSERT;
- }
- catch (Exception $e) {
- // The insert query failed, maybe it's because a racing insert query
- // beat us in inserting the same row. Retry the select query, if it
- // returns a row, ignore the error and continue with the update
- // query below.
- if (!$select->execute()->fetchField()) {
- throw $e;
- }
+ if (!count($this->condition)) {
+ throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
+ }
+ $select = $this->connection->select($this->conditionTable)
+ ->condition($this->condition);
+ $select->addExpression('1');
+ if (!$select->execute()->fetchField()) {
+ try {
+ $insert = $this->connection->insert($this->table)->fields($this->insertFields);
+ if ($this->defaultFields) {
+ $insert->useDefaults($this->defaultFields);
}
+ $insert->execute();
+ return self::STATUS_INSERT;
}
- if ($this->needsUpdate) {
- $update = $this->connection->update($this->table)
- ->fields($this->updateFields)
- ->condition($this->condition);
- if ($this->expressionFields) {
- foreach ($this->expressionFields as $field => $data) {
- $update->expression($field, $data['expression'], $data['arguments']);
- }
+ catch (Exception $e) {
+ // The insert query failed, maybe it's because a racing insert query
+ // beat us in inserting the same row. Retry the select query, if it
+ // returns a row, ignore the error and continue with the update
+ // query below.
+ if (!$select->execute()->fetchField()) {
+ throw $e;
}
- $update->execute();
- return MergeQuery::STATUS_UPDATE;
}
}
- catch (Exception $e) {
- // Something really wrong happened here, bubble up the exception to the
- // caller.
- $transaction->rollback();
- throw $e;
- }
- // Transaction commits here where $transaction looses scope.
+ if ($this->needsUpdate) {
+ $update = $this->connection->update($this->table)
+ ->fields($this->updateFields)
+ ->condition($this->condition);
+ if ($this->expressionFields) {
+ foreach ($this->expressionFields as $field => $data) {
+ $update->expression($field, $data['expression'], $data['arguments']);
+ }
+ }
+ $update->execute();
+ return self::STATUS_UPDATE;
+ }
}
}