@@ -69,7 +69,17 @@ export interface SqlExecutor {
6969 executeBatch : ( query : string , params ?: any [ ] [ ] ) => Promise < QueryResult > ;
7070}
7171
72- export interface LockContext extends SqlExecutor , DBGetUtils { }
72+ export interface LockContext extends SqlExecutor , DBGetUtils {
73+ /**
74+ * How the connection has been opened.
75+ *
76+ * `writer` indicates that the lock context is capable of writing to the database.
77+ * `queryOnly` indicates that the lock context has been opened in a readwrite mode, but a `PRAGMA query_only = TRUE`
78+ * disabled writes.
79+ * `readOnly` indicates that the lock context has been opened by passing `SQLITE_OPEN_READONLY` to `sqlite3_open_v2`.
80+ */
81+ connectionType ?: 'writer' | 'queryOnly' | 'readOnly' ;
82+ }
7383
7484/**
7585 * Implements {@link DBGetUtils} on a {@link SqlRunner}.
@@ -263,8 +273,16 @@ class TransactionImplementation extends DBGetUtilsDefaultMixin(BaseTransaction)
263273 static async runWith < T > ( ctx : LockContext , fn : ( tx : Transaction ) => Promise < T > ) : Promise < T > {
264274 let tx = new TransactionImplementation ( ctx ) ;
265275
276+ // For write transactions, use BEGIN IMMEDIATE to immediately obtain a write lock on the database (instead of doing
277+ // that on the first statement). If we have a genuine read-only connection, we also use BEGIN IMMEDIATE there: In
278+ // WAL mode, that ensures we pin the current state of the database (instead of the state at the first statement in
279+ // the transaction). But if we have a "fake" read-only connection implemented through `pragma query_only = true`, we
280+ // can't use this trick because it would attempt to lock the connection. So there, we use a regular `BEGIN`
281+ // statement.
282+ const useBeginImmediate = ctx . connectionType != 'queryOnly' ;
283+
266284 try {
267- await ctx . execute ( 'BEGIN IMMEDIATE' ) ;
285+ await ctx . execute ( useBeginImmediate ? 'BEGIN IMMEDIATE' : 'BEGIN ') ;
268286
269287 const result = await fn ( tx ) ;
270288 await tx . commit ( ) ;
0 commit comments