diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
index 30e9e01..a5ca652 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
@@ -35,6 +35,13 @@ class Connection extends DatabaseConnection {
   const DATABASE_NOT_FOUND = 7;
 
   /**
+   * Last used cursor number.
+   *
+   * @var type int
+   */
+  private $_cursor_ctr;
+
+  /**
    * Constructs a connection object.
    */
   public function __construct(PDO $connection, array $connection_options) {
@@ -56,6 +63,8 @@ public function __construct(PDO $connection, array $connection_options) {
     if (isset($connection_options['init_commands'])) {
       $this->connection->exec(implode('; ', $connection_options['init_commands']));
     }
+
+    $this->_cursor_ctr = 0;
   }
 
   /**
@@ -132,6 +141,10 @@ public function query($query, array $args = array(), $options = array()) {
         $stmt->execute($args, $options);
       }
 
+      if (strpos($stmt->queryString,'SAVEPOINT mimic_innodb_not_released;') !== FALSE) {
+        $this->connection->prepare("RELEASE SAVEPOINT mimic_innodb_not_released")->execute();
+      }
+
       switch ($options['return']) {
         case Database::RETURN_STATEMENT:
           return $stmt;
@@ -146,6 +159,11 @@ public function query($query, array $args = array(), $options = array()) {
       }
     }
     catch (PDOException $e) {
+
+      if (preg_match("/SAVEPOINT (mimic_innodb_(released|not_released))/",$stmt->queryString,$matches)) {
+        $this->connection->prepare("ROLLBACK TO SAVEPOINT " . $matches[1])->execute();
+      }
+
       if ($options['throw_exception']) {
         // Match all SQLSTATE 23xxx errors.
         if (substr($e->getCode(), -6, -3) == '23') {
@@ -173,7 +191,27 @@ public function prepareQuery($query) {
     // @todo This workaround only affects bytea fields, but the involved field
     //   types involved in the query are unknown, so there is no way to
     //   conditionally execute this for affected queries only.
-    return parent::prepareQuery(preg_replace('/ ([^ ]+) +(I*LIKE|NOT +I*LIKE) /i', ' ${1}::text ${2} ', $query));
+    $query = preg_replace('/ ([^ ]+) +(I*LIKE|NOT +I*LIKE) /i', ' ${1}::text ${2} ', $query);
+
+    // While in transaction context, put a SAVEPOINT around every query that isn't
+    // itself a SAVEPOINT operation.  This means that a failed query can't cause
+    // the transaction to abort, which mimics the behavior of innodb.
+    if ($this->inTransaction() &&
+            (stripos($query,'SAVEPOINT ') === FALSE) &&
+            (stripos($query,'RELEASE ') === FALSE)) {
+        if (preg_match('/^[\s]*SELECT /i', $query)) {
+          // In the case of SELECT the SAVEPOINT can also be released in the same
+          // query.  Otherwise the RELEASE is a separate query.
+          $csr = 'csr' . $this->_cursor_ctr++;
+          $query = 'SAVEPOINT mimic_innodb_released; DECLARE '. $csr .' CURSOR FOR ' .
+                  $query . '; RELEASE SAVEPOINT mimic_innodb_released; FETCH ALL ' . $csr;
+        }
+        else {
+          $query = 'SAVEPOINT mimic_innodb_not_released; ' . $query;
+        }
+    }
+
+    return parent::prepareQuery($query);
   }
 
   public function queryRange($query, $from, $count, array $args = array(), array $options = array()) {
