         //
         // 1. A database is invoked from some queue like the main queue:
         //
-        //      dbQueue.inDatabase { db in       // <-- we're here
+        //      serializedDatabase.reentrantSync { db in       // <-- we're here
         //      }
         //
         // 2. A database is invoked in a reentrant way:
         //
-        //      dbQueue.inDatabase { db in
-        //          dbQueue.inDatabase { db in   // <-- we're here
+        //      serializedDatabase.reentrantSync { db in
+        //          serializedDatabase.reentrantSync { db in   // <-- we're here
         //          }
         //      }
         //
         // 3. A database in invoked from another database:
         //
-        //      dbQueue1.inDatabase { db1 in
-        //          dbQueue2.inDatabase { db2 in // <-- we're here
+        //      serializedDatabase1.reentrantSync { db1 in
+        //          serializedDatabase2.reentrantSync { db2 in // <-- we're here
         //          }
         //      }
         
         guard let watchdog = SchedulingWatchdog.current else {
             // Case 1
             return try queue.sync {
-                defer { preconditionNoTransactionLeft(db) }
-                return try block(db)
+                // Since we are reentrant, a transaction may already be opened.
+                // In this case, don't check for unsafe transaction at the end.
+                if db.isInsideTransaction {
+                    return try block(db)
+                } else {
+                    defer { preconditionNoUnsafeTransactionLeft(db) }
+                    return try block(db)
+                }
             }
         }
         
         // Case 2
         if watchdog.allows(db) {
-            defer { preconditionNoTransactionLeft(db) }
-            return try block(db)
+            // Since we are reentrant, a transaction may already be opened.
+            // In this case, don't check for unsafe transaction at the end.
+            if db.isInsideTransaction {
+                return try block(db)
+            } else {
+                defer { preconditionNoUnsafeTransactionLeft(db) }
+                return try block(db)
+            }
         }
         
         // Case 3
         return try queue.sync {
             try SchedulingWatchdog.current!.inheritingAllowedDatabases(from: watchdog) {
-                defer { preconditionNoTransactionLeft(db) }
-                return try block(db)
+                // Since we are reentrant, a transaction may already be opened.
+                // In this case, don't check for unsafe transaction at the end.
+                if db.isInsideTransaction {
+                    return try block(db)
+                } else {
+                    defer { preconditionNoUnsafeTransactionLeft(db) }
+                    return try block(db)
+                }
             }
         }
     }

    }
    
    /// Fatal error if a transaction has been left opened.
    func preconditionNoTransactionLeft(_ db: Database, _ message: @autoclosure() -> String = "A transaction has been left opened at the end of a database access", file: StaticString = #file, line: UInt = #line) {
        GRDBPrecondition(configuration.allowsUnsafeTransactions || !db.isInsideTransaction, message, file: file, line: line)
    }
}

    func async(_ block: @escaping (Database) -> Void) {
        queue.async {
            block(self.db)
            self.preconditionNoUnsafeTransactionLeft(self.db)
        }
    }
    
