#357470 by Damien Tournoud: SQLite should use explicit ROLLBACK policy on insert and update queries.

From: Damien Tournoud <damien@tournoud.net>


---

 database/database.inc     |    8 +++++++-
 database/sqlite/query.inc |   12 ++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git includes/database/database.inc includes/database/database.inc
index 94aad52..4380e51 100644
--- includes/database/database.inc
+++ includes/database/database.inc
@@ -1426,7 +1426,13 @@ class DatabaseTransaction {
   }
 
   public function __destruct() {
-    $this->connection->popTransaction();
+    try {
+      $this->connection->popTransaction();
+    }
+    catch (PDOException $e) {
+      // Some database engines raise exceptions if the transaction was already
+      // rolled-back internally.
+    }
   }
 
 }
diff --git includes/database/sqlite/query.inc includes/database/sqlite/query.inc
index fb73d32..82d2366 100644
--- includes/database/sqlite/query.inc
+++ includes/database/sqlite/query.inc
@@ -23,14 +23,14 @@ class InsertQuery_sqlite extends InsertQuery {
       return parent::execute();
     }
     else {
-      return $this->connection->query('INSERT INTO {'. $this->table .'} DEFAULT VALUES', array(), $this->queryOptions);
+      return $this->connection->query('INSERT OR ROLLBACK INTO {'. $this->table .'} DEFAULT VALUES', array(), $this->queryOptions);
     }
   }
 
   public function __toString() {
     // Produce as many generic placeholders as necessary.
     $placeholders = array_fill(0, count($this->insertFields), '?');
-    return 'INSERT INTO {'. $this->table .'} ('. implode(', ', $this->insertFields) .') VALUES ('. implode(', ', $placeholders) .')';
+    return 'INSERT OR ROLLBACK INTO {'. $this->table .'} ('. implode(', ', $this->insertFields) .') VALUES ('. implode(', ', $placeholders) .')';
   }
 
 }
@@ -101,6 +101,14 @@ class UpdateQuery_sqlite extends UpdateQuery {
     return parent::execute();
   }
 
+  public function __toString() {
+    // SQLite need an explicit "OR ROLLBACK" clause to comply to our transaction
+    // constraints. To minimize code duplication, we use a little string
+    // manipulation here.
+    $query = parent::__toString();
+    return "UPDATE OR ROLLBACK " . substr($query, 7);
+  }
+
 }
 
 /**
