diff options
author | David Rothstein <drothstein@gmail.com> | 2013-12-30 17:23:37 -0500 |
---|---|---|
committer | David Rothstein <drothstein@gmail.com> | 2013-12-30 17:23:37 -0500 |
commit | 70e0b16715cb81f2a0450335eaf9fba349f44012 (patch) | |
tree | 77222cb82bb3a260c1964b61229c59f599fd43e1 /includes/database | |
parent | ddba1d97c70a8df07d17be4c83cab459715d8339 (diff) | |
download | brdo-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.inc | 76 |
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; + } } } |