expo-sqlite 57.0.3 → 57.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/sqlite/NativeDatabaseBinding.kt +1 -0
  4. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +47 -23
  5. package/build/SQLiteStatement.d.ts +10 -0
  6. package/build/SQLiteStatement.d.ts.map +1 -1
  7. package/build/SQLiteStatement.js +58 -16
  8. package/build/SQLiteStatement.js.map +1 -1
  9. package/expo-module.config.json +1 -1
  10. package/ios/SQLiteModule.swift +37 -1
  11. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5-sources.jar +0 -0
  12. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5-sources.jar.md5 +1 -0
  13. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5-sources.jar.sha1 +1 -0
  14. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5-sources.jar.sha256 +1 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5-sources.jar.sha512 +1 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.aar +0 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.aar.md5 +1 -0
  18. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.aar.sha1 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.aar.sha256 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.aar.sha512 +1 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/{57.0.3/expo.modules.sqlite-57.0.3.module → 57.0.5/expo.modules.sqlite-57.0.5.module} +22 -22
  22. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.module.md5 +1 -0
  23. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.module.sha1 +1 -0
  24. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.module.sha256 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.module.sha512 +1 -0
  26. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/{57.0.3/expo.modules.sqlite-57.0.3.pom → 57.0.5/expo.modules.sqlite-57.0.5.pom} +1 -1
  27. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.pom.md5 +1 -0
  28. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.pom.sha1 +1 -0
  29. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.pom.sha256 +1 -0
  30. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.5/expo.modules.sqlite-57.0.5.pom.sha512 +1 -0
  31. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml +4 -4
  32. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.md5 +1 -1
  33. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha1 +1 -1
  34. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha256 +1 -1
  35. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha512 +1 -1
  36. package/package.json +3 -3
  37. package/src/SQLiteStatement.ts +70 -16
  38. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3-sources.jar +0 -0
  39. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3-sources.jar.md5 +0 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3-sources.jar.sha1 +0 -1
  41. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3-sources.jar.sha256 +0 -1
  42. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3-sources.jar.sha512 +0 -1
  43. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.aar +0 -0
  44. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.aar.md5 +0 -1
  45. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.aar.sha1 +0 -1
  46. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.aar.sha256 +0 -1
  47. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.aar.sha512 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.module.md5 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.module.sha1 +0 -1
  50. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.module.sha256 +0 -1
  51. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.module.sha512 +0 -1
  52. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.pom.md5 +0 -1
  53. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.pom.sha1 +0 -1
  54. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.pom.sha256 +0 -1
  55. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/57.0.3/expo.modules.sqlite-57.0.3.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,19 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 57.0.5 — 2026-11-12
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [iOS][Android] Fix every later transaction on a connection failing with `cannot commit transaction - SQL statements in progress` after a statement fails with `database is locked`, by resetting the statement when its run fails. ([#51413](https://github.com/expo/expo/pull/51413) by [@kudo](https://github.com/kudo))
18
+ - [iOS][Android] Fix `finalizeAsync()` and `finalizeSync()` not reporting the earlier error of a failed `run()`, by resetting the statement only when the run fails with `database is locked`. ([#53339](https://github.com/expo/expo/pull/53339) by [@kudo](https://github.com/kudo))
19
+
20
+ ## 57.0.4 — 2026-10-06
21
+
22
+ ### 🐛 Bug fixes
23
+
24
+ - Fixed reading a prepared statement result after the same statement ran again returning the later run's rows instead of throwing. Also guarded `step`, `getAll`, `reset` and `finalize` with the same per-statement lock that `run` takes. ([#49796](https://github.com/expo/expo/pull/49796) by [@tsapeta](https://github.com/tsapeta))
25
+
13
26
  ## 57.0.3 — 2026-09-11
14
27
 
15
28
  _This version does not introduce any user-facing changes._
@@ -47,13 +47,13 @@ def reactNativeArchitectures() {
47
47
  }
48
48
 
49
49
  group = 'host.exp.exponent'
50
- version = '57.0.3'
50
+ version = '57.0.5'
51
51
 
52
52
  android {
53
53
  namespace "expo.modules.sqlite"
54
54
  defaultConfig {
55
55
  versionCode 18
56
- versionName "57.0.3"
56
+ versionName "57.0.5"
57
57
  buildConfigField "boolean", "USE_LIBSQL", project.ext.USE_LIBSQL.toString()
58
58
  buildConfigField "boolean", "WITH_SQLITE_VEC", project.ext.WITH_SQLITE_VEC.toString()
59
59
 
@@ -93,6 +93,7 @@ internal class NativeDatabaseBinding : Closeable {
93
93
 
94
94
  // These error code should be synced with sqlite3.h
95
95
  const val SQLITE_OK = 0
96
+ const val SQLITE_BUSY = 5
96
97
 
97
98
  const val SQLITE_ROW = 100
98
99
  const val SQLITE_DONE = 101
@@ -417,7 +417,15 @@ class SQLiteModule : Module() {
417
417
 
418
418
  val ret = statement.ref.sqlite3_step()
419
419
  if (ret != NativeDatabaseBinding.SQLITE_ROW && ret != NativeDatabaseBinding.SQLITE_DONE) {
420
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
420
+ // A step that fails with SQLITE_BUSY leaves the statement running, so every later COMMIT
421
+ // on the connection fails until the statement is reset.
422
+ // Reset only for SQLITE_BUSY. A reset also clears other errors, which finalize() must still report.
423
+ // Read the message first. sqlite3_reset() replaces the error message.
424
+ val message = database.ref.convertSqlLiteErrorToString()
425
+ if ((ret and 0xff) == NativeDatabaseBinding.SQLITE_BUSY) {
426
+ statement.ref.sqlite3_reset()
427
+ }
428
+ throw SQLiteErrorException(message)
421
429
  }
422
430
  val firstRowValues: SQLiteColumnValues =
423
431
  if (ret == NativeDatabaseBinding.SQLITE_ROW) {
@@ -437,40 +445,52 @@ class SQLiteModule : Module() {
437
445
  private fun step(statement: NativeStatement, database: NativeDatabase): SQLiteColumnValues? {
438
446
  maybeThrowForClosedDatabase(database)
439
447
  maybeThrowForFinalizedStatement(statement)
440
- val ret = statement.ref.sqlite3_step()
441
- if (ret == NativeDatabaseBinding.SQLITE_ROW) {
442
- return statement.getTransformedColumnValues()
443
- }
444
- if (ret != NativeDatabaseBinding.SQLITE_DONE) {
445
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
448
+
449
+ // Guard the stateful statement, see `run` above.
450
+ synchronized(statement) {
451
+ val ret = statement.ref.sqlite3_step()
452
+ if (ret == NativeDatabaseBinding.SQLITE_ROW) {
453
+ return statement.getTransformedColumnValues()
454
+ }
455
+ if (ret != NativeDatabaseBinding.SQLITE_DONE) {
456
+ throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
457
+ }
458
+ return null
446
459
  }
447
- return null
448
460
  }
449
461
 
450
462
  @Throws(AccessClosedResourceException::class, InvalidConvertibleException::class, SQLiteErrorException::class)
451
463
  private fun getAll(statement: NativeStatement, database: NativeDatabase): List<SQLiteColumnValues> {
452
464
  maybeThrowForClosedDatabase(database)
453
465
  maybeThrowForFinalizedStatement(statement)
454
- val columnValuesList = mutableListOf<SQLiteColumnValues>()
455
- while (true) {
456
- val ret = statement.ref.sqlite3_step()
457
- if (ret == NativeDatabaseBinding.SQLITE_ROW) {
458
- columnValuesList.add(statement.getTransformedColumnValues())
459
- continue
460
- } else if (ret == NativeDatabaseBinding.SQLITE_DONE) {
461
- break
466
+
467
+ // Guard the stateful statement, see `run` above.
468
+ synchronized(statement) {
469
+ val columnValuesList = mutableListOf<SQLiteColumnValues>()
470
+ while (true) {
471
+ val ret = statement.ref.sqlite3_step()
472
+ if (ret == NativeDatabaseBinding.SQLITE_ROW) {
473
+ columnValuesList.add(statement.getTransformedColumnValues())
474
+ continue
475
+ } else if (ret == NativeDatabaseBinding.SQLITE_DONE) {
476
+ break
477
+ }
478
+ throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
462
479
  }
463
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
480
+ return columnValuesList
464
481
  }
465
- return columnValuesList
466
482
  }
467
483
 
468
484
  @Throws(AccessClosedResourceException::class, SQLiteErrorException::class)
469
485
  private fun reset(statement: NativeStatement, database: NativeDatabase) {
470
486
  maybeThrowForClosedDatabase(database)
471
487
  maybeThrowForFinalizedStatement(statement)
472
- if (statement.ref.sqlite3_reset() != NativeDatabaseBinding.SQLITE_OK) {
473
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
488
+
489
+ // Guard the stateful statement, see `run` above.
490
+ synchronized(statement) {
491
+ if (statement.ref.sqlite3_reset() != NativeDatabaseBinding.SQLITE_OK) {
492
+ throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
493
+ }
474
494
  }
475
495
  }
476
496
 
@@ -478,10 +498,14 @@ class SQLiteModule : Module() {
478
498
  private fun finalize(statement: NativeStatement, database: NativeDatabase) {
479
499
  maybeThrowForClosedDatabase(database)
480
500
  maybeThrowForFinalizedStatement(statement)
481
- if (statement.ref.sqlite3_finalize() != NativeDatabaseBinding.SQLITE_OK) {
482
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
501
+
502
+ // Guard the stateful statement, see `run` above.
503
+ synchronized(statement) {
504
+ if (statement.ref.sqlite3_finalize() != NativeDatabaseBinding.SQLITE_OK) {
505
+ throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
506
+ }
507
+ statement.isFinalized = true
483
508
  }
484
- statement.isFinalized = true
485
509
  }
486
510
 
487
511
  private fun addUpdateHook(database: NativeDatabase) {
@@ -8,7 +8,17 @@ type ValuesOf<T extends object> = T[keyof T][];
8
8
  export declare class SQLiteStatement {
9
9
  private readonly nativeDatabase;
10
10
  private readonly nativeStatement;
11
+ /**
12
+ * The cursor that currently owns the underlying `sqlite3_stmt`. A prepared statement has exactly
13
+ * one cursor, so running the statement again invalidates the cursor of every earlier run.
14
+ */
15
+ private currentCursor;
11
16
  constructor(nativeDatabase: NativeDatabase, nativeStatement: NativeStatement);
17
+ /**
18
+ * Make the run that just finished the owner of the statement cursor, and return a predicate
19
+ * that tells whether it still is.
20
+ */
21
+ private claimCursor;
12
22
  /**
13
23
  * Run the prepared statement and return the [`SQLiteExecuteAsyncResult`](#sqliteexecuteasyncresult) instance.
14
24
  * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`SQLiteBindValue`](#sqlitebindvalue) for more information about binding values.
@@ -1 +1 @@
1
- {"version":3,"file":"SQLiteStatement.d.ts","sourceRoot":"","sources":["../src/SQLiteStatement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SQLiteStatement.d.ts","sourceRoot":"","sources":["../src/SQLiteStatement.ts"],"names":[],"mappings":"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"}
@@ -5,17 +5,31 @@ import { composeRow, composeRows, normalizeParams } from './paramUtils';
5
5
  export class SQLiteStatement {
6
6
  nativeDatabase;
7
7
  nativeStatement;
8
+ /**
9
+ * The cursor that currently owns the underlying `sqlite3_stmt`. A prepared statement has exactly
10
+ * one cursor, so running the statement again invalidates the cursor of every earlier run.
11
+ */
12
+ currentCursor = null;
8
13
  constructor(nativeDatabase, nativeStatement) {
9
14
  this.nativeDatabase = nativeDatabase;
10
15
  this.nativeStatement = nativeStatement;
11
16
  }
17
+ /**
18
+ * Make the run that just finished the owner of the statement cursor, and return a predicate
19
+ * that tells whether it still is.
20
+ */
21
+ claimCursor() {
22
+ const cursor = {};
23
+ this.currentCursor = cursor;
24
+ return () => this.currentCursor === cursor;
25
+ }
12
26
  async executeAsync(...params) {
13
27
  const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(this.nativeDatabase, ...normalizeParams(...params));
14
28
  return createSQLiteExecuteAsyncResult(this.nativeDatabase, this.nativeStatement, firstRowValues, {
15
29
  rawResult: false,
16
30
  lastInsertRowId,
17
31
  changes,
18
- });
32
+ }, this.claimCursor());
19
33
  }
20
34
  async executeForRawResultAsync(...params) {
21
35
  const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(this.nativeDatabase, ...normalizeParams(...params));
@@ -23,7 +37,7 @@ export class SQLiteStatement {
23
37
  rawResult: true,
24
38
  lastInsertRowId,
25
39
  changes,
26
- });
40
+ }, this.claimCursor());
27
41
  }
28
42
  /**
29
43
  * Get the column names of the prepared statement.
@@ -48,7 +62,7 @@ export class SQLiteStatement {
48
62
  rawResult: false,
49
63
  lastInsertRowId,
50
64
  changes,
51
- });
65
+ }, this.claimCursor());
52
66
  }
53
67
  executeForRawResultSync(...params) {
54
68
  const { lastInsertRowId, changes, firstRowValues } = this.nativeStatement.runSync(this.nativeDatabase, ...normalizeParams(...params));
@@ -56,7 +70,7 @@ export class SQLiteStatement {
56
70
  rawResult: true,
57
71
  lastInsertRowId,
58
72
  changes,
59
- });
73
+ }, this.claimCursor());
60
74
  }
61
75
  /**
62
76
  * Get the column names of the prepared statement.
@@ -77,14 +91,18 @@ export class SQLiteStatement {
77
91
  this.nativeStatement.finalizeSync(this.nativeDatabase);
78
92
  }
79
93
  }
94
+ const SUPERSEDED_CURSOR_MESSAGE = 'This result is no longer readable because the prepared statement ran again. ' +
95
+ 'A prepared statement holds a single SQLite cursor, so a later run rebinds the parameters and moves that cursor, ' +
96
+ 'and this result would return the rows of the later run. ' +
97
+ 'Read a result to the end before you run the same statement again, or prepare a separate statement for each reader.';
80
98
  /**
81
99
  * Create the `SQLiteExecuteAsyncResult` instance.
82
100
  *
83
101
  * NOTE: Since Hermes does not support the `Symbol.asyncIterator` feature, we have to use an AsyncGenerator to implement the `AsyncIterableIterator` interface.
84
102
  * This is done by `Object.defineProperties` to add the properties to the AsyncGenerator.
85
103
  */
86
- async function createSQLiteExecuteAsyncResult(database, statement, firstRowValues, options) {
87
- const instance = new SQLiteExecuteAsyncResultImpl(database, statement, firstRowValues ? processNativeRow(firstRowValues) : null, options);
104
+ async function createSQLiteExecuteAsyncResult(database, statement, firstRowValues, options, isCursorOwner) {
105
+ const instance = new SQLiteExecuteAsyncResultImpl(database, statement, firstRowValues ? processNativeRow(firstRowValues) : null, options, isCursorOwner);
88
106
  const generator = instance.generatorAsync();
89
107
  Object.defineProperties(generator, {
90
108
  lastInsertRowId: {
@@ -118,8 +136,8 @@ async function createSQLiteExecuteAsyncResult(database, statement, firstRowValue
118
136
  /**
119
137
  * Create the `SQLiteExecuteSyncResult` instance.
120
138
  */
121
- function createSQLiteExecuteSyncResult(database, statement, firstRowValues, options) {
122
- const instance = new SQLiteExecuteSyncResultImpl(database, statement, firstRowValues ? processNativeRow(firstRowValues) : firstRowValues, options);
139
+ function createSQLiteExecuteSyncResult(database, statement, firstRowValues, options, isCursorOwner) {
140
+ const instance = new SQLiteExecuteSyncResultImpl(database, statement, firstRowValues ? processNativeRow(firstRowValues) : firstRowValues, options, isCursorOwner);
123
141
  const generator = instance.generatorSync();
124
142
  Object.defineProperties(generator, {
125
143
  lastInsertRowId: {
@@ -155,13 +173,21 @@ class SQLiteExecuteAsyncResultImpl {
155
173
  statement;
156
174
  firstRowValues;
157
175
  options;
176
+ isCursorOwner;
158
177
  columnNames = null;
159
178
  isStepCalled = false;
160
- constructor(database, statement, firstRowValues, options) {
179
+ constructor(database, statement, firstRowValues, options, isCursorOwner) {
161
180
  this.database = database;
162
181
  this.statement = statement;
163
182
  this.firstRowValues = firstRowValues;
164
183
  this.options = options;
184
+ this.isCursorOwner = isCursorOwner;
185
+ }
186
+ /** Throw rather than step a cursor that a later run of the same statement has taken over. */
187
+ assertCursorOwner() {
188
+ if (!this.isCursorOwner()) {
189
+ throw new Error(SUPERSEDED_CURSOR_MESSAGE);
190
+ }
165
191
  }
166
192
  async getFirstAsync() {
167
193
  if (this.isStepCalled) {
@@ -173,6 +199,7 @@ class SQLiteExecuteAsyncResultImpl {
173
199
  if (firstRowValues != null) {
174
200
  return composeRowIfNeeded(this.options.rawResult, columnNames, firstRowValues);
175
201
  }
202
+ this.assertCursorOwner();
176
203
  const firstRow = await this.statement.stepAsync(this.database);
177
204
  return firstRow != null
178
205
  ? composeRowIfNeeded(this.options.rawResult, columnNames, processNativeRow(firstRow))
@@ -189,9 +216,10 @@ class SQLiteExecuteAsyncResultImpl {
189
216
  return [];
190
217
  }
191
218
  const columnNames = await this.getColumnNamesAsync();
219
+ this.assertCursorOwner();
192
220
  const nativeRows = await this.statement.getAllAsync(this.database);
193
221
  const allRows = processNativeRows(nativeRows);
194
- if (firstRowValues != null && firstRowValues.length > 0) {
222
+ if (firstRowValues.length > 0) {
195
223
  return composeRowsIfNeeded(this.options.rawResult, columnNames, [
196
224
  firstRowValues,
197
225
  ...allRows,
@@ -208,16 +236,18 @@ class SQLiteExecuteAsyncResultImpl {
208
236
  }
209
237
  let result;
210
238
  do {
239
+ this.assertCursorOwner();
211
240
  result = await this.statement.stepAsync(this.database);
212
241
  if (result != null) {
213
242
  yield composeRowIfNeeded(this.options.rawResult, columnNames, processNativeRow(result));
214
243
  }
215
244
  } while (result != null);
216
245
  }
217
- resetAsync() {
218
- const result = this.statement.resetAsync(this.database);
246
+ async resetAsync() {
247
+ // Resetting a superseded result would rewind the cursor of the run that owns it now.
248
+ this.assertCursorOwner();
249
+ await this.statement.resetAsync(this.database);
219
250
  this.isStepCalled = false;
220
- return result;
221
251
  }
222
252
  popFirstRowValues() {
223
253
  if (this.firstRowValues != null) {
@@ -239,13 +269,21 @@ class SQLiteExecuteSyncResultImpl {
239
269
  statement;
240
270
  firstRowValues;
241
271
  options;
272
+ isCursorOwner;
242
273
  columnNames = null;
243
274
  isStepCalled = false;
244
- constructor(database, statement, firstRowValues, options) {
275
+ constructor(database, statement, firstRowValues, options, isCursorOwner) {
245
276
  this.database = database;
246
277
  this.statement = statement;
247
278
  this.firstRowValues = firstRowValues;
248
279
  this.options = options;
280
+ this.isCursorOwner = isCursorOwner;
281
+ }
282
+ /** Throw rather than step a cursor that a later run of the same statement has taken over. */
283
+ assertCursorOwner() {
284
+ if (!this.isCursorOwner()) {
285
+ throw new Error(SUPERSEDED_CURSOR_MESSAGE);
286
+ }
249
287
  }
250
288
  getFirstSync() {
251
289
  if (this.isStepCalled) {
@@ -256,6 +294,7 @@ class SQLiteExecuteSyncResultImpl {
256
294
  if (firstRowValues != null) {
257
295
  return composeRowIfNeeded(this.options.rawResult, columnNames, firstRowValues);
258
296
  }
297
+ this.assertCursorOwner();
259
298
  const firstRow = this.statement.stepSync(this.database);
260
299
  return firstRow != null
261
300
  ? composeRowIfNeeded(this.options.rawResult, columnNames, processNativeRow(firstRow))
@@ -271,6 +310,7 @@ class SQLiteExecuteSyncResultImpl {
271
310
  return [];
272
311
  }
273
312
  const columnNames = this.getColumnNamesSync();
313
+ this.assertCursorOwner();
274
314
  const nativeRows = this.statement.getAllSync(this.database);
275
315
  const allRows = processNativeRows(nativeRows);
276
316
  if (firstRowValues != null && firstRowValues.length > 0) {
@@ -289,6 +329,7 @@ class SQLiteExecuteSyncResultImpl {
289
329
  }
290
330
  let result;
291
331
  do {
332
+ this.assertCursorOwner();
292
333
  result = this.statement.stepSync(this.database);
293
334
  if (result != null) {
294
335
  yield composeRowIfNeeded(this.options.rawResult, columnNames, processNativeRow(result));
@@ -296,9 +337,10 @@ class SQLiteExecuteSyncResultImpl {
296
337
  } while (result != null);
297
338
  }
298
339
  resetSync() {
299
- const result = this.statement.resetSync(this.database);
340
+ // Resetting a superseded result would rewind the cursor of the run that owns it now.
341
+ this.assertCursorOwner();
342
+ this.statement.resetSync(this.database);
300
343
  this.isStepCalled = false;
301
- return result;
302
344
  }
303
345
  popFirstRowValues() {
304
346
  if (this.firstRowValues != null) {
@@ -1 +1 @@
1
- {"version":3,"file":"SQLiteStatement.js","sourceRoot":"","sources":["../src/SQLiteStatement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NativeDatabase } from './NativeDatabase';\nimport type {\n NativeStatement,\n SQLiteBindParams,\n SQLiteVariadicBindParams,\n SQLiteAnyDatabase,\n SQLiteColumnNames,\n SQLiteColumnValues,\n} from './NativeStatement';\nimport { composeRow, composeRows, normalizeParams } from './paramUtils';\n\nexport type {\n SQLiteBindParams,\n SQLiteBindValue,\n SQLiteRunResult,\n SQLiteVariadicBindParams,\n} from './NativeStatement';\n\ntype ValuesOf<T extends object> = T[keyof T][];\n\n/**\n * A prepared statement returned by [`SQLiteDatabase.prepareAsync()`](#prepareasyncsource) or [`SQLiteDatabase.prepareSync()`](#preparesyncsource) that can be binded with parameters and executed.\n */\nexport class SQLiteStatement {\n constructor(\n private readonly nativeDatabase: NativeDatabase,\n private readonly nativeStatement: NativeStatement\n ) {}\n\n //#region Asynchronous API\n\n /**\n * Run the prepared statement and return the [`SQLiteExecuteAsyncResult`](#sqliteexecuteasyncresult) instance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`SQLiteBindValue`](#sqlitebindvalue) for more information about binding values.\n */\n public executeAsync<T>(params: SQLiteBindParams): Promise<SQLiteExecuteAsyncResult<T>>;\n /**\n * @hidden\n */\n public executeAsync<T>(...params: SQLiteVariadicBindParams): Promise<SQLiteExecuteAsyncResult<T>>;\n public async executeAsync<T>(...params: unknown[]): Promise<SQLiteExecuteAsyncResult<T>> {\n const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteAsyncResult<T>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: false,\n lastInsertRowId,\n changes,\n }\n );\n }\n\n /**\n * Similar to [`executeAsync()`](#executeasyncparams) but returns the raw value array result instead of the row objects.\n * @hidden Advanced use only.\n */\n public executeForRawResultAsync<T extends object>(\n params: SQLiteBindParams\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>>;\n /**\n * @hidden\n */\n public executeForRawResultAsync<T extends object>(\n ...params: SQLiteVariadicBindParams\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>>;\n public async executeForRawResultAsync<T extends object>(\n ...params: unknown[]\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>> {\n const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteAsyncResult<ValuesOf<T>>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: true,\n lastInsertRowId,\n changes,\n }\n );\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesAsync(): Promise<string[]> {\n return this.nativeStatement.getColumnNamesAsync();\n }\n\n /**\n * Finalize the prepared statement. This will call the [`sqlite3_finalize()`](https://www.sqlite.org/c3ref/finalize.html) C function under the hood.\n *\n * Attempting to access a finalized statement will result in an error.\n * > **Note:** While `expo-sqlite` will automatically finalize any orphaned prepared statements upon closing the database, it is considered best practice\n * > to manually finalize prepared statements as soon as they are no longer needed. This helps to prevent resource leaks.\n * > You can use the `try...finally` statement to ensure that prepared statements are finalized even if an error occurs.\n */\n public async finalizeAsync(): Promise<void> {\n await this.nativeStatement.finalizeAsync(this.nativeDatabase);\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Run the prepared statement and return the [`SQLiteExecuteSyncResult`](#sqliteexecutesyncresult) instance.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`SQLiteBindValue`](#sqlitebindvalue) for more information about binding values.\n */\n public executeSync<T>(params: SQLiteBindParams): SQLiteExecuteSyncResult<T>;\n /**\n * @hidden\n */\n public executeSync<T>(...params: SQLiteVariadicBindParams): SQLiteExecuteSyncResult<T>;\n public executeSync<T>(...params: unknown[]): SQLiteExecuteSyncResult<T> {\n const { lastInsertRowId, changes, firstRowValues } = this.nativeStatement.runSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteSyncResult<T>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: false,\n lastInsertRowId,\n changes,\n }\n );\n }\n\n /**\n * Similar to [`executeSync()`](#executesyncparams) but returns the raw value array result instead of the row objects.\n * @hidden Advanced use only.\n */\n public executeForRawResultSync<T extends object>(\n params: SQLiteBindParams\n ): SQLiteExecuteSyncResult<ValuesOf<T>>;\n /**\n * @hidden\n */\n public executeForRawResultSync<T extends object>(\n ...params: SQLiteVariadicBindParams\n ): SQLiteExecuteSyncResult<ValuesOf<T>>;\n public executeForRawResultSync<T extends object>(\n ...params: unknown[]\n ): SQLiteExecuteSyncResult<ValuesOf<T>> {\n const { lastInsertRowId, changes, firstRowValues } = this.nativeStatement.runSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteSyncResult<ValuesOf<T>>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: true,\n lastInsertRowId,\n changes,\n }\n );\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesSync(): string[] {\n return this.nativeStatement.getColumnNamesSync();\n }\n\n /**\n * Finalize the prepared statement. This will call the [`sqlite3_finalize()`](https://www.sqlite.org/c3ref/finalize.html) C function under the hood.\n *\n * Attempting to access a finalized statement will result in an error.\n *\n * > **Note:** While `expo-sqlite` will automatically finalize any orphaned prepared statements upon closing the database, it is considered best practice\n * > to manually finalize prepared statements as soon as they are no longer needed. This helps to prevent resource leaks.\n * > You can use the `try...finally` statement to ensure that prepared statements are finalized even if an error occurs.\n */\n public finalizeSync(): void {\n this.nativeStatement.finalizeSync(this.nativeDatabase);\n }\n\n //#endregion\n}\n\n/**\n * A result returned by [`SQLiteStatement.executeAsync()`](#executeasyncparams).\n *\n * @example\n * The result includes the [`lastInsertRowId`](https://www.sqlite.org/c3ref/last_insert_rowid.html) and [`changes`](https://www.sqlite.org/c3ref/changes.html) properties. You can get the information from the write operations.\n * ```ts\n * const statement = await db.prepareAsync('INSERT INTO test (value) VALUES (?)');\n * try {\n * const result = await statement.executeAsync(101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n *\n * @example\n * The result implements the [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator) interface, so you can use it in `for await...of` loops.\n * ```ts\n * const statement = await db.prepareAsync('SELECT value FROM test WHERE value > ?');\n * try {\n * const result = await statement.executeAsync<{ value: number }>(100);\n * for await (const row of result) {\n * console.log('row value:', row.value);\n * }\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n *\n * @example\n * If your write operations also return values, you can mix all of them together.\n * ```ts\n * const statement = await db.prepareAsync('INSERT INTO test (name, value) VALUES (?, ?) RETURNING name');\n * try {\n * const result = await statement.executeAsync<{ name: string }>('John Doe', 101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * for await (const row of result) {\n * console.log('name:', row.name);\n * }\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n */\nexport interface SQLiteExecuteAsyncResult<T> extends AsyncIterableIterator<T> {\n /**\n * The last inserted row ID. Returned from the [`sqlite3_last_insert_rowid()`](https://www.sqlite.org/c3ref/last_insert_rowid.html) function.\n */\n readonly lastInsertRowId: number;\n\n /**\n * The number of rows affected. Returned from the [`sqlite3_changes()`](https://www.sqlite.org/c3ref/changes.html) function.\n */\n readonly changes: number;\n\n /**\n * Get the first row of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetAsync()`](#resetasync). Otherwise, an error will be thrown.\n */\n getFirstAsync(): Promise<T | null>;\n\n /**\n * Get all rows of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetAsync()`](#resetasync). Otherwise, an error will be thrown.\n */\n getAllAsync(): Promise<T[]>;\n\n /**\n * Reset the prepared statement cursor. This will call the [`sqlite3_reset()`](https://www.sqlite.org/c3ref/reset.html) C function under the hood.\n */\n resetAsync(): Promise<void>;\n}\n\n/**\n * A result returned by [`SQLiteStatement.executeSync()`](#executesyncparams).\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n\n * @example\n * The result includes the [`lastInsertRowId`](https://www.sqlite.org/c3ref/last_insert_rowid.html) and [`changes`](https://www.sqlite.org/c3ref/changes.html) properties. You can get the information from the write operations.\n * ```ts\n * const statement = db.prepareSync('INSERT INTO test (value) VALUES (?)');\n * try {\n * const result = statement.executeSync(101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n *\n * @example\n * The result implements the [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) interface, so you can use it in `for...of` loops.\n * ```ts\n * const statement = db.prepareSync('SELECT value FROM test WHERE value > ?');\n * try {\n * const result = statement.executeSync<{ value: number }>(100);\n * for (const row of result) {\n * console.log('row value:', row.value);\n * }\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n *\n * @example\n * If your write operations also return values, you can mix all of them together.\n * ```ts\n * const statement = db.prepareSync('INSERT INTO test (name, value) VALUES (?, ?) RETURNING name');\n * try {\n * const result = statement.executeSync<{ name: string }>('John Doe', 101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * for (const row of result) {\n * console.log('name:', row.name);\n * }\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n */\nexport interface SQLiteExecuteSyncResult<T> extends IterableIterator<T> {\n /**\n * The last inserted row ID. Returned from the [`sqlite3_last_insert_rowid()`](https://www.sqlite.org/c3ref/last_insert_rowid.html) function.\n */\n readonly lastInsertRowId: number;\n\n /**\n * The number of rows affected. Returned from the [`sqlite3_changes()`](https://www.sqlite.org/c3ref/changes.html) function.\n */\n readonly changes: number;\n\n /**\n * Get the first row of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetSync()`](#resetsync). Otherwise, an error will be thrown.\n */\n getFirstSync(): T | null;\n\n /**\n * Get all rows of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetSync()`](#resetsync). Otherwise, an error will be thrown.\n */\n getAllSync(): T[];\n\n /**\n * Reset the prepared statement cursor. This will call the [`sqlite3_reset()`](https://www.sqlite.org/c3ref/reset.html) C function under the hood.\n */\n resetSync(): void;\n}\n\n//#region Internals for SQLiteExecuteAsyncResult and SQLiteExecuteSyncResult\n\ninterface SQLiteExecuteResultOptions {\n rawResult: boolean;\n lastInsertRowId: number;\n changes: number;\n}\n\n/**\n * Create the `SQLiteExecuteAsyncResult` instance.\n *\n * NOTE: Since Hermes does not support the `Symbol.asyncIterator` feature, we have to use an AsyncGenerator to implement the `AsyncIterableIterator` interface.\n * This is done by `Object.defineProperties` to add the properties to the AsyncGenerator.\n */\nasync function createSQLiteExecuteAsyncResult<T>(\n database: SQLiteAnyDatabase,\n statement: NativeStatement,\n firstRowValues: SQLiteColumnValues | null,\n options: SQLiteExecuteResultOptions\n): Promise<SQLiteExecuteAsyncResult<T>> {\n const instance = new SQLiteExecuteAsyncResultImpl<T>(\n database,\n statement,\n firstRowValues ? processNativeRow(firstRowValues) : null,\n options\n );\n const generator = instance.generatorAsync();\n Object.defineProperties(generator, {\n lastInsertRowId: {\n value: options.lastInsertRowId,\n enumerable: true,\n writable: false,\n configurable: true,\n },\n changes: { value: options.changes, enumerable: true, writable: false, configurable: true },\n getFirstAsync: {\n value: instance.getFirstAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n getAllAsync: {\n value: instance.getAllAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n resetAsync: {\n value: instance.resetAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n });\n\n return generator as SQLiteExecuteAsyncResult<T>;\n}\n\n/**\n * Create the `SQLiteExecuteSyncResult` instance.\n */\nfunction createSQLiteExecuteSyncResult<T>(\n database: SQLiteAnyDatabase,\n statement: NativeStatement,\n firstRowValues: SQLiteColumnValues | null,\n options: SQLiteExecuteResultOptions\n): SQLiteExecuteSyncResult<T> {\n const instance = new SQLiteExecuteSyncResultImpl<T>(\n database,\n statement,\n firstRowValues ? processNativeRow(firstRowValues) : firstRowValues,\n options\n );\n const generator = instance.generatorSync();\n Object.defineProperties(generator, {\n lastInsertRowId: {\n value: options.lastInsertRowId,\n enumerable: true,\n writable: false,\n configurable: true,\n },\n changes: { value: options.changes, enumerable: true, writable: false, configurable: true },\n getFirstSync: {\n value: instance.getFirstSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n getAllSync: {\n value: instance.getAllSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n resetSync: {\n value: instance.resetSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n });\n\n return generator as SQLiteExecuteSyncResult<T>;\n}\n\nclass SQLiteExecuteAsyncResultImpl<T> {\n private columnNames: string[] | null = null;\n private isStepCalled = false;\n\n constructor(\n private readonly database: SQLiteAnyDatabase,\n private readonly statement: NativeStatement,\n private firstRowValues: SQLiteColumnValues | null,\n public readonly options: SQLiteExecuteResultOptions\n ) {}\n\n async getFirstAsync(): Promise<T | null> {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve the first row without being reset. Invoke `resetAsync()` to reset the cursor first if you want to retrieve the first row.'\n );\n }\n this.isStepCalled = true;\n const columnNames = await this.getColumnNamesAsync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n const firstRow = await this.statement.stepAsync(this.database);\n return firstRow != null\n ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))\n : null;\n }\n\n async getAllAsync(): Promise<T[]> {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve all rows without being reset. Invoke `resetAsync()` to reset the cursor first if you want to retrieve all rows.'\n );\n }\n this.isStepCalled = true;\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues == null) {\n // If the first row is empty, this SQL query may be a write operation. We should not call `statement.getAllAsync()` to write again.\n return [];\n }\n const columnNames = await this.getColumnNamesAsync();\n const nativeRows = await this.statement.getAllAsync(this.database);\n const allRows = processNativeRows(nativeRows);\n if (firstRowValues != null && firstRowValues.length > 0) {\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, [\n firstRowValues,\n ...allRows,\n ]);\n }\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, allRows);\n }\n\n async *generatorAsync(): AsyncIterableIterator<T> {\n this.isStepCalled = true;\n const columnNames = await this.getColumnNamesAsync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n\n let result;\n do {\n result = await this.statement.stepAsync(this.database);\n if (result != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));\n }\n } while (result != null);\n }\n\n resetAsync(): Promise<void> {\n const result = this.statement.resetAsync(this.database);\n this.isStepCalled = false;\n return result;\n }\n\n private popFirstRowValues(): SQLiteColumnValues | null {\n if (this.firstRowValues != null) {\n const firstRowValues = this.firstRowValues;\n this.firstRowValues = null;\n return firstRowValues.length > 0 ? firstRowValues : null;\n }\n return null;\n }\n\n private async getColumnNamesAsync(): Promise<string[]> {\n if (this.columnNames == null) {\n this.columnNames = await this.statement.getColumnNamesAsync();\n }\n return this.columnNames;\n }\n}\n\nclass SQLiteExecuteSyncResultImpl<T> {\n private columnNames: string[] | null = null;\n private isStepCalled = false;\n\n constructor(\n private readonly database: SQLiteAnyDatabase,\n private readonly statement: NativeStatement,\n private firstRowValues: SQLiteColumnValues | null,\n public readonly options: SQLiteExecuteResultOptions\n ) {}\n\n getFirstSync(): T | null {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve the first row without being reset. Invoke `resetSync()` to reset the cursor first if you want to retrieve the first row.'\n );\n }\n const columnNames = this.getColumnNamesSync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n const firstRow = this.statement.stepSync(this.database);\n return firstRow != null\n ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))\n : null;\n }\n\n getAllSync(): T[] {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve all rows without being reset. Invoke `resetSync()` to reset the cursor first if you want to retrieve all rows.'\n );\n }\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues == null) {\n // If the first row is empty, this SQL query may be a write operation. We should not call `statement.getAllAsync()` to write again.\n return [];\n }\n const columnNames = this.getColumnNamesSync();\n const nativeRows = this.statement.getAllSync(this.database);\n const allRows = processNativeRows(nativeRows);\n if (firstRowValues != null && firstRowValues.length > 0) {\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, [\n firstRowValues,\n ...allRows,\n ]);\n }\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, allRows);\n }\n\n *generatorSync(): IterableIterator<T> {\n const columnNames = this.getColumnNamesSync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n let result;\n do {\n result = this.statement.stepSync(this.database);\n if (result != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));\n }\n } while (result != null);\n }\n\n resetSync(): void {\n const result = this.statement.resetSync(this.database);\n this.isStepCalled = false;\n return result;\n }\n\n private popFirstRowValues(): SQLiteColumnValues | null {\n if (this.firstRowValues != null) {\n const firstRowValues = this.firstRowValues;\n this.firstRowValues = null;\n return firstRowValues.length > 0 ? firstRowValues : null;\n }\n return null;\n }\n\n private getColumnNamesSync(): string[] {\n if (this.columnNames == null) {\n this.columnNames = this.statement.getColumnNamesSync();\n }\n return this.columnNames;\n }\n}\n\nfunction composeRowIfNeeded<T>(\n rawResult: boolean,\n columnNames: SQLiteColumnNames,\n columnValues: SQLiteColumnValues\n): T {\n return rawResult\n ? (columnValues as T) // T would be a ValuesOf<> from caller\n : composeRow<T>(columnNames, columnValues);\n}\n\nfunction composeRowsIfNeeded<T>(\n rawResult: boolean,\n columnNames: SQLiteColumnNames,\n columnValuesList: SQLiteColumnValues[]\n): T[] {\n return rawResult\n ? (columnValuesList as T[]) // T[] would be a ValuesOf<>[] from caller\n : composeRows<T>(columnNames, columnValuesList);\n}\n\nfunction processNativeRow(nativeRow: SQLiteColumnValues): SQLiteColumnValues {\n return nativeRow?.map((column) =>\n column instanceof ArrayBuffer ? new Uint8Array(column) : column\n );\n}\n\nfunction processNativeRows(nativeRows: SQLiteColumnValues[]): SQLiteColumnValues[] {\n return nativeRows.map(processNativeRow);\n}\n\n//#endregion\n"]}
1
+ {"version":3,"file":"SQLiteStatement.js","sourceRoot":"","sources":["../src/SQLiteStatement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NativeDatabase } from './NativeDatabase';\nimport type {\n NativeStatement,\n SQLiteBindParams,\n SQLiteVariadicBindParams,\n SQLiteAnyDatabase,\n SQLiteColumnNames,\n SQLiteColumnValues,\n} from './NativeStatement';\nimport { composeRow, composeRows, normalizeParams } from './paramUtils';\n\nexport type {\n SQLiteBindParams,\n SQLiteBindValue,\n SQLiteRunResult,\n SQLiteVariadicBindParams,\n} from './NativeStatement';\n\ntype ValuesOf<T extends object> = T[keyof T][];\n\n/**\n * A prepared statement returned by [`SQLiteDatabase.prepareAsync()`](#prepareasyncsource) or [`SQLiteDatabase.prepareSync()`](#preparesyncsource) that can be binded with parameters and executed.\n */\nexport class SQLiteStatement {\n /**\n * The cursor that currently owns the underlying `sqlite3_stmt`. A prepared statement has exactly\n * one cursor, so running the statement again invalidates the cursor of every earlier run.\n */\n private currentCursor: object | null = null;\n\n constructor(\n private readonly nativeDatabase: NativeDatabase,\n private readonly nativeStatement: NativeStatement\n ) {}\n\n /**\n * Make the run that just finished the owner of the statement cursor, and return a predicate\n * that tells whether it still is.\n */\n private claimCursor(): () => boolean {\n const cursor = {};\n this.currentCursor = cursor;\n return () => this.currentCursor === cursor;\n }\n\n //#region Asynchronous API\n\n /**\n * Run the prepared statement and return the [`SQLiteExecuteAsyncResult`](#sqliteexecuteasyncresult) instance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`SQLiteBindValue`](#sqlitebindvalue) for more information about binding values.\n */\n public executeAsync<T>(params: SQLiteBindParams): Promise<SQLiteExecuteAsyncResult<T>>;\n /**\n * @hidden\n */\n public executeAsync<T>(...params: SQLiteVariadicBindParams): Promise<SQLiteExecuteAsyncResult<T>>;\n public async executeAsync<T>(...params: unknown[]): Promise<SQLiteExecuteAsyncResult<T>> {\n const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteAsyncResult<T>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: false,\n lastInsertRowId,\n changes,\n },\n this.claimCursor()\n );\n }\n\n /**\n * Similar to [`executeAsync()`](#executeasyncparams) but returns the raw value array result instead of the row objects.\n * @hidden Advanced use only.\n */\n public executeForRawResultAsync<T extends object>(\n params: SQLiteBindParams\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>>;\n /**\n * @hidden\n */\n public executeForRawResultAsync<T extends object>(\n ...params: SQLiteVariadicBindParams\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>>;\n public async executeForRawResultAsync<T extends object>(\n ...params: unknown[]\n ): Promise<SQLiteExecuteAsyncResult<ValuesOf<T>>> {\n const { lastInsertRowId, changes, firstRowValues } = await this.nativeStatement.runAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteAsyncResult<ValuesOf<T>>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: true,\n lastInsertRowId,\n changes,\n },\n this.claimCursor()\n );\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesAsync(): Promise<string[]> {\n return this.nativeStatement.getColumnNamesAsync();\n }\n\n /**\n * Finalize the prepared statement. This will call the [`sqlite3_finalize()`](https://www.sqlite.org/c3ref/finalize.html) C function under the hood.\n *\n * Attempting to access a finalized statement will result in an error.\n * > **Note:** While `expo-sqlite` will automatically finalize any orphaned prepared statements upon closing the database, it is considered best practice\n * > to manually finalize prepared statements as soon as they are no longer needed. This helps to prevent resource leaks.\n * > You can use the `try...finally` statement to ensure that prepared statements are finalized even if an error occurs.\n */\n public async finalizeAsync(): Promise<void> {\n await this.nativeStatement.finalizeAsync(this.nativeDatabase);\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Run the prepared statement and return the [`SQLiteExecuteSyncResult`](#sqliteexecutesyncresult) instance.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`SQLiteBindValue`](#sqlitebindvalue) for more information about binding values.\n */\n public executeSync<T>(params: SQLiteBindParams): SQLiteExecuteSyncResult<T>;\n /**\n * @hidden\n */\n public executeSync<T>(...params: SQLiteVariadicBindParams): SQLiteExecuteSyncResult<T>;\n public executeSync<T>(...params: unknown[]): SQLiteExecuteSyncResult<T> {\n const { lastInsertRowId, changes, firstRowValues } = this.nativeStatement.runSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteSyncResult<T>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: false,\n lastInsertRowId,\n changes,\n },\n this.claimCursor()\n );\n }\n\n /**\n * Similar to [`executeSync()`](#executesyncparams) but returns the raw value array result instead of the row objects.\n * @hidden Advanced use only.\n */\n public executeForRawResultSync<T extends object>(\n params: SQLiteBindParams\n ): SQLiteExecuteSyncResult<ValuesOf<T>>;\n /**\n * @hidden\n */\n public executeForRawResultSync<T extends object>(\n ...params: SQLiteVariadicBindParams\n ): SQLiteExecuteSyncResult<ValuesOf<T>>;\n public executeForRawResultSync<T extends object>(\n ...params: unknown[]\n ): SQLiteExecuteSyncResult<ValuesOf<T>> {\n const { lastInsertRowId, changes, firstRowValues } = this.nativeStatement.runSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return createSQLiteExecuteSyncResult<ValuesOf<T>>(\n this.nativeDatabase,\n this.nativeStatement,\n firstRowValues,\n {\n rawResult: true,\n lastInsertRowId,\n changes,\n },\n this.claimCursor()\n );\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesSync(): string[] {\n return this.nativeStatement.getColumnNamesSync();\n }\n\n /**\n * Finalize the prepared statement. This will call the [`sqlite3_finalize()`](https://www.sqlite.org/c3ref/finalize.html) C function under the hood.\n *\n * Attempting to access a finalized statement will result in an error.\n *\n * > **Note:** While `expo-sqlite` will automatically finalize any orphaned prepared statements upon closing the database, it is considered best practice\n * > to manually finalize prepared statements as soon as they are no longer needed. This helps to prevent resource leaks.\n * > You can use the `try...finally` statement to ensure that prepared statements are finalized even if an error occurs.\n */\n public finalizeSync(): void {\n this.nativeStatement.finalizeSync(this.nativeDatabase);\n }\n\n //#endregion\n}\n\n/**\n * A result returned by [`SQLiteStatement.executeAsync()`](#executeasyncparams).\n *\n * @example\n * The result includes the [`lastInsertRowId`](https://www.sqlite.org/c3ref/last_insert_rowid.html) and [`changes`](https://www.sqlite.org/c3ref/changes.html) properties. You can get the information from the write operations.\n * ```ts\n * const statement = await db.prepareAsync('INSERT INTO test (value) VALUES (?)');\n * try {\n * const result = await statement.executeAsync(101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n *\n * @example\n * The result implements the [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator) interface, so you can use it in `for await...of` loops.\n * ```ts\n * const statement = await db.prepareAsync('SELECT value FROM test WHERE value > ?');\n * try {\n * const result = await statement.executeAsync<{ value: number }>(100);\n * for await (const row of result) {\n * console.log('row value:', row.value);\n * }\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n *\n * @example\n * If your write operations also return values, you can mix all of them together.\n * ```ts\n * const statement = await db.prepareAsync('INSERT INTO test (name, value) VALUES (?, ?) RETURNING name');\n * try {\n * const result = await statement.executeAsync<{ name: string }>('John Doe', 101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * for await (const row of result) {\n * console.log('name:', row.name);\n * }\n * } finally {\n * await statement.finalizeAsync();\n * }\n * ```\n */\nexport interface SQLiteExecuteAsyncResult<T> extends AsyncIterableIterator<T> {\n /**\n * The last inserted row ID. Returned from the [`sqlite3_last_insert_rowid()`](https://www.sqlite.org/c3ref/last_insert_rowid.html) function.\n */\n readonly lastInsertRowId: number;\n\n /**\n * The number of rows affected. Returned from the [`sqlite3_changes()`](https://www.sqlite.org/c3ref/changes.html) function.\n */\n readonly changes: number;\n\n /**\n * Get the first row of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetAsync()`](#resetasync). Otherwise, an error will be thrown.\n */\n getFirstAsync(): Promise<T | null>;\n\n /**\n * Get all rows of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetAsync()`](#resetasync). Otherwise, an error will be thrown.\n */\n getAllAsync(): Promise<T[]>;\n\n /**\n * Reset the prepared statement cursor. This will call the [`sqlite3_reset()`](https://www.sqlite.org/c3ref/reset.html) C function under the hood.\n */\n resetAsync(): Promise<void>;\n}\n\n/**\n * A result returned by [`SQLiteStatement.executeSync()`](#executesyncparams).\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n\n * @example\n * The result includes the [`lastInsertRowId`](https://www.sqlite.org/c3ref/last_insert_rowid.html) and [`changes`](https://www.sqlite.org/c3ref/changes.html) properties. You can get the information from the write operations.\n * ```ts\n * const statement = db.prepareSync('INSERT INTO test (value) VALUES (?)');\n * try {\n * const result = statement.executeSync(101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n *\n * @example\n * The result implements the [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) interface, so you can use it in `for...of` loops.\n * ```ts\n * const statement = db.prepareSync('SELECT value FROM test WHERE value > ?');\n * try {\n * const result = statement.executeSync<{ value: number }>(100);\n * for (const row of result) {\n * console.log('row value:', row.value);\n * }\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n *\n * @example\n * If your write operations also return values, you can mix all of them together.\n * ```ts\n * const statement = db.prepareSync('INSERT INTO test (name, value) VALUES (?, ?) RETURNING name');\n * try {\n * const result = statement.executeSync<{ name: string }>('John Doe', 101);\n * console.log('lastInsertRowId:', result.lastInsertRowId);\n * console.log('changes:', result.changes);\n * for (const row of result) {\n * console.log('name:', row.name);\n * }\n * } finally {\n * statement.finalizeSync();\n * }\n * ```\n */\nexport interface SQLiteExecuteSyncResult<T> extends IterableIterator<T> {\n /**\n * The last inserted row ID. Returned from the [`sqlite3_last_insert_rowid()`](https://www.sqlite.org/c3ref/last_insert_rowid.html) function.\n */\n readonly lastInsertRowId: number;\n\n /**\n * The number of rows affected. Returned from the [`sqlite3_changes()`](https://www.sqlite.org/c3ref/changes.html) function.\n */\n readonly changes: number;\n\n /**\n * Get the first row of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetSync()`](#resetsync). Otherwise, an error will be thrown.\n */\n getFirstSync(): T | null;\n\n /**\n * Get all rows of the result set. This requires the SQLite cursor to be in its initial state. If you have already retrieved rows from the result set, you need to reset the cursor first by calling [`resetSync()`](#resetsync). Otherwise, an error will be thrown.\n */\n getAllSync(): T[];\n\n /**\n * Reset the prepared statement cursor. This will call the [`sqlite3_reset()`](https://www.sqlite.org/c3ref/reset.html) C function under the hood.\n */\n resetSync(): void;\n}\n\n//#region Internals for SQLiteExecuteAsyncResult and SQLiteExecuteSyncResult\n\ninterface SQLiteExecuteResultOptions {\n rawResult: boolean;\n lastInsertRowId: number;\n changes: number;\n}\n\nconst SUPERSEDED_CURSOR_MESSAGE =\n 'This result is no longer readable because the prepared statement ran again. ' +\n 'A prepared statement holds a single SQLite cursor, so a later run rebinds the parameters and moves that cursor, ' +\n 'and this result would return the rows of the later run. ' +\n 'Read a result to the end before you run the same statement again, or prepare a separate statement for each reader.';\n\n/**\n * Create the `SQLiteExecuteAsyncResult` instance.\n *\n * NOTE: Since Hermes does not support the `Symbol.asyncIterator` feature, we have to use an AsyncGenerator to implement the `AsyncIterableIterator` interface.\n * This is done by `Object.defineProperties` to add the properties to the AsyncGenerator.\n */\nasync function createSQLiteExecuteAsyncResult<T>(\n database: SQLiteAnyDatabase,\n statement: NativeStatement,\n firstRowValues: SQLiteColumnValues | null,\n options: SQLiteExecuteResultOptions,\n isCursorOwner: () => boolean\n): Promise<SQLiteExecuteAsyncResult<T>> {\n const instance = new SQLiteExecuteAsyncResultImpl<T>(\n database,\n statement,\n firstRowValues ? processNativeRow(firstRowValues) : null,\n options,\n isCursorOwner\n );\n const generator = instance.generatorAsync();\n Object.defineProperties(generator, {\n lastInsertRowId: {\n value: options.lastInsertRowId,\n enumerable: true,\n writable: false,\n configurable: true,\n },\n changes: { value: options.changes, enumerable: true, writable: false, configurable: true },\n getFirstAsync: {\n value: instance.getFirstAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n getAllAsync: {\n value: instance.getAllAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n resetAsync: {\n value: instance.resetAsync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n });\n\n return generator as SQLiteExecuteAsyncResult<T>;\n}\n\n/**\n * Create the `SQLiteExecuteSyncResult` instance.\n */\nfunction createSQLiteExecuteSyncResult<T>(\n database: SQLiteAnyDatabase,\n statement: NativeStatement,\n firstRowValues: SQLiteColumnValues | null,\n options: SQLiteExecuteResultOptions,\n isCursorOwner: () => boolean\n): SQLiteExecuteSyncResult<T> {\n const instance = new SQLiteExecuteSyncResultImpl<T>(\n database,\n statement,\n firstRowValues ? processNativeRow(firstRowValues) : firstRowValues,\n options,\n isCursorOwner\n );\n const generator = instance.generatorSync();\n Object.defineProperties(generator, {\n lastInsertRowId: {\n value: options.lastInsertRowId,\n enumerable: true,\n writable: false,\n configurable: true,\n },\n changes: { value: options.changes, enumerable: true, writable: false, configurable: true },\n getFirstSync: {\n value: instance.getFirstSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n getAllSync: {\n value: instance.getAllSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n resetSync: {\n value: instance.resetSync.bind(instance),\n enumerable: true,\n writable: false,\n configurable: true,\n },\n });\n\n return generator as SQLiteExecuteSyncResult<T>;\n}\n\nclass SQLiteExecuteAsyncResultImpl<T> {\n private columnNames: string[] | null = null;\n private isStepCalled = false;\n\n constructor(\n private readonly database: SQLiteAnyDatabase,\n private readonly statement: NativeStatement,\n private firstRowValues: SQLiteColumnValues | null,\n public readonly options: SQLiteExecuteResultOptions,\n private readonly isCursorOwner: () => boolean\n ) {}\n\n /** Throw rather than step a cursor that a later run of the same statement has taken over. */\n private assertCursorOwner() {\n if (!this.isCursorOwner()) {\n throw new Error(SUPERSEDED_CURSOR_MESSAGE);\n }\n }\n\n async getFirstAsync(): Promise<T | null> {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve the first row without being reset. Invoke `resetAsync()` to reset the cursor first if you want to retrieve the first row.'\n );\n }\n this.isStepCalled = true;\n const columnNames = await this.getColumnNamesAsync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n this.assertCursorOwner();\n const firstRow = await this.statement.stepAsync(this.database);\n return firstRow != null\n ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))\n : null;\n }\n\n async getAllAsync(): Promise<T[]> {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve all rows without being reset. Invoke `resetAsync()` to reset the cursor first if you want to retrieve all rows.'\n );\n }\n this.isStepCalled = true;\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues == null) {\n // If the first row is empty, this SQL query may be a write operation. We should not call `statement.getAllAsync()` to write again.\n return [];\n }\n const columnNames = await this.getColumnNamesAsync();\n this.assertCursorOwner();\n const nativeRows = await this.statement.getAllAsync(this.database);\n const allRows = processNativeRows(nativeRows);\n if (firstRowValues.length > 0) {\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, [\n firstRowValues,\n ...allRows,\n ]);\n }\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, allRows);\n }\n\n async *generatorAsync(): AsyncIterableIterator<T> {\n this.isStepCalled = true;\n const columnNames = await this.getColumnNamesAsync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n\n let result;\n do {\n this.assertCursorOwner();\n result = await this.statement.stepAsync(this.database);\n if (result != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));\n }\n } while (result != null);\n }\n\n async resetAsync(): Promise<void> {\n // Resetting a superseded result would rewind the cursor of the run that owns it now.\n this.assertCursorOwner();\n await this.statement.resetAsync(this.database);\n this.isStepCalled = false;\n }\n\n private popFirstRowValues(): SQLiteColumnValues | null {\n if (this.firstRowValues != null) {\n const firstRowValues = this.firstRowValues;\n this.firstRowValues = null;\n return firstRowValues.length > 0 ? firstRowValues : null;\n }\n return null;\n }\n\n private async getColumnNamesAsync(): Promise<string[]> {\n if (this.columnNames == null) {\n this.columnNames = await this.statement.getColumnNamesAsync();\n }\n return this.columnNames;\n }\n}\n\nclass SQLiteExecuteSyncResultImpl<T> {\n private columnNames: string[] | null = null;\n private isStepCalled = false;\n\n constructor(\n private readonly database: SQLiteAnyDatabase,\n private readonly statement: NativeStatement,\n private firstRowValues: SQLiteColumnValues | null,\n public readonly options: SQLiteExecuteResultOptions,\n private readonly isCursorOwner: () => boolean\n ) {}\n\n /** Throw rather than step a cursor that a later run of the same statement has taken over. */\n private assertCursorOwner() {\n if (!this.isCursorOwner()) {\n throw new Error(SUPERSEDED_CURSOR_MESSAGE);\n }\n }\n\n getFirstSync(): T | null {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve the first row without being reset. Invoke `resetSync()` to reset the cursor first if you want to retrieve the first row.'\n );\n }\n const columnNames = this.getColumnNamesSync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n this.assertCursorOwner();\n const firstRow = this.statement.stepSync(this.database);\n return firstRow != null\n ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))\n : null;\n }\n\n getAllSync(): T[] {\n if (this.isStepCalled) {\n throw new Error(\n 'The SQLite cursor has been shifted and is unable to retrieve all rows without being reset. Invoke `resetSync()` to reset the cursor first if you want to retrieve all rows.'\n );\n }\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues == null) {\n // If the first row is empty, this SQL query may be a write operation. We should not call `statement.getAllAsync()` to write again.\n return [];\n }\n const columnNames = this.getColumnNamesSync();\n this.assertCursorOwner();\n const nativeRows = this.statement.getAllSync(this.database);\n const allRows = processNativeRows(nativeRows);\n if (firstRowValues != null && firstRowValues.length > 0) {\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, [\n firstRowValues,\n ...allRows,\n ]);\n }\n return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, allRows);\n }\n\n *generatorSync(): IterableIterator<T> {\n const columnNames = this.getColumnNamesSync();\n const firstRowValues = this.popFirstRowValues();\n if (firstRowValues != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);\n }\n let result;\n do {\n this.assertCursorOwner();\n result = this.statement.stepSync(this.database);\n if (result != null) {\n yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));\n }\n } while (result != null);\n }\n\n resetSync(): void {\n // Resetting a superseded result would rewind the cursor of the run that owns it now.\n this.assertCursorOwner();\n this.statement.resetSync(this.database);\n this.isStepCalled = false;\n }\n\n private popFirstRowValues(): SQLiteColumnValues | null {\n if (this.firstRowValues != null) {\n const firstRowValues = this.firstRowValues;\n this.firstRowValues = null;\n return firstRowValues.length > 0 ? firstRowValues : null;\n }\n return null;\n }\n\n private getColumnNamesSync(): string[] {\n if (this.columnNames == null) {\n this.columnNames = this.statement.getColumnNamesSync();\n }\n return this.columnNames;\n }\n}\n\nfunction composeRowIfNeeded<T>(\n rawResult: boolean,\n columnNames: SQLiteColumnNames,\n columnValues: SQLiteColumnValues\n): T {\n return rawResult\n ? (columnValues as T) // T would be a ValuesOf<> from caller\n : composeRow<T>(columnNames, columnValues);\n}\n\nfunction composeRowsIfNeeded<T>(\n rawResult: boolean,\n columnNames: SQLiteColumnNames,\n columnValuesList: SQLiteColumnValues[]\n): T[] {\n return rawResult\n ? (columnValuesList as T[]) // T[] would be a ValuesOf<>[] from caller\n : composeRows<T>(columnNames, columnValuesList);\n}\n\nfunction processNativeRow(nativeRow: SQLiteColumnValues): SQLiteColumnValues {\n return nativeRow?.map((column) =>\n column instanceof ArrayBuffer ? new Uint8Array(column) : column\n );\n}\n\nfunction processNativeRows(nativeRows: SQLiteColumnValues[]): SQLiteColumnValues[] {\n return nativeRows.map(processNativeRow);\n}\n\n//#endregion\n"]}
@@ -9,7 +9,7 @@
9
9
  "publication": {
10
10
  "groupId": "host.exp.exponent",
11
11
  "artifactId": "expo.modules.sqlite",
12
- "version": "57.0.3",
12
+ "version": "57.0.5",
13
13
  "repository": "local-maven-repo"
14
14
  }
15
15
  },
@@ -413,7 +413,15 @@ public final class SQLiteModule: Module {
413
413
 
414
414
  let ret = exsqlite3_step(statement.pointer)
415
415
  if ret != SQLITE_ROW && ret != SQLITE_DONE {
416
- throw SQLiteErrorException(convertSqlLiteErrorToString(database))
416
+ // A step that fails with `SQLITE_BUSY` leaves the statement running, so every later `COMMIT`
417
+ // on the connection fails with "SQL statements in progress" until the statement is reset.
418
+ // Reset only for `SQLITE_BUSY`. A reset also clears other errors, which `finalize()` must still report.
419
+ // Read the message first. `sqlite3_reset` replaces the error message.
420
+ let message = convertSqlLiteErrorToString(database)
421
+ if ret & 0xff == SQLITE_BUSY {
422
+ exsqlite3_reset(statement.pointer)
423
+ }
424
+ throw SQLiteErrorException(message)
417
425
  }
418
426
  let firstRowValues: SQLiteColumnValues = (ret == SQLITE_ROW) ? try getColumnValues(statement: statement) : []
419
427
  return [
@@ -428,6 +436,13 @@ public final class SQLiteModule: Module {
428
436
  private func step(statement: NativeStatement, database: NativeDatabase) throws -> SQLiteColumnValues? {
429
437
  try maybeThrowForClosedDatabase(database)
430
438
  try maybeThrowForFinalizedStatement(statement)
439
+
440
+ // Guard the stateful statement, see `run` above.
441
+ statement.lock.wait()
442
+ defer {
443
+ statement.lock.signal()
444
+ }
445
+
431
446
  let ret = exsqlite3_step(statement.pointer)
432
447
  if ret == SQLITE_ROW {
433
448
  return try getColumnValues(statement: statement)
@@ -441,6 +456,13 @@ public final class SQLiteModule: Module {
441
456
  private func getAll(statement: NativeStatement, database: NativeDatabase) throws -> [SQLiteColumnValues] {
442
457
  try maybeThrowForClosedDatabase(database)
443
458
  try maybeThrowForFinalizedStatement(statement)
459
+
460
+ // Guard the stateful statement, see `run` above.
461
+ statement.lock.wait()
462
+ defer {
463
+ statement.lock.signal()
464
+ }
465
+
444
466
  var columnValuesList: [SQLiteColumnValues] = []
445
467
  while true {
446
468
  let ret = exsqlite3_step(statement.pointer)
@@ -459,6 +481,13 @@ public final class SQLiteModule: Module {
459
481
  private func reset(statement: NativeStatement, database: NativeDatabase) throws {
460
482
  try maybeThrowForClosedDatabase(database)
461
483
  try maybeThrowForFinalizedStatement(statement)
484
+
485
+ // Guard the stateful statement, see `run` above.
486
+ statement.lock.wait()
487
+ defer {
488
+ statement.lock.signal()
489
+ }
490
+
462
491
  if exsqlite3_reset(statement.pointer) != SQLITE_OK {
463
492
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
464
493
  }
@@ -467,6 +496,13 @@ public final class SQLiteModule: Module {
467
496
  private func finalize(statement: NativeStatement, database: NativeDatabase) throws {
468
497
  try maybeThrowForClosedDatabase(database)
469
498
  try maybeThrowForFinalizedStatement(statement)
499
+
500
+ // Guard the stateful statement, see `run` above.
501
+ statement.lock.wait()
502
+ defer {
503
+ statement.lock.signal()
504
+ }
505
+
470
506
  if exsqlite3_finalize(statement.pointer) != SQLITE_OK {
471
507
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
472
508
  }
@@ -0,0 +1 @@
1
+ 246e4dc5d5ea9cec2e91193b6fe95946f29674d2a9762171daf01c60f8bdd7a9
@@ -0,0 +1 @@
1
+ d54e01c015f2c8f7ff965d4afe4a76b297b9bf4a63c60b173f904aad0ca11100ac6e50cc62f27066068fa28453b6305020c428568dedd94a61fbce8abfc4db24
@@ -0,0 +1 @@
1
+ 21dfa7a364f93fdac8f5dd3bbc73949d836079d79f900905ec0ced8034873759
@@ -0,0 +1 @@
1
+ b4f071be26571e04e9451e10b9f27219b7b6719b54be9c3f8cea1550efe6f219d175171e325f91a80ee087df944a1e53c886af61afc7982c1cfd8c8604b4f60c
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.sqlite",
6
- "version": "57.0.3",
6
+ "version": "57.0.5",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -24,13 +24,13 @@
24
24
  },
25
25
  "files": [
26
26
  {
27
- "name": "expo.modules.sqlite-57.0.3.aar",
28
- "url": "expo.modules.sqlite-57.0.3.aar",
29
- "size": 3823160,
30
- "sha512": "97b9f3c849ecda169a14bd40502d11b42a7db55e98a1ac3a33391a720bdac4748fd4e7fe190c1ab77c37aada7d932f7b587efa141949d4f4f281959e5e1a2475",
31
- "sha256": "df1da5f5381b01deb84c69e946436e98f69fb7a3c3f55c03b01e88061fd88e4d",
32
- "sha1": "87f1f42b8d635fff98edf78cf7a123628dc369e0",
33
- "md5": "89190f5fa83aadb89346c061f9cb6c34"
27
+ "name": "expo.modules.sqlite-57.0.5.aar",
28
+ "url": "expo.modules.sqlite-57.0.5.aar",
29
+ "size": 1147519,
30
+ "sha512": "b4f071be26571e04e9451e10b9f27219b7b6719b54be9c3f8cea1550efe6f219d175171e325f91a80ee087df944a1e53c886af61afc7982c1cfd8c8604b4f60c",
31
+ "sha256": "21dfa7a364f93fdac8f5dd3bbc73949d836079d79f900905ec0ced8034873759",
32
+ "sha1": "69de56b1948910c75d4c51ddea38ff3567706dc6",
33
+ "md5": "d6631a5fb1bd6725a6b4cc14e11d853f"
34
34
  }
35
35
  ]
36
36
  },
@@ -67,13 +67,13 @@
67
67
  ],
68
68
  "files": [
69
69
  {
70
- "name": "expo.modules.sqlite-57.0.3.aar",
71
- "url": "expo.modules.sqlite-57.0.3.aar",
72
- "size": 3823160,
73
- "sha512": "97b9f3c849ecda169a14bd40502d11b42a7db55e98a1ac3a33391a720bdac4748fd4e7fe190c1ab77c37aada7d932f7b587efa141949d4f4f281959e5e1a2475",
74
- "sha256": "df1da5f5381b01deb84c69e946436e98f69fb7a3c3f55c03b01e88061fd88e4d",
75
- "sha1": "87f1f42b8d635fff98edf78cf7a123628dc369e0",
76
- "md5": "89190f5fa83aadb89346c061f9cb6c34"
70
+ "name": "expo.modules.sqlite-57.0.5.aar",
71
+ "url": "expo.modules.sqlite-57.0.5.aar",
72
+ "size": 1147519,
73
+ "sha512": "b4f071be26571e04e9451e10b9f27219b7b6719b54be9c3f8cea1550efe6f219d175171e325f91a80ee087df944a1e53c886af61afc7982c1cfd8c8604b4f60c",
74
+ "sha256": "21dfa7a364f93fdac8f5dd3bbc73949d836079d79f900905ec0ced8034873759",
75
+ "sha1": "69de56b1948910c75d4c51ddea38ff3567706dc6",
76
+ "md5": "d6631a5fb1bd6725a6b4cc14e11d853f"
77
77
  }
78
78
  ]
79
79
  },
@@ -87,13 +87,13 @@
87
87
  },
88
88
  "files": [
89
89
  {
90
- "name": "expo.modules.sqlite-57.0.3-sources.jar",
91
- "url": "expo.modules.sqlite-57.0.3-sources.jar",
92
- "size": 11551,
93
- "sha512": "3b63d91aadb7a09514fc8fb158bb08caf92b6108cbc0876893b1a7a3fd33c1a4934c3b7912a858404f0a0eac7b854572fa90c90b8c93b9b52bde2204dcdab735",
94
- "sha256": "b8f668275e3ec93cff367011da2b3ae7bd83f43a690ce56473395ba6284c8b7c",
95
- "sha1": "7c0a8d8193faac646dccacbe00982974ffb4f488",
96
- "md5": "9b900a345245e67770016ae8154b63e1"
90
+ "name": "expo.modules.sqlite-57.0.5-sources.jar",
91
+ "url": "expo.modules.sqlite-57.0.5-sources.jar",
92
+ "size": 11795,
93
+ "sha512": "d54e01c015f2c8f7ff965d4afe4a76b297b9bf4a63c60b173f904aad0ca11100ac6e50cc62f27066068fa28453b6305020c428568dedd94a61fbce8abfc4db24",
94
+ "sha256": "246e4dc5d5ea9cec2e91193b6fe95946f29674d2a9762171daf01c60f8bdd7a9",
95
+ "sha1": "14aee4e10a29fa128eac15592d7d2615b925b4ba",
96
+ "md5": "34e7fea693f36611af7d552e9c477a03"
97
97
  }
98
98
  ]
99
99
  }
@@ -0,0 +1 @@
1
+ 09bfabf57d1e2fe9807bc15dcd5c2c82352618cda400a621dbdc913021434349
@@ -0,0 +1 @@
1
+ c522663f3ea1aa4fa23869e41e6fdacd3e2b24a54c71ae928ffa9b3f064ac1d7a7fb54d25271d1c942f2a238b917a80e9c86f6d0f781f3f42e0977a94a67fd0b
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>host.exp.exponent</groupId>
11
11
  <artifactId>expo.modules.sqlite</artifactId>
12
- <version>57.0.3</version>
12
+ <version>57.0.5</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.sqlite</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ 175b8d0b117dd21841ad39dcf829c54c8f71e11b0b4bb0662df25e422b25813c
@@ -0,0 +1 @@
1
+ f4302aaa17f006f0e9b1f6ee231f6598fbc6f0c7d4cd7514326361d13067d1c2a287fc6fa54fbf911059e64e4aaef0b4ac766f3d7a0c879589aed2836e52da41
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.sqlite</artifactId>
5
5
  <versioning>
6
- <latest>57.0.3</latest>
7
- <release>57.0.3</release>
6
+ <latest>57.0.5</latest>
7
+ <release>57.0.5</release>
8
8
  <versions>
9
- <version>57.0.3</version>
9
+ <version>57.0.5</version>
10
10
  </versions>
11
- <lastUpdated>20260911111657</lastUpdated>
11
+ <lastUpdated>20261112131753</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 5cb9dfd764cd0e869f7e386f6b7ce0bc
1
+ dccdb3d0f6e21b82da4026c5964c250f
@@ -1 +1 @@
1
- 19c3594316a37dc3e9d0fde3db4d68b1b0d89ce1
1
+ f600d5787ea2bdfd0922dd260c30b940bc2fe248
@@ -1 +1 @@
1
- 72bc2d458f5ca000bc7e23bc0e303d45be74b3aa47ad0dcd01d929d54776fee3
1
+ 039aeb06e7d3d367792bf461f21b1d5647d4b72d4bd1b191f14cd302530a3ccf
@@ -1 +1 @@
1
- 80b8bd1ab7324b519d09d3393ad25884eb047741ff2f25c6a53caed51827e8301f9ec4e8e4e8d713ac05e80fa0adc64383c8d7302994bc34e9c3be39d7e29dab
1
+ 5b2af984e10d8f78bcd71adda7c3ff62500e17c682452f9d3469df91cdff1a6d440db6c3b6f0fdc58fc90e71a8ad71c707cfc24776d21bf15607c7395525112f
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-sqlite",
3
- "version": "57.0.3",
3
+ "version": "57.0.5",
4
4
  "description": "Provides access to a database using SQLite (https://www.sqlite.org/). The database is persisted across restarts of your app.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -55,7 +55,7 @@
55
55
  "@types/react": "~19.2.0",
56
56
  "better-sqlite3": "^11.6.0",
57
57
  "react-error-boundary": "^4.0.11",
58
- "expo": "57.0.22",
58
+ "expo": "57.0.33",
59
59
  "expo-module-scripts": "56.0.3"
60
60
  },
61
61
  "peerDependencies": {
@@ -63,7 +63,7 @@
63
63
  "react": "*",
64
64
  "react-native": "*"
65
65
  },
66
- "gitHead": "9e5319c0f821a27b7924841903abae50e2b41790",
66
+ "gitHead": "968a9dcec304789b2ccc1a41ef5d301938e91478",
67
67
  "scripts": {
68
68
  "build": "expo-module build",
69
69
  "bundle:webui": "pushd dev-plugin-webui && bun run build && popd && rm -rf dev-plugin-dist && mv dev-plugin-webui/dist dev-plugin-dist",
@@ -22,11 +22,27 @@ type ValuesOf<T extends object> = T[keyof T][];
22
22
  * A prepared statement returned by [`SQLiteDatabase.prepareAsync()`](#prepareasyncsource) or [`SQLiteDatabase.prepareSync()`](#preparesyncsource) that can be binded with parameters and executed.
23
23
  */
24
24
  export class SQLiteStatement {
25
+ /**
26
+ * The cursor that currently owns the underlying `sqlite3_stmt`. A prepared statement has exactly
27
+ * one cursor, so running the statement again invalidates the cursor of every earlier run.
28
+ */
29
+ private currentCursor: object | null = null;
30
+
25
31
  constructor(
26
32
  private readonly nativeDatabase: NativeDatabase,
27
33
  private readonly nativeStatement: NativeStatement
28
34
  ) {}
29
35
 
36
+ /**
37
+ * Make the run that just finished the owner of the statement cursor, and return a predicate
38
+ * that tells whether it still is.
39
+ */
40
+ private claimCursor(): () => boolean {
41
+ const cursor = {};
42
+ this.currentCursor = cursor;
43
+ return () => this.currentCursor === cursor;
44
+ }
45
+
30
46
  //#region Asynchronous API
31
47
 
32
48
  /**
@@ -51,7 +67,8 @@ export class SQLiteStatement {
51
67
  rawResult: false,
52
68
  lastInsertRowId,
53
69
  changes,
54
- }
70
+ },
71
+ this.claimCursor()
55
72
  );
56
73
  }
57
74
 
@@ -83,7 +100,8 @@ export class SQLiteStatement {
83
100
  rawResult: true,
84
101
  lastInsertRowId,
85
102
  changes,
86
- }
103
+ },
104
+ this.claimCursor()
87
105
  );
88
106
  }
89
107
 
@@ -133,7 +151,8 @@ export class SQLiteStatement {
133
151
  rawResult: false,
134
152
  lastInsertRowId,
135
153
  changes,
136
- }
154
+ },
155
+ this.claimCursor()
137
156
  );
138
157
  }
139
158
 
@@ -165,7 +184,8 @@ export class SQLiteStatement {
165
184
  rawResult: true,
166
185
  lastInsertRowId,
167
186
  changes,
168
- }
187
+ },
188
+ this.claimCursor()
169
189
  );
170
190
  }
171
191
 
@@ -347,6 +367,12 @@ interface SQLiteExecuteResultOptions {
347
367
  changes: number;
348
368
  }
349
369
 
370
+ const SUPERSEDED_CURSOR_MESSAGE =
371
+ 'This result is no longer readable because the prepared statement ran again. ' +
372
+ 'A prepared statement holds a single SQLite cursor, so a later run rebinds the parameters and moves that cursor, ' +
373
+ 'and this result would return the rows of the later run. ' +
374
+ 'Read a result to the end before you run the same statement again, or prepare a separate statement for each reader.';
375
+
350
376
  /**
351
377
  * Create the `SQLiteExecuteAsyncResult` instance.
352
378
  *
@@ -357,13 +383,15 @@ async function createSQLiteExecuteAsyncResult<T>(
357
383
  database: SQLiteAnyDatabase,
358
384
  statement: NativeStatement,
359
385
  firstRowValues: SQLiteColumnValues | null,
360
- options: SQLiteExecuteResultOptions
386
+ options: SQLiteExecuteResultOptions,
387
+ isCursorOwner: () => boolean
361
388
  ): Promise<SQLiteExecuteAsyncResult<T>> {
362
389
  const instance = new SQLiteExecuteAsyncResultImpl<T>(
363
390
  database,
364
391
  statement,
365
392
  firstRowValues ? processNativeRow(firstRowValues) : null,
366
- options
393
+ options,
394
+ isCursorOwner
367
395
  );
368
396
  const generator = instance.generatorAsync();
369
397
  Object.defineProperties(generator, {
@@ -404,13 +432,15 @@ function createSQLiteExecuteSyncResult<T>(
404
432
  database: SQLiteAnyDatabase,
405
433
  statement: NativeStatement,
406
434
  firstRowValues: SQLiteColumnValues | null,
407
- options: SQLiteExecuteResultOptions
435
+ options: SQLiteExecuteResultOptions,
436
+ isCursorOwner: () => boolean
408
437
  ): SQLiteExecuteSyncResult<T> {
409
438
  const instance = new SQLiteExecuteSyncResultImpl<T>(
410
439
  database,
411
440
  statement,
412
441
  firstRowValues ? processNativeRow(firstRowValues) : firstRowValues,
413
- options
442
+ options,
443
+ isCursorOwner
414
444
  );
415
445
  const generator = instance.generatorSync();
416
446
  Object.defineProperties(generator, {
@@ -452,9 +482,17 @@ class SQLiteExecuteAsyncResultImpl<T> {
452
482
  private readonly database: SQLiteAnyDatabase,
453
483
  private readonly statement: NativeStatement,
454
484
  private firstRowValues: SQLiteColumnValues | null,
455
- public readonly options: SQLiteExecuteResultOptions
485
+ public readonly options: SQLiteExecuteResultOptions,
486
+ private readonly isCursorOwner: () => boolean
456
487
  ) {}
457
488
 
489
+ /** Throw rather than step a cursor that a later run of the same statement has taken over. */
490
+ private assertCursorOwner() {
491
+ if (!this.isCursorOwner()) {
492
+ throw new Error(SUPERSEDED_CURSOR_MESSAGE);
493
+ }
494
+ }
495
+
458
496
  async getFirstAsync(): Promise<T | null> {
459
497
  if (this.isStepCalled) {
460
498
  throw new Error(
@@ -467,6 +505,7 @@ class SQLiteExecuteAsyncResultImpl<T> {
467
505
  if (firstRowValues != null) {
468
506
  return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);
469
507
  }
508
+ this.assertCursorOwner();
470
509
  const firstRow = await this.statement.stepAsync(this.database);
471
510
  return firstRow != null
472
511
  ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))
@@ -486,9 +525,10 @@ class SQLiteExecuteAsyncResultImpl<T> {
486
525
  return [];
487
526
  }
488
527
  const columnNames = await this.getColumnNamesAsync();
528
+ this.assertCursorOwner();
489
529
  const nativeRows = await this.statement.getAllAsync(this.database);
490
530
  const allRows = processNativeRows(nativeRows);
491
- if (firstRowValues != null && firstRowValues.length > 0) {
531
+ if (firstRowValues.length > 0) {
492
532
  return composeRowsIfNeeded<T>(this.options.rawResult, columnNames, [
493
533
  firstRowValues,
494
534
  ...allRows,
@@ -507,6 +547,7 @@ class SQLiteExecuteAsyncResultImpl<T> {
507
547
 
508
548
  let result;
509
549
  do {
550
+ this.assertCursorOwner();
510
551
  result = await this.statement.stepAsync(this.database);
511
552
  if (result != null) {
512
553
  yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));
@@ -514,10 +555,11 @@ class SQLiteExecuteAsyncResultImpl<T> {
514
555
  } while (result != null);
515
556
  }
516
557
 
517
- resetAsync(): Promise<void> {
518
- const result = this.statement.resetAsync(this.database);
558
+ async resetAsync(): Promise<void> {
559
+ // Resetting a superseded result would rewind the cursor of the run that owns it now.
560
+ this.assertCursorOwner();
561
+ await this.statement.resetAsync(this.database);
519
562
  this.isStepCalled = false;
520
- return result;
521
563
  }
522
564
 
523
565
  private popFirstRowValues(): SQLiteColumnValues | null {
@@ -545,9 +587,17 @@ class SQLiteExecuteSyncResultImpl<T> {
545
587
  private readonly database: SQLiteAnyDatabase,
546
588
  private readonly statement: NativeStatement,
547
589
  private firstRowValues: SQLiteColumnValues | null,
548
- public readonly options: SQLiteExecuteResultOptions
590
+ public readonly options: SQLiteExecuteResultOptions,
591
+ private readonly isCursorOwner: () => boolean
549
592
  ) {}
550
593
 
594
+ /** Throw rather than step a cursor that a later run of the same statement has taken over. */
595
+ private assertCursorOwner() {
596
+ if (!this.isCursorOwner()) {
597
+ throw new Error(SUPERSEDED_CURSOR_MESSAGE);
598
+ }
599
+ }
600
+
551
601
  getFirstSync(): T | null {
552
602
  if (this.isStepCalled) {
553
603
  throw new Error(
@@ -559,6 +609,7 @@ class SQLiteExecuteSyncResultImpl<T> {
559
609
  if (firstRowValues != null) {
560
610
  return composeRowIfNeeded<T>(this.options.rawResult, columnNames, firstRowValues);
561
611
  }
612
+ this.assertCursorOwner();
562
613
  const firstRow = this.statement.stepSync(this.database);
563
614
  return firstRow != null
564
615
  ? composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(firstRow))
@@ -577,6 +628,7 @@ class SQLiteExecuteSyncResultImpl<T> {
577
628
  return [];
578
629
  }
579
630
  const columnNames = this.getColumnNamesSync();
631
+ this.assertCursorOwner();
580
632
  const nativeRows = this.statement.getAllSync(this.database);
581
633
  const allRows = processNativeRows(nativeRows);
582
634
  if (firstRowValues != null && firstRowValues.length > 0) {
@@ -596,6 +648,7 @@ class SQLiteExecuteSyncResultImpl<T> {
596
648
  }
597
649
  let result;
598
650
  do {
651
+ this.assertCursorOwner();
599
652
  result = this.statement.stepSync(this.database);
600
653
  if (result != null) {
601
654
  yield composeRowIfNeeded<T>(this.options.rawResult, columnNames, processNativeRow(result));
@@ -604,9 +657,10 @@ class SQLiteExecuteSyncResultImpl<T> {
604
657
  }
605
658
 
606
659
  resetSync(): void {
607
- const result = this.statement.resetSync(this.database);
660
+ // Resetting a superseded result would rewind the cursor of the run that owns it now.
661
+ this.assertCursorOwner();
662
+ this.statement.resetSync(this.database);
608
663
  this.isStepCalled = false;
609
- return result;
610
664
  }
611
665
 
612
666
  private popFirstRowValues(): SQLiteColumnValues | null {
@@ -1 +0,0 @@
1
- b8f668275e3ec93cff367011da2b3ae7bd83f43a690ce56473395ba6284c8b7c
@@ -1 +0,0 @@
1
- 3b63d91aadb7a09514fc8fb158bb08caf92b6108cbc0876893b1a7a3fd33c1a4934c3b7912a858404f0a0eac7b854572fa90c90b8c93b9b52bde2204dcdab735
@@ -1 +0,0 @@
1
- 87f1f42b8d635fff98edf78cf7a123628dc369e0
@@ -1 +0,0 @@
1
- df1da5f5381b01deb84c69e946436e98f69fb7a3c3f55c03b01e88061fd88e4d
@@ -1 +0,0 @@
1
- 97b9f3c849ecda169a14bd40502d11b42a7db55e98a1ac3a33391a720bdac4748fd4e7fe190c1ab77c37aada7d932f7b587efa141949d4f4f281959e5e1a2475
@@ -1 +0,0 @@
1
- ee3f075f3c6a0fd48956f50476ba6b9b2c53dfe35b19cce7f8e1976a1edb57a7
@@ -1 +0,0 @@
1
- 7072e77137d8d04d74c12cc050c55aad54854784349d7810b257b6cf8ea13dc94c885edd53532403ffa546d5f0d65623bb42340f7466e6f9b0442c6cc1b01d3a
@@ -1 +0,0 @@
1
- 2d42be1f6cf0cb586196d93f920c8c780f4635d9
@@ -1 +0,0 @@
1
- 3af19f382afed8dd75aec53c44bf8e83edc810d919cb7603b9c70e055314bf85
@@ -1 +0,0 @@
1
- 2ad35fe02f25b6a226941470aa67c2027318609b7ec156d61d77837bbdc8811de072fd24692a4577419b2fb1350e23377e031f82b9c835202b42ef14da542ca4