From 33d4ce4bde8f25634587666354cf14e0b60bf116 Mon Sep 17 00:00:00 2001 From: webchick Date: Sun, 29 May 2011 21:51:22 -0700 Subject: Issue #1007830 by drunken monkey, Damien Tournoud, bfroehle: Fixed Nested transactions throw exceptions on ddl changes. --- includes/database/mysql/database.inc | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'includes/database/mysql') diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index 262cc6051..47ef8d52e 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -133,6 +133,55 @@ 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 error code 42000 ("Syntax error or + // access rule violation"). + if ($e->getCode() != '42000') { + throw $e; + } + // If one SAVEPOINT was released automatically, then all were. + // Therefore, we keep just the topmost transaction. + $this->transactionLayers = array('drupal_transaction'); + } + break; + } + } + } } -- cgit v1.2.3