@crvouga/sqlite-mem 0.2.0 → 1.1.0

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.
package/dist/index.js CHANGED
@@ -2,18 +2,21 @@
2
2
  var SqliteError = class extends Error {
3
3
  /** Coarse error class (constraint vs syntax vs missing object, …). */
4
4
  category;
5
- /** Optional SQLite result-code name such as `SQLITE_CONSTRAINT`. */
5
+ /** SQLite result-code name such as `SQLITE_CONSTRAINT_UNIQUE`. */
6
6
  sqliteCode;
7
+ /** Same value as {@link sqliteCode} (Node `err.code` convention). */
8
+ code;
7
9
  /**
8
10
  * @param message - Human-readable error text.
9
11
  * @param category - Coarse class; defaults to `"other"`.
10
- * @param sqliteCode - Optional SQLite result-code name.
12
+ * @param sqliteCode - SQLite result-code name; defaults to `"SQLITE_ERROR"`.
11
13
  */
12
- constructor(message, category = "other", sqliteCode) {
14
+ constructor(message, category = "other", sqliteCode = "SQLITE_ERROR") {
13
15
  super(message);
14
16
  this.name = "SqliteError";
15
17
  this.category = category;
16
18
  this.sqliteCode = sqliteCode;
19
+ this.code = sqliteCode;
17
20
  }
18
21
  };
19
22
  var TriggerRaiseError = class extends SqliteError {
@@ -2396,17 +2399,6 @@ var Prng = class _Prng {
2396
2399
  return copy;
2397
2400
  }
2398
2401
  };
2399
- function deriveSeed(...parts) {
2400
- let hash = 2166136261;
2401
- for (const part of parts) {
2402
- const text2 = String(part);
2403
- for (let i = 0; i < text2.length; i++) {
2404
- hash ^= text2.charCodeAt(i);
2405
- hash = Math.imul(hash, 16777619);
2406
- }
2407
- }
2408
- return hash | 0;
2409
- }
2410
2402
 
2411
2403
  // src/types/value.ts
2412
2404
  var SqlReal = class {
@@ -8733,7 +8725,7 @@ function decodeDatabaseState(snapshot) {
8733
8725
  throw new SqliteError("invalid sqlite-mem snapshot magic", "other");
8734
8726
  const version = reader.u32();
8735
8727
  if (version !== VERSION && version !== VERSION_V1) {
8736
- throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "unsupported");
8728
+ throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "snapshot_version", "SQLITE_FORMAT");
8737
8729
  }
8738
8730
  const state = new DatabaseState();
8739
8731
  state.foreignKeysEnabled = reader.u8() !== 0;
@@ -8989,16 +8981,14 @@ var ExecutionEnv = class {
8989
8981
  }
8990
8982
  getBoundParameter(name) {
8991
8983
  if (typeof name === "number") {
8992
- if (name < 1 || name > this.positional.length)
8993
- throw new SqliteError(`binding parameter ${name} is not supplied`, "misuse");
8984
+ if (name < 1 || name > this.positional.length) return null;
8994
8985
  return this.positional[name - 1];
8995
8986
  }
8996
8987
  const key = name.toLowerCase();
8997
- const value = this.named.get(key);
8998
- if (value === void 0 && !this.named.has(key)) {
8999
- throw new SqliteError(`binding parameter :${name} is not supplied`, "misuse");
8988
+ if (!this.named.has(key)) {
8989
+ return null;
9000
8990
  }
9001
- return value ?? null;
8991
+ return this.named.get(key) ?? null;
9002
8992
  }
9003
8993
  setNamed(name, value) {
9004
8994
  this.named.set(name.toLowerCase(), toSqlValue(value));
@@ -9086,7 +9076,7 @@ var ExecutionEnv = class {
9086
9076
  const result = this.selectRunner(select, this, context);
9087
9077
  return {
9088
9078
  columns: result.columns,
9089
- rows: result.values?.map((row2) => [...row2]) ?? result.rows.map((record) => result.columns.map((column) => record[column] ?? null))
9079
+ rows: result.values.length > 0 ? result.values.map((row2) => [...row2]) : result.rows.map((record) => result.columns.map((column) => record[column] ?? null))
9090
9080
  };
9091
9081
  },
9092
9082
  matchFts: (table, column, query) => {
@@ -9114,14 +9104,29 @@ function toSqlValue(value) {
9114
9104
  }
9115
9105
  if (typeof value === "boolean") return value ? 1 : 0;
9116
9106
  if (value instanceof SqlReal || value instanceof SqlJsonText) return value;
9117
- if (value instanceof Uint8Array) return new Uint8Array(value);
9107
+ if (value instanceof Uint8Array) {
9108
+ if (isSharedArrayBufferView(value)) {
9109
+ throw new SqliteError("cannot bind SharedArrayBuffer-backed buffers; copy into a Uint8Array first", "misuse");
9110
+ }
9111
+ return new Uint8Array(value);
9112
+ }
9118
9113
  if (value instanceof ArrayBuffer) return new Uint8Array(value);
9114
+ if (typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer) {
9115
+ throw new SqliteError("cannot bind SharedArrayBuffer; copy into an ArrayBuffer or Uint8Array first", "misuse");
9116
+ }
9117
+ if (ArrayBuffer.isView(value)) {
9118
+ const kind = Object.prototype.toString.call(value).slice(8, -1);
9119
+ throw new SqliteError(`cannot bind ${kind}; only Uint8Array and ArrayBuffer are accepted as BLOB values`, "misuse");
9120
+ }
9119
9121
  throw new SqliteError(`unsupported bind value: ${typeof value}`, "datatype_mismatch");
9120
9122
  }
9123
+ function isSharedArrayBufferView(view) {
9124
+ return typeof SharedArrayBuffer !== "undefined" && view.buffer instanceof SharedArrayBuffer;
9125
+ }
9121
9126
 
9122
9127
  // src/executor/result.ts
9123
9128
  function emptyResult(changes = 0, lastInsertRowid = 0) {
9124
- return { columns: [], rows: [], changes, lastInsertRowid };
9129
+ return { columns: [], rows: [], values: [], changes, lastInsertRowid };
9125
9130
  }
9126
9131
  function exportSqlValue(value) {
9127
9132
  if (isSqlReal(value)) return value.value;
@@ -9133,7 +9138,7 @@ function valuesToResult(columns, values, changes = 0, lastInsertRowid = 0, optio
9133
9138
  const keepValues = options?.keepValues !== false;
9134
9139
  return {
9135
9140
  columns,
9136
- values: keepValues ? values.map((row) => row.map(exportSqlValue)) : void 0,
9141
+ values: keepValues ? values.map((row) => row.map(exportSqlValue)) : [],
9137
9142
  rows: named ? values.map((row) => {
9138
9143
  const object = {};
9139
9144
  for (let index = 0; index < columns.length; index++) {
@@ -9146,7 +9151,10 @@ function valuesToResult(columns, values, changes = 0, lastInsertRowid = 0, optio
9146
9151
  };
9147
9152
  }
9148
9153
  function resultValues(result) {
9149
- return result.values?.map((row) => [...row]) ?? result.rows.map((row) => result.columns.map((column) => row[column] ?? null));
9154
+ if (result.values.length > 0 || result.rows.length === 0) {
9155
+ return result.values.map((row) => [...row]);
9156
+ }
9157
+ return result.rows.map((row) => result.columns.map((column) => row[column] ?? null));
9150
9158
  }
9151
9159
 
9152
9160
  // src/executor/attach.ts
@@ -9182,8 +9190,579 @@ function executeDetach(stmt, env) {
9182
9190
  return emptyResult(0, env.state.lastInsertRowid);
9183
9191
  }
9184
9192
 
9185
- // src/functions/table-valued.ts
9193
+ // src/functions/window.ts
9194
+ function rowsEqual(left, right) {
9195
+ if (left.length !== right.length) return false;
9196
+ return left.every((value, index) => {
9197
+ const other = right[index];
9198
+ return value === null && other === null || other !== void 0 && compareSql(value, other) === 0;
9199
+ });
9200
+ }
9201
+ function rowNumber(_partition, index) {
9202
+ return index + 1;
9203
+ }
9204
+ function rank(partition, index, orderKeys = partition) {
9205
+ if (index <= 0) return 1;
9206
+ let firstPeer = index;
9207
+ while (firstPeer > 0 && rowsEqual(orderKeys[firstPeer], orderKeys[firstPeer - 1])) firstPeer--;
9208
+ return firstPeer + 1;
9209
+ }
9210
+ function denseRank(partition, index, orderKeys = partition) {
9211
+ if (index <= 0) return 1;
9212
+ let result = 1;
9213
+ for (let i = 1; i <= index; i++) {
9214
+ if (!rowsEqual(orderKeys[i], orderKeys[i - 1])) result++;
9215
+ }
9216
+ return result;
9217
+ }
9218
+ function lag(partition, index, valueIndex = 0, offset = 1, defaultValue = null) {
9219
+ const target = index - Math.max(0, Math.trunc(offset));
9220
+ return target < 0 ? defaultValue : partition[target]?.[valueIndex] ?? null;
9221
+ }
9222
+ function lead(partition, index, valueIndex = 0, offset = 1, defaultValue = null) {
9223
+ const target = index + Math.max(0, Math.trunc(offset));
9224
+ return target >= partition.length ? defaultValue : partition[target]?.[valueIndex] ?? null;
9225
+ }
9226
+ function firstValue(partition, valueIndex = 0, frameStart = 0) {
9227
+ return partition[frameStart]?.[valueIndex] ?? null;
9228
+ }
9229
+ function lastValue(partition, valueIndex = 0, frameEnd = partition.length - 1) {
9230
+ return partition[frameEnd]?.[valueIndex] ?? null;
9231
+ }
9232
+ function nthValue(partition, n, valueIndex = 0, frameStart = 0) {
9233
+ const offset = Math.trunc(n);
9234
+ if (offset <= 0) return null;
9235
+ return partition[frameStart + offset - 1]?.[valueIndex] ?? null;
9236
+ }
9237
+ var windowFunctions = {
9238
+ row_number: rowNumber,
9239
+ rank,
9240
+ dense_rank: denseRank,
9241
+ lag,
9242
+ lead,
9243
+ first_value: firstValue,
9244
+ last_value: lastValue,
9245
+ nth_value: nthValue,
9246
+ ntile: () => 0,
9247
+ cume_dist: () => 0,
9248
+ percent_rank: () => 0
9249
+ };
9250
+
9251
+ // src/executor/pragma-engine.ts
9252
+ var PRAGMA_TVF_NAMES = [
9253
+ "analysis_limit",
9254
+ "application_id",
9255
+ "auto_vacuum",
9256
+ "automatic_index",
9257
+ "busy_timeout",
9258
+ "cache_size",
9259
+ "cache_spill",
9260
+ "cell_size_check",
9261
+ "checkpoint_fullfsync",
9262
+ "collation_list",
9263
+ "compile_options",
9264
+ "count_changes",
9265
+ "data_version",
9266
+ "database_list",
9267
+ "default_cache_size",
9268
+ "defer_foreign_keys",
9269
+ "empty_result_callbacks",
9270
+ "encoding",
9271
+ "foreign_key_check",
9272
+ "foreign_key_list",
9273
+ "foreign_keys",
9274
+ "freelist_count",
9275
+ "full_column_names",
9276
+ "fullfsync",
9277
+ "function_list",
9278
+ "hard_heap_limit",
9279
+ "ignore_check_constraints",
9280
+ "index_info",
9281
+ "index_list",
9282
+ "index_xinfo",
9283
+ "integrity_check",
9284
+ "journal_mode",
9285
+ "journal_size_limit",
9286
+ "legacy_alter_table",
9287
+ "locking_mode",
9288
+ "max_page_count",
9289
+ "module_list",
9290
+ "optimize",
9291
+ "page_count",
9292
+ "page_size",
9293
+ "pragma_list",
9294
+ "query_only",
9295
+ "quick_check",
9296
+ "read_uncommitted",
9297
+ "recursive_triggers",
9298
+ "reverse_unordered_selects",
9299
+ "schema_version",
9300
+ "secure_delete",
9301
+ "short_column_names",
9302
+ "soft_heap_limit",
9303
+ "synchronous",
9304
+ "table_info",
9305
+ "table_list",
9306
+ "table_xinfo",
9307
+ "temp_store",
9308
+ "threads",
9309
+ "trusted_schema",
9310
+ "user_version",
9311
+ "writable_schema"
9312
+ ];
9313
+ var PRAGMA_LIST_NAMES = [
9314
+ "activate_extensions",
9315
+ ...PRAGMA_TVF_NAMES,
9316
+ "case_sensitive_like",
9317
+ "hexkey",
9318
+ "hexrekey",
9319
+ "incremental_vacuum",
9320
+ "key",
9321
+ "lock_proxy_file",
9322
+ "mmap_size",
9323
+ "rekey",
9324
+ "shrink_memory",
9325
+ "temp_store_directory",
9326
+ "textkey",
9327
+ "textrekey",
9328
+ "wal_autocheckpoint",
9329
+ "wal_checkpoint"
9330
+ ].sort((a, b) => a.localeCompare(b));
9331
+ var MEMORY_VTABLE_MODULES = [
9332
+ "bytecode",
9333
+ "dbstat",
9334
+ "fts3",
9335
+ "fts3tokenize",
9336
+ "fts4",
9337
+ "fts4aux",
9338
+ "fts5",
9339
+ "fts5vocab",
9340
+ "json_each",
9341
+ "json_tree",
9342
+ "rtree",
9343
+ "rtree_i32",
9344
+ "tables_used"
9345
+ ];
9346
+ var COMPILE_OPTIONS2 = [
9347
+ "COMPILER=typescript",
9348
+ "ENABLE_FTS3",
9349
+ "ENABLE_FTS4",
9350
+ "ENABLE_FTS5",
9351
+ "ENABLE_JSON1",
9352
+ "ENABLE_RTREE",
9353
+ "THREADSAFE=0"
9354
+ ];
9355
+ var STORAGE_DEFAULTS = {
9356
+ analysis_limit: { column: "analysis_limit", value: 0 },
9357
+ application_id: { column: "application_id", value: 0 },
9358
+ auto_vacuum: { column: "auto_vacuum", value: 0 },
9359
+ automatic_index: { column: "automatic_index", value: 1 },
9360
+ busy_timeout: { column: "timeout", value: 0 },
9361
+ cache_size: { column: "cache_size", value: 2e3 },
9362
+ cache_spill: { column: "cache_spill", value: 2e4 },
9363
+ cell_size_check: { column: "cell_size_check", value: 0 },
9364
+ checkpoint_fullfsync: { column: "checkpoint_fullfsync", value: 1 },
9365
+ count_changes: { column: "count_changes", value: 0 },
9366
+ data_version: { column: "data_version", value: 1 },
9367
+ default_cache_size: { column: "cache_size", value: 2e3 },
9368
+ defer_foreign_keys: { column: "defer_foreign_keys", value: 0 },
9369
+ empty_result_callbacks: { column: "empty_result_callbacks", value: 0 },
9370
+ encoding: { column: "encoding", value: "UTF-8" },
9371
+ freelist_count: { column: "freelist_count", value: 0 },
9372
+ full_column_names: { column: "full_column_names", value: 0 },
9373
+ fullfsync: { column: "fullfsync", value: 0 },
9374
+ hard_heap_limit: { column: "hard_heap_limit", value: 0 },
9375
+ ignore_check_constraints: { column: "ignore_check_constraints", value: 0 },
9376
+ journal_mode: { column: "journal_mode", value: "memory" },
9377
+ journal_size_limit: { column: "journal_size_limit", value: 32768 },
9378
+ legacy_alter_table: { column: "legacy_alter_table", value: 1 },
9379
+ locking_mode: { column: "locking_mode", value: "normal" },
9380
+ max_page_count: { column: "max_page_count", value: 1073741823 },
9381
+ page_size: { column: "page_size", value: 4096 },
9382
+ query_only: { column: "query_only", value: 0 },
9383
+ read_uncommitted: { column: "read_uncommitted", value: 0 },
9384
+ recursive_triggers: { column: "recursive_triggers", value: 0 },
9385
+ reverse_unordered_selects: { column: "reverse_unordered_selects", value: 0 },
9386
+ secure_delete: { column: "secure_delete", value: 2 },
9387
+ short_column_names: { column: "short_column_names", value: 1 },
9388
+ soft_heap_limit: { column: "soft_heap_limit", value: 0 },
9389
+ synchronous: { column: "synchronous", value: 2 },
9390
+ temp_store: { column: "temp_store", value: 0 },
9391
+ threads: { column: "threads", value: 0 },
9392
+ trusted_schema: { column: "trusted_schema", value: 1 },
9393
+ writable_schema: { column: "writable_schema", value: 0 }
9394
+ };
9395
+ function isPragmaTvfName(name) {
9396
+ const lower = name.toLowerCase();
9397
+ if (PRAGMA_TVF_NAMES.includes(lower)) return true;
9398
+ if (lower.startsWith("pragma_")) {
9399
+ return PRAGMA_TVF_NAMES.includes(lower.slice("pragma_".length));
9400
+ }
9401
+ return false;
9402
+ }
9403
+ function normalizePragmaKey(name) {
9404
+ const lower = name.toLowerCase();
9405
+ if (PRAGMA_TVF_NAMES.includes(lower)) return lower;
9406
+ if (lower.startsWith("pragma_")) {
9407
+ const stripped = lower.slice("pragma_".length);
9408
+ if (PRAGMA_TVF_NAMES.includes(stripped)) return stripped;
9409
+ return stripped;
9410
+ }
9411
+ return lower;
9412
+ }
9413
+ function queryPragma(name, args, env) {
9414
+ const key = normalizePragmaKey(name);
9415
+ switch (key) {
9416
+ case "foreign_keys":
9417
+ return single("foreign_keys", env.state.foreignKeysEnabled ? 1 : 0);
9418
+ case "user_version":
9419
+ return single("user_version", env.state.userVersion);
9420
+ case "schema_version":
9421
+ return single("schema_version", env.state.schemaVersion);
9422
+ case "table_info":
9423
+ return pragmaTableInfo(args, env, false);
9424
+ case "table_xinfo":
9425
+ return pragmaTableInfo(args, env, true);
9426
+ case "index_list":
9427
+ return pragmaIndexList(args, env);
9428
+ case "index_info":
9429
+ return pragmaIndexInfo(args, env, false);
9430
+ case "index_xinfo":
9431
+ return pragmaIndexInfo(args, env, true);
9432
+ case "foreign_key_list":
9433
+ return pragmaForeignKeyList(args, env);
9434
+ case "foreign_key_check":
9435
+ return pragmaForeignKeyCheck(args, env);
9436
+ case "database_list":
9437
+ return pragmaDatabaseList(env);
9438
+ case "table_list":
9439
+ return pragmaTableList(env);
9440
+ case "collation_list":
9441
+ return {
9442
+ columns: ["seq", "name"],
9443
+ rows: [
9444
+ [0, "RTRIM"],
9445
+ [1, "NOCASE"],
9446
+ [2, "BINARY"]
9447
+ ]
9448
+ };
9449
+ case "compile_options":
9450
+ return { columns: ["compile_options"], rows: COMPILE_OPTIONS2.map((opt) => [opt]) };
9451
+ case "function_list":
9452
+ return pragmaFunctionList();
9453
+ case "module_list":
9454
+ return pragmaModuleList();
9455
+ case "pragma_list":
9456
+ return { columns: ["name"], rows: PRAGMA_LIST_NAMES.map((n) => [n]) };
9457
+ case "integrity_check":
9458
+ case "quick_check":
9459
+ return single(key, "ok");
9460
+ case "optimize":
9461
+ return { columns: ["optimize"], rows: [] };
9462
+ case "page_count":
9463
+ return single("page_count", estimatePageCount(env));
9464
+ default: {
9465
+ const storage = STORAGE_DEFAULTS[key];
9466
+ if (storage) return single(storage.column, storage.value);
9467
+ return { columns: [], rows: [] };
9468
+ }
9469
+ }
9470
+ }
9471
+ function single(column, value) {
9472
+ return { columns: [column], rows: [[value]] };
9473
+ }
9474
+ function estimatePageCount(env) {
9475
+ const objects = env.state.tables.size + env.state.indexes.size + env.state.views.size + env.state.virtualTables.size;
9476
+ return objects === 0 ? 0 : Math.max(1, objects);
9477
+ }
9478
+ function pragmaTableInfo(args, env, xinfo) {
9479
+ const tableName = requireNameArg(args, "table_info");
9480
+ const table = env.state.tables.get(tableName.toLowerCase());
9481
+ if (!table) return { columns: xinfoColumns(xinfo), rows: [] };
9482
+ const rows = table.columns.map((column, cid) => {
9483
+ const pkIndex = table.columns.filter((c) => c.primaryKey).findIndex((c) => c.name === column.name);
9484
+ const pk = column.primaryKey ? pkIndex >= 0 ? pkIndex + 1 : 1 : 0;
9485
+ const dflt = column.defaultExpr ? defaultLiteral(column.defaultExpr) : null;
9486
+ const base = [cid, column.name, column.typeName ?? "", column.notNull ? 1 : 0, dflt, pk];
9487
+ if (xinfo) {
9488
+ let hidden = 0;
9489
+ if (column.generated && !column.generated.stored) hidden = 2;
9490
+ if (column.generated?.stored) hidden = 3;
9491
+ base.push(hidden);
9492
+ }
9493
+ return base;
9494
+ });
9495
+ return { columns: xinfoColumns(xinfo), rows };
9496
+ }
9497
+ function xinfoColumns(xinfo) {
9498
+ return xinfo ? ["cid", "name", "type", "notnull", "dflt_value", "pk", "hidden"] : ["cid", "name", "type", "notnull", "dflt_value", "pk"];
9499
+ }
9500
+ function defaultLiteral(expr) {
9501
+ if (expr.type === "literal")
9502
+ return typeof expr.value === "string" ? `'${expr.value.replace(/'/g, "''")}'` : expr.value;
9503
+ if (expr.type === "null") return "NULL";
9504
+ return null;
9505
+ }
9506
+ function pragmaIndexList(args, env) {
9507
+ const tableName = requireNameArg(args, "index_list");
9508
+ const table = env.state.tables.get(tableName.toLowerCase());
9509
+ if (!table) return { columns: ["seq", "name", "unique", "origin", "partial"], rows: [] };
9510
+ const rows = [];
9511
+ let seq = 0;
9512
+ for (const name of table.indexes) {
9513
+ const index = env.state.indexes.get(name.toLowerCase());
9514
+ if (!index) continue;
9515
+ rows.push([seq++, index.name, index.unique ? 1 : 0, indexOrigin(index), index.where ? 1 : 0]);
9516
+ }
9517
+ return { columns: ["seq", "name", "unique", "origin", "partial"], rows };
9518
+ }
9519
+ function indexOrigin(index) {
9520
+ if (index.originalSql) return "c";
9521
+ if (index.name.toLowerCase().startsWith("sqlite_autoindex_") && index.unique) return "u";
9522
+ return "c";
9523
+ }
9524
+ function pragmaIndexInfo(args, env, xinfo) {
9525
+ const indexName = requireNameArg(args, "index_info");
9526
+ const index = env.state.indexes.get(indexName.toLowerCase());
9527
+ const columns = xinfo ? ["seqno", "cid", "name", "desc", "coll", "key"] : ["seqno", "cid", "name"];
9528
+ if (!index) return { columns, rows: [] };
9529
+ const table = env.state.tables.get(index.tableName.toLowerCase());
9530
+ const rows = index.columns.map((column, seqno) => {
9531
+ const cid = table?.columns.findIndex((c) => c.name.toLowerCase() === column.name.toLowerCase()) ?? -1;
9532
+ const base = [seqno, cid, column.name];
9533
+ if (xinfo) {
9534
+ base.push(column.order === "DESC" ? 1 : 0, (column.collate ?? "BINARY").toUpperCase(), 1);
9535
+ }
9536
+ return base;
9537
+ });
9538
+ if (xinfo) {
9539
+ rows.push([index.columns.length, -1, null, 0, "BINARY", 0]);
9540
+ }
9541
+ return { columns, rows };
9542
+ }
9543
+ function pragmaForeignKeyList(args, env) {
9544
+ const tableName = requireNameArg(args, "foreign_key_list");
9545
+ const table = env.state.tables.get(tableName.toLowerCase());
9546
+ const columns = ["id", "seq", "table", "from", "to", "on_update", "on_delete", "match"];
9547
+ if (!table) return { columns, rows: [] };
9548
+ const rows = [];
9549
+ let id = 0;
9550
+ for (const constraint of table.constraints) {
9551
+ if (constraint.type !== "foreign_key") continue;
9552
+ const refColumns = constraint.refColumns ?? env.state.tables.get(constraint.refTable.toLowerCase())?.columns.filter((c) => c.primaryKey).map((c) => c.name) ?? [];
9553
+ constraint.columns.forEach((column, seq) => {
9554
+ rows.push([
9555
+ id,
9556
+ seq,
9557
+ constraint.refTable,
9558
+ column,
9559
+ refColumns[seq] ?? null,
9560
+ constraint.onUpdate ?? "NO ACTION",
9561
+ constraint.onDelete ?? "NO ACTION",
9562
+ "NONE"
9563
+ ]);
9564
+ });
9565
+ id++;
9566
+ }
9567
+ return { columns, rows };
9568
+ }
9569
+ function pragmaForeignKeyCheck(args, env) {
9570
+ const columns = ["table", "rowid", "parent", "fkid"];
9571
+ const filter = args[0] != null && args[0] !== null ? String(args[0]).toLowerCase() : null;
9572
+ const rows = [];
9573
+ for (const table of env.state.tables.values()) {
9574
+ if (filter && table.name.toLowerCase() !== filter) continue;
9575
+ let fkid = 0;
9576
+ for (const constraint of table.constraints) {
9577
+ if (constraint.type !== "foreign_key") continue;
9578
+ const parent = env.state.tables.get(constraint.refTable.toLowerCase());
9579
+ const refColumns = constraint.refColumns ?? parent?.columns.filter((c) => c.primaryKey).map((c) => c.name) ?? [];
9580
+ for (const row of table.scan()) {
9581
+ let allNull = true;
9582
+ const childValues = [];
9583
+ for (const col of constraint.columns) {
9584
+ const value = row.values.get(col.toLowerCase()) ?? null;
9585
+ childValues.push(value);
9586
+ if (value !== null) allNull = false;
9587
+ }
9588
+ if (allNull) continue;
9589
+ if (!parent || !parentHasMatch(parent, refColumns, childValues)) {
9590
+ rows.push([table.name, row.rowid, constraint.refTable, fkid]);
9591
+ }
9592
+ }
9593
+ fkid++;
9594
+ }
9595
+ }
9596
+ return { columns, rows };
9597
+ }
9598
+ function parentHasMatch(parent, refColumns, childValues) {
9599
+ if (refColumns.length === 0) return false;
9600
+ for (const row of parent.scan()) {
9601
+ let ok = true;
9602
+ for (let i = 0; i < refColumns.length; i++) {
9603
+ const parentVal = row.values.get(refColumns[i].toLowerCase()) ?? null;
9604
+ if (!sqlValuesEqual(parentVal, childValues[i] ?? null)) {
9605
+ ok = false;
9606
+ break;
9607
+ }
9608
+ }
9609
+ if (ok) return true;
9610
+ }
9611
+ return false;
9612
+ }
9613
+ function sqlValuesEqual(a, b) {
9614
+ if (a === null || b === null) return a === b;
9615
+ if (typeof a === "number" && typeof b === "number") return a === b;
9616
+ if (typeof a === "bigint" || typeof b === "bigint") {
9617
+ return BigInt(a) === BigInt(b);
9618
+ }
9619
+ if (a instanceof Uint8Array || b instanceof Uint8Array) return false;
9620
+ return String(a) === String(b);
9621
+ }
9622
+ function pragmaDatabaseList(env) {
9623
+ const rows = [[0, "main", ""]];
9624
+ let seq = 2;
9625
+ for (const [name, attached] of env.state.attached) {
9626
+ const file = attached.filename === ":memory:" ? "" : attached.filename;
9627
+ rows.push([seq++, name, file]);
9628
+ }
9629
+ return { columns: ["seq", "name", "file"], rows };
9630
+ }
9631
+ function pragmaTableList(env) {
9632
+ const columns = ["schema", "name", "type", "ncol", "wr", "strict"];
9633
+ const rows = [];
9634
+ for (const table of env.state.tables.values()) {
9635
+ rows.push(["main", table.name, "table", table.columns.length, table.withoutRowid ? 1 : 0, table.strict ? 1 : 0]);
9636
+ }
9637
+ for (const view of env.state.views.values()) {
9638
+ const ncol = view.columns?.length ?? 0;
9639
+ rows.push(["main", view.name, "view", ncol, 0, 0]);
9640
+ }
9641
+ for (const vt of env.state.virtualTables.values()) {
9642
+ rows.push(["main", vt.name, "virtual", vt.columns.length, 0, 0]);
9643
+ }
9644
+ rows.push(["main", "sqlite_schema", "table", 5, 0, 0]);
9645
+ rows.push(["temp", "sqlite_temp_schema", "table", 5, 0, 0]);
9646
+ for (const [schema] of env.state.attached) {
9647
+ rows.push([schema, "sqlite_schema", "table", 5, 0, 0]);
9648
+ }
9649
+ return { columns, rows };
9650
+ }
9651
+ function pragmaFunctionList() {
9652
+ const columns = ["name", "builtin", "type", "enc", "narg", "flags"];
9653
+ const rows = [];
9654
+ const add = (name, type, narg, flags) => {
9655
+ rows.push([name, 1, type, "utf8", narg, flags]);
9656
+ };
9657
+ for (const name of Object.keys(getScalarFunctions())) add(name, "s", -1, 2099200);
9658
+ for (const name of Object.keys(dateTimeFunctions)) add(name, "s", -1, 2099200);
9659
+ for (const name of Object.keys(jsonScalarFunctions)) add(name, "s", -1, 2099200);
9660
+ for (const name of Object.keys(mathFunctions)) add(name, "s", -1, 2099200);
9661
+ for (const name of Object.keys(ftsAuxFunctions)) add(name, "s", -1, 2099200);
9662
+ for (const name of Object.keys(rtreeAuxFunctions)) add(name, "s", -1, 2099200);
9663
+ for (const name of Object.keys(aggregateFunctions)) {
9664
+ add(name, "w", name === "count" ? 0 : 1, 2097152);
9665
+ if (name === "count") add(name, "w", 1, 2097152);
9666
+ }
9667
+ for (const name of Object.keys(jsonAggregateFunctions)) add(name, "w", -1, 2097152);
9668
+ for (const name of Object.keys(windowFunctions)) add(name, "w", -1, 2097152);
9669
+ for (const name of ["generate_series", "json_each", "json_tree"]) {
9670
+ add(name, "s", -1, 2099200);
9671
+ }
9672
+ rows.sort((a, b) => String(a[0]).localeCompare(String(b[0])) || Number(a[4]) - Number(b[4]));
9673
+ return { columns, rows };
9674
+ }
9675
+ function pragmaModuleList() {
9676
+ const names = /* @__PURE__ */ new Set([
9677
+ ...MEMORY_VTABLE_MODULES,
9678
+ ...PRAGMA_TVF_NAMES.map((n) => `pragma_${n}`),
9679
+ "generate_series",
9680
+ "json_each",
9681
+ "json_tree"
9682
+ ]);
9683
+ return {
9684
+ columns: ["name"],
9685
+ rows: [...names].sort((a, b) => a.localeCompare(b)).map((name) => [name])
9686
+ };
9687
+ }
9688
+ function requireNameArg(args, pragma) {
9689
+ if (args.length === 0 || args[0] == null) {
9690
+ throw new SqliteError(`missing pragma argument for ${pragma}`, "misuse");
9691
+ }
9692
+ const value = args[0];
9693
+ if (typeof value === "string") return value;
9694
+ if (typeof value === "number" || typeof value === "bigint") return String(value);
9695
+ throw new SqliteError(`invalid pragma argument for ${pragma}`, "misuse");
9696
+ }
9697
+ function evalPragmaArgs(expr, env) {
9698
+ if (expr === null) return [];
9699
+ if (expr.type === "column" && expr.table === null) return [expr.name];
9700
+ if (expr.type === "literal") return [expr.value];
9701
+ return [evalExpr(expr, env.createEvalContext())];
9702
+ }
9703
+ function evalPragmaSetValue(expr, env) {
9704
+ if (expr.type === "column" && expr.table === null) {
9705
+ const keyword = expr.name.toLowerCase();
9706
+ if (keyword === "on" || keyword === "true" || keyword === "yes") return 1;
9707
+ if (keyword === "off" || keyword === "false" || keyword === "no") return 0;
9708
+ return expr.name;
9709
+ }
9710
+ return evalExpr(expr, env.createEvalContext());
9711
+ }
9712
+ function coercePragmaInt(value) {
9713
+ if (typeof value === "number") return Math.trunc(value);
9714
+ if (typeof value === "bigint") return Number(value);
9715
+ if (typeof value === "string") {
9716
+ const n = Number.parseInt(value, 10);
9717
+ return Number.isFinite(n) ? n : 0;
9718
+ }
9719
+ const asInt = toInteger(value);
9720
+ return asInt === null ? 0 : typeof asInt === "bigint" ? Number(asInt) : asInt;
9721
+ }
9722
+ function coercePragmaTruthy(value) {
9723
+ return isTruthySql(value) === true;
9724
+ }
9725
+
9726
+ // src/functions/table-valued-registry.ts
9186
9727
  var registry = /* @__PURE__ */ new Map();
9728
+ function registerTableValuedFunction(name, fn) {
9729
+ registry.set(name.toLowerCase(), fn);
9730
+ }
9731
+ function getTableValuedFunction(name) {
9732
+ return registry.get(name.toLowerCase());
9733
+ }
9734
+ function hasRegisteredTableValuedFunction(name) {
9735
+ return registry.has(name.toLowerCase());
9736
+ }
9737
+
9738
+ // src/functions/pragma-tvf.ts
9739
+ function toTvfResult(alias, defaultName, columns, rows) {
9740
+ const table = alias ?? defaultName;
9741
+ return {
9742
+ columns,
9743
+ rows: rows.map((row) => ({
9744
+ cells: columns.map((name, index) => ({
9745
+ table,
9746
+ name,
9747
+ value: row[index] ?? null
9748
+ }))
9749
+ }))
9750
+ };
9751
+ }
9752
+ var registered = false;
9753
+ function ensurePragmaTvfsRegistered() {
9754
+ if (registered) return;
9755
+ registered = true;
9756
+ for (const baseName of PRAGMA_TVF_NAMES) {
9757
+ const tvfName = `pragma_${baseName}`;
9758
+ registerTableValuedFunction(tvfName, (args, alias, env) => {
9759
+ const result = queryPragma(baseName, args, env);
9760
+ return toTvfResult(alias, tvfName, result.columns, result.rows);
9761
+ });
9762
+ }
9763
+ }
9764
+
9765
+ // src/functions/table-valued.ts
9187
9766
  var JSON_TVF_COLUMNS = ["key", "value", "type", "atom", "id", "parent", "fullkey", "path"];
9188
9767
  function jsonTvfResult(alias, defaultName, rows) {
9189
9768
  const table = alias ?? defaultName;
@@ -9198,7 +9777,7 @@ function jsonTvfResult(alias, defaultName, rows) {
9198
9777
  }))
9199
9778
  };
9200
9779
  }
9201
- registry.set("generate_series", (args, alias) => {
9780
+ registerTableValuedFunction("generate_series", (args, alias) => {
9202
9781
  if (args.length < 2 || args.length > 3) {
9203
9782
  throw new SqliteError("wrong number of arguments to function generate_series()", "misuse");
9204
9783
  }
@@ -9229,13 +9808,13 @@ registry.set("generate_series", (args, alias) => {
9229
9808
  }
9230
9809
  return { columns: ["value"], rows };
9231
9810
  });
9232
- registry.set("json_each", (args, alias) => {
9811
+ registerTableValuedFunction("json_each", (args, alias) => {
9233
9812
  if (args.length < 1 || args.length > 2) {
9234
9813
  throw new SqliteError("wrong number of arguments to function json_each()", "misuse");
9235
9814
  }
9236
9815
  return jsonTvfResult(alias, "json_each", jsonEachRows(args[0], args[1]));
9237
9816
  });
9238
- registry.set("json_tree", (args, alias) => {
9817
+ registerTableValuedFunction("json_tree", (args, alias) => {
9239
9818
  if (args.length < 1 || args.length > 2) {
9240
9819
  throw new SqliteError("wrong number of arguments to function json_tree()", "misuse");
9241
9820
  }
@@ -9245,11 +9824,16 @@ function safeInt(value) {
9245
9824
  return value <= BigInt(Number.MAX_SAFE_INTEGER) && value >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(value) : value;
9246
9825
  }
9247
9826
  function evaluateTableFunction(name, args, alias, env, scope, parent) {
9248
- const fn = registry.get(name.toLowerCase());
9827
+ ensurePragmaTvfsRegistered();
9828
+ const fn = getTableValuedFunction(name);
9249
9829
  if (!fn) throw new SqliteError(`no such table-valued function: ${name}`, "no_such_table");
9250
9830
  const values = args.map((arg) => evalExpr(arg, env.createEvalContext(scope ?? null, parent)));
9251
9831
  return fn(values, alias, env);
9252
9832
  }
9833
+ function hasTableValuedFunction(name) {
9834
+ ensurePragmaTvfsRegistered();
9835
+ return hasRegisteredTableValuedFunction(name);
9836
+ }
9253
9837
 
9254
9838
  // src/schema/catalog.ts
9255
9839
  function schemaCatalogRows(state) {
@@ -9980,10 +10564,10 @@ function executeSelect2(stmt, env, parent) {
9980
10564
  rows = uniqueRows([...leftRows, ...rightRows]);
9981
10565
  break;
9982
10566
  case "INTERSECT":
9983
- rows = uniqueRows(leftRows).filter((row) => rightRows.some((other) => rowsEqual(row, other)));
10567
+ rows = uniqueRows(leftRows).filter((row) => rightRows.some((other) => rowsEqual2(row, other)));
9984
10568
  break;
9985
10569
  case "EXCEPT":
9986
- rows = uniqueRows(leftRows).filter((row) => !rightRows.some((other) => rowsEqual(row, other)));
10570
+ rows = uniqueRows(leftRows).filter((row) => !rightRows.some((other) => rowsEqual2(row, other)));
9987
10571
  break;
9988
10572
  }
9989
10573
  if (stmt.orderBy.length > 0) rows.sort((a, b) => compareCompoundRows(a, b, stmt.orderBy, base.columns));
@@ -10017,7 +10601,7 @@ function executeWith(stmt, env, parent) {
10017
10601
  env.ctes.set(key, valuesToResult(columns, delta));
10018
10602
  const nextResult = executeSelect2(cte.select.compound.select, env, parent);
10019
10603
  const candidates = resultValues(nextResult);
10020
- const additions = cte.select.compound.op === "UNION ALL" ? candidates : candidates.filter((row) => !accumulated.some((existing) => rowsEqual(existing, row)));
10604
+ const additions = cte.select.compound.op === "UNION ALL" ? candidates : candidates.filter((row) => !accumulated.some((existing) => rowsEqual2(existing, row)));
10021
10605
  if (additions.length === 0) break;
10022
10606
  accumulated = [...accumulated, ...additions];
10023
10607
  delta = additions;
@@ -10319,6 +10903,9 @@ function scanFrom(item, env, parent) {
10319
10903
  if (item.type === "table_func") {
10320
10904
  return evaluateTableFunction(item.name, item.args, item.alias, env).rows;
10321
10905
  }
10906
+ if (item.type === "table" && isPragmaTvfName(item.name) && hasTableValuedFunction(item.name.toLowerCase())) {
10907
+ return evaluateTableFunction(item.name, [], item.alias, env, null, parent).rows;
10908
+ }
10322
10909
  const alias = item.alias ?? item.name;
10323
10910
  const qualified = item.schema ? `${item.schema}.${item.name}` : item.name;
10324
10911
  const db = env.state.databaseForSchema(item.schema, qualified);
@@ -10491,6 +11078,14 @@ function shapeOf(item, env) {
10491
11078
  value: null
10492
11079
  }));
10493
11080
  }
11081
+ if (item.type === "table" && isPragmaTvfName(item.name) && hasTableValuedFunction(item.name.toLowerCase())) {
11082
+ const columns = evaluateTableFunction(item.name, [], item.alias, env).columns;
11083
+ return columns.map((name) => ({
11084
+ table: item.alias ?? item.name,
11085
+ name,
11086
+ value: null
11087
+ }));
11088
+ }
10494
11089
  const alias = item.alias ?? item.name;
10495
11090
  const qualified = item.schema ? `${item.schema}.${item.name}` : item.name;
10496
11091
  const db = env.state.databaseForSchema(item.schema, qualified);
@@ -10560,7 +11155,7 @@ function aggregateValue(expr, rows, env, parent) {
10560
11155
  const ctx = env.createEvalContext(row, parent);
10561
11156
  if (expr.filter && isTruthySql(evalExpr(expr.filter, ctx)) !== true) continue;
10562
11157
  const args = expr.args === "*" ? [] : expr.args.map((arg) => evalExpr(arg, ctx));
10563
- if (expr.distinct && seen.some((values) => rowsEqual(values, args))) continue;
11158
+ if (expr.distinct && seen.some((values) => rowsEqual2(values, args))) continue;
10564
11159
  seen.push(args);
10565
11160
  accumulator.step(args);
10566
11161
  }
@@ -10571,7 +11166,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10571
11166
  const currentCtx = env.createEvalContext(current, parent);
10572
11167
  const partitionKey = spec.partitionBy.map((item) => evalExpr(item, currentCtx));
10573
11168
  const partition = rows.filter(
10574
- (row) => rowsEqual(
11169
+ (row) => rowsEqual2(
10575
11170
  partitionKey,
10576
11171
  spec.partitionBy.map((item) => evalExpr(item, env.createEvalContext(row, parent)))
10577
11172
  )
@@ -10600,13 +11195,13 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10600
11195
  if (name === "row_number") return index + 1;
10601
11196
  if (name === "rank") {
10602
11197
  let first = index;
10603
- while (first > 0 && rowsEqual(orderKeys[first], orderKeys[first - 1])) first--;
11198
+ while (first > 0 && rowsEqual2(orderKeys[first], orderKeys[first - 1])) first--;
10604
11199
  return first + 1;
10605
11200
  }
10606
11201
  if (name === "dense_rank") {
10607
- let rank = 1;
10608
- for (let i = 1; i <= index; i++) if (!rowsEqual(orderKeys[i], orderKeys[i - 1])) rank++;
10609
- return rank;
11202
+ let rank2 = 1;
11203
+ for (let i = 1; i <= index; i++) if (!rowsEqual2(orderKeys[i], orderKeys[i - 1])) rank2++;
11204
+ return rank2;
10610
11205
  }
10611
11206
  const evaluated = args.map((arg) => evalExpr(arg, currentCtx));
10612
11207
  if (name === "lag" || name === "lead") {
@@ -10640,7 +11235,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10640
11235
  if (name === "cume_dist") {
10641
11236
  if (partition.length === 0) return null;
10642
11237
  let lastPeer = index;
10643
- while (lastPeer + 1 < partition.length && rowsEqual(orderKeys[lastPeer + 1], orderKeys[index])) {
11238
+ while (lastPeer + 1 < partition.length && rowsEqual2(orderKeys[lastPeer + 1], orderKeys[index])) {
10644
11239
  lastPeer++;
10645
11240
  }
10646
11241
  return (lastPeer + 1) / partition.length;
@@ -10648,7 +11243,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10648
11243
  if (name === "percent_rank") {
10649
11244
  if (partition.length <= 1) return 0;
10650
11245
  let first = index;
10651
- while (first > 0 && rowsEqual(orderKeys[first], orderKeys[first - 1])) first--;
11246
+ while (first > 0 && rowsEqual2(orderKeys[first], orderKeys[first - 1])) first--;
10652
11247
  return first / (partition.length - 1);
10653
11248
  }
10654
11249
  throw new SqliteError(`no such window function: ${expr.func.name}`, "other");
@@ -10673,7 +11268,7 @@ function frameBounds(spec, index, length, ctx, defaultFrameEnd, orderKeys) {
10673
11268
  const isRangeLike = spec.frame.type === "RANGE" || spec.frame.type === "GROUPS";
10674
11269
  let peerFirst = index;
10675
11270
  if (isRangeLike && spec.orderBy.length > 0) {
10676
- while (peerFirst > 0 && rowsEqual(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
11271
+ while (peerFirst > 0 && rowsEqual2(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
10677
11272
  }
10678
11273
  const bound = (item, isStart) => {
10679
11274
  switch (item.kind) {
@@ -10695,8 +11290,8 @@ function frameBounds(spec, index, length, ctx, defaultFrameEnd, orderKeys) {
10695
11290
  function frameRows(partition, start, end, index, orderKeys, exclude) {
10696
11291
  let peerFirst = index;
10697
11292
  let peerLast = index;
10698
- while (peerFirst > 0 && rowsEqual(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
10699
- while (peerLast + 1 < partition.length && rowsEqual(orderKeys[peerLast], orderKeys[peerLast + 1])) peerLast++;
11293
+ while (peerFirst > 0 && rowsEqual2(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
11294
+ while (peerLast + 1 < partition.length && rowsEqual2(orderKeys[peerLast], orderKeys[peerLast + 1])) peerLast++;
10700
11295
  const rows = [];
10701
11296
  for (let i = Math.max(0, start); i <= end && i < partition.length; i++) {
10702
11297
  if (exclude === "current_row" && i === index) continue;
@@ -10922,7 +11517,7 @@ function referencesTable(select, name) {
10922
11517
  };
10923
11518
  return visit(select.from) || (select.compound ? referencesTable(select.compound.select, name) : false);
10924
11519
  }
10925
- function rowsEqual(left, right) {
11520
+ function rowsEqual2(left, right) {
10926
11521
  return left.length === right.length && left.every((value, index) => {
10927
11522
  const other = right[index] ?? null;
10928
11523
  return value === null && other === null || value !== null && other !== null && sqlValueEquals(value, other);
@@ -12347,154 +12942,24 @@ function asExplicitRowid(value) {
12347
12942
  // src/executor/pragma.ts
12348
12943
  function executePragma(name, expr, env) {
12349
12944
  const key = name.toLowerCase();
12350
- switch (key) {
12351
- case "foreign_keys":
12352
- return pragmaForeignKeys(expr, env);
12353
- case "table_info":
12354
- return pragmaTableInfo(expr, env, false);
12355
- case "table_xinfo":
12356
- return pragmaTableInfo(expr, env, true);
12357
- case "index_list":
12358
- return pragmaIndexList(expr, env);
12359
- case "index_info":
12360
- return pragmaIndexInfo(expr, env);
12361
- case "foreign_key_list":
12362
- return pragmaForeignKeyList(expr, env);
12363
- case "database_list":
12364
- return pragmaDatabaseList(env);
12365
- case "user_version":
12366
- return pragmaIntVersion("user_version", expr, env, "userVersion");
12367
- case "schema_version":
12368
- return pragmaIntVersion("schema_version", expr, env, "schemaVersion");
12369
- default:
12370
- return emptyResult(0, env.state.lastInsertRowid);
12371
- }
12372
- }
12373
- function pragmaForeignKeys(expr, env) {
12374
- if (expr === null) {
12375
- return valuesToResult(["foreign_keys"], [[env.state.foreignKeysEnabled ? 1 : 0]], 0, env.state.lastInsertRowid);
12376
- }
12377
- const value = pragmaValue(expr, env);
12378
- if (!env.transactions.inTransaction) env.state.foreignKeysEnabled = isTruthySql(value) === true;
12379
- return emptyResult(0, env.state.lastInsertRowid);
12380
- }
12381
- function pragmaTableInfo(expr, env, xinfo) {
12382
- const tableName = pragmaTableArg(expr, env);
12383
- const table = env.state.tables.get(tableName.toLowerCase());
12384
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12385
- const columns = xinfo ? ["cid", "name", "type", "notnull", "dflt_value", "pk", "hidden"] : ["cid", "name", "type", "notnull", "dflt_value", "pk"];
12386
- const rows = table.columns.map((column, cid) => {
12387
- const pkIndex = table.columns.filter((c) => c.primaryKey).findIndex((c) => c.name === column.name);
12388
- const pk = column.primaryKey ? pkIndex >= 0 ? pkIndex + 1 : 1 : 0;
12389
- const dflt = column.defaultExpr ? defaultLiteral(column.defaultExpr) : null;
12390
- const base = [cid, column.name, column.typeName ?? "", column.notNull ? 1 : 0, dflt, pk];
12391
- if (xinfo) {
12392
- let hidden = 0;
12393
- if (column.generated?.stored) hidden = 2;
12394
- else if (column.generated) hidden = 2;
12395
- if (column.generated && !column.generated.stored) hidden = 2;
12396
- if (column.generated?.stored) hidden = 3;
12397
- base.push(hidden);
12398
- }
12399
- return base;
12400
- });
12401
- return valuesToResult(columns, rows, 0, env.state.lastInsertRowid);
12402
- }
12403
- function defaultLiteral(expr) {
12404
- if (expr.type === "literal")
12405
- return typeof expr.value === "string" ? `'${expr.value.replace(/'/g, "''")}'` : expr.value;
12406
- if (expr.type === "null") return "NULL";
12407
- return null;
12408
- }
12409
- function pragmaIndexList(expr, env) {
12410
- const tableName = pragmaTableArg(expr, env);
12411
- const table = env.state.tables.get(tableName.toLowerCase());
12412
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12413
- const rows = [];
12414
- let seq = 0;
12415
- for (const name of table.indexes) {
12416
- const index = env.state.indexes.get(name.toLowerCase());
12417
- if (!index) continue;
12418
- rows.push([seq++, index.name, index.unique ? 1 : 0, "c", 0]);
12419
- }
12420
- return valuesToResult(["seq", "name", "unique", "origin", "partial"], rows, 0, env.state.lastInsertRowid);
12421
- }
12422
- function pragmaIndexInfo(expr, env) {
12423
- const indexName = pragmaTableArg(expr, env);
12424
- const index = env.state.indexes.get(indexName.toLowerCase());
12425
- if (!index) return emptyResult(0, env.state.lastInsertRowid);
12426
- const table = env.state.getTable(index.tableName);
12427
- const rows = index.columns.map((column, seqno) => {
12428
- const cid = table.columns.findIndex((c) => c.name.toLowerCase() === column.name.toLowerCase());
12429
- return [seqno, cid, column.name];
12430
- });
12431
- return valuesToResult(["seqno", "cid", "name"], rows, 0, env.state.lastInsertRowid);
12432
- }
12433
- function pragmaForeignKeyList(expr, env) {
12434
- const tableName = pragmaTableArg(expr, env);
12435
- const table = env.state.tables.get(tableName.toLowerCase());
12436
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12437
- const rows = [];
12438
- let id = 0;
12439
- for (const constraint of table.constraints) {
12440
- if (constraint.type !== "foreign_key") continue;
12441
- const refColumns = constraint.refColumns ?? env.state.tables.get(constraint.refTable.toLowerCase())?.columns.filter((c) => c.primaryKey).map((c) => c.name) ?? [];
12442
- constraint.columns.forEach((column, seq) => {
12443
- rows.push([
12444
- id,
12445
- seq,
12446
- constraint.refTable,
12447
- column,
12448
- refColumns[seq] ?? null,
12449
- constraint.onUpdate ?? "NO ACTION",
12450
- constraint.onDelete ?? "NO ACTION",
12451
- "NONE"
12452
- ]);
12453
- });
12454
- id++;
12455
- }
12456
- return valuesToResult(
12457
- ["id", "seq", "table", "from", "to", "on_update", "on_delete", "match"],
12458
- rows,
12459
- 0,
12460
- env.state.lastInsertRowid
12461
- );
12462
- }
12463
- function pragmaDatabaseList(env) {
12464
- const rows = [[0, "main", ""]];
12465
- let seq = 2;
12466
- for (const [name, attached] of env.state.attached) {
12467
- const file = attached.filename === ":memory:" ? "" : attached.filename;
12468
- rows.push([seq++, name, file]);
12945
+ if (key === "foreign_keys" && expr !== null) {
12946
+ const value = evalPragmaSetValue(expr, env);
12947
+ if (!env.transactions.inTransaction) env.state.foreignKeysEnabled = coercePragmaTruthy(value);
12948
+ return emptyResult(0, env.state.lastInsertRowid);
12469
12949
  }
12470
- return valuesToResult(["seq", "name", "file"], rows, 0, env.state.lastInsertRowid);
12471
- }
12472
- function pragmaIntVersion(label, expr, env, field) {
12473
- if (expr === null) {
12474
- return valuesToResult([label], [[env.state[field]]], 0, env.state.lastInsertRowid);
12950
+ if ((key === "user_version" || key === "schema_version") && expr !== null) {
12951
+ const value = evalPragmaSetValue(expr, env);
12952
+ const num2 = coercePragmaInt(value);
12953
+ if (key === "user_version") env.state.userVersion = num2;
12954
+ else env.state.schemaVersion = num2;
12955
+ return emptyResult(0, env.state.lastInsertRowid);
12475
12956
  }
12476
- const value = pragmaValue(expr, env);
12477
- const num2 = typeof value === "number" ? Math.trunc(value) : typeof value === "bigint" ? Number(value) : typeof value === "string" ? Number.parseInt(value, 10) : 0;
12478
- if (field === "userVersion") env.state.userVersion = Number.isFinite(num2) ? num2 : 0;
12479
- else env.state.schemaVersion = Number.isFinite(num2) ? num2 : 0;
12480
- return emptyResult(0, env.state.lastInsertRowid);
12481
- }
12482
- function pragmaTableArg(expr, env) {
12483
- if (!expr) throw new SqliteError("missing pragma argument", "misuse");
12484
- if (expr.type === "column" && expr.table === null) return expr.name;
12485
- if (expr.type === "literal" && typeof expr.value === "string") return expr.value;
12486
- const value = evalExpr(expr, env.createEvalContext());
12487
- if (typeof value === "string") return value;
12488
- throw new SqliteError("invalid pragma argument", "misuse");
12489
- }
12490
- function pragmaValue(expr, env) {
12491
- if (expr.type === "column" && expr.table === null) {
12492
- const keyword = expr.name.toLowerCase();
12493
- if (keyword === "on" || keyword === "true" || keyword === "yes") return 1;
12494
- if (keyword === "off" || keyword === "false" || keyword === "no") return 0;
12495
- return expr.name;
12957
+ const args = evalPragmaArgs(expr, env);
12958
+ const result = queryPragma(key, args, env);
12959
+ if (result.columns.length === 0 && result.rows.length === 0) {
12960
+ return emptyResult(0, env.state.lastInsertRowid);
12496
12961
  }
12497
- return evalExpr(expr, env.createEvalContext());
12962
+ return valuesToResult(result.columns, result.rows, 0, env.state.lastInsertRowid);
12498
12963
  }
12499
12964
 
12500
12965
  // src/executor/execute.ts
@@ -12637,50 +13102,37 @@ var Statement = class _Statement {
12637
13102
  }
12638
13103
  database;
12639
13104
  sql;
12640
- bound = [];
12641
13105
  namedPlan = null;
12642
13106
  env = null;
12643
13107
  statements;
12644
13108
  schemaVersion;
12645
13109
  /**
12646
- * Construct a {@link Statement} for {@link Database.prepare}.
13110
+ * Construct a {@link Statement} for {@link Database.prepare} / {@link Database.exec}.
12647
13111
  * @internal
12648
13112
  */
12649
13113
  static create(database, sql, statements) {
12650
13114
  return new _Statement(database, sql, statements);
12651
13115
  }
12652
- /**
12653
- * Store parameters for later {@link run} / {@link all} / {@link get} / {@link result}.
12654
- *
12655
- * Supports positional `?` / `?NNN` and named `:name` / `@name` / `$name` placeholders.
12656
- *
12657
- * @param params - Values to bind, in placeholder order.
12658
- * @returns `this` for chaining.
12659
- */
12660
- bind(...params) {
12661
- this.bound = [...params];
12662
- return this;
12663
- }
12664
13116
  /**
12665
13117
  * Execute for side effects (INSERT / UPDATE / DELETE / DDL).
12666
13118
  *
12667
- * @param params - If provided, override the last {@link bind}; otherwise bound values are used.
13119
+ * @param params - Bind values for this call only.
12668
13120
  * @returns Mutation counters for this execution.
12669
13121
  * @throws {SqliteError} If the database is closed, the statement is empty, or execution fails.
12670
13122
  */
12671
13123
  run(...params) {
12672
- const result = this.execute(params.length > 0 ? params : this.bound, { named: false });
13124
+ const result = this.execute(params, { named: false });
12673
13125
  return { changes: result.changes, lastInsertRowid: result.lastInsertRowid };
12674
13126
  }
12675
13127
  /**
12676
13128
  * Execute and return every result row as an object keyed by column name.
12677
13129
  *
12678
13130
  * @typeParam T - Row shape. Defaults to {@link QueryRow}.
12679
- * @param params - If provided, override the last {@link bind}; otherwise bound values are used.
13131
+ * @param params - Bind values for this call only.
12680
13132
  * @throws {SqliteError} If the database is closed, the statement is empty, or execution fails.
12681
13133
  */
12682
13134
  all(...params) {
12683
- return this.execute(params.length > 0 ? params : this.bound, { named: true }).rows;
13135
+ return this.execute(params, { named: true }).rows;
12684
13136
  }
12685
13137
  /**
12686
13138
  * Execute and return the full {@link ResultSet}, including column names.
@@ -12688,38 +13140,41 @@ var Statement = class _Statement {
12688
13140
  * Use this when you need metadata for an empty result (column names with zero rows).
12689
13141
  * {@link all} only returns row objects.
12690
13142
  *
12691
- * @param params - If provided, override the last {@link bind}; otherwise bound values are used.
13143
+ * @param params - Bind values for this call only.
12692
13144
  * @throws {SqliteError} If the database is closed, the statement is empty, or execution fails.
12693
13145
  */
12694
13146
  result(...params) {
12695
- return this.execute(params.length > 0 ? params : this.bound, { named: true });
13147
+ return this.execute(params, { named: true });
12696
13148
  }
12697
13149
  /**
12698
13150
  * Execute and return the first row, or `undefined` if there are no rows.
12699
13151
  *
12700
13152
  * @typeParam T - Row shape. Defaults to {@link QueryRow}.
12701
- * @param params - If provided, override the last {@link bind}; otherwise bound values are used.
13153
+ * @param params - Bind values for this call only.
12702
13154
  * @throws {SqliteError} If the database is closed, the statement is empty, or execution fails.
12703
13155
  */
12704
13156
  get(...params) {
12705
- return this.execute(params.length > 0 ? params : this.bound, { named: true, maxRows: 1 }).rows[0];
13157
+ return this.execute(params, { named: true, maxRows: 1 }).rows[0];
12706
13158
  }
12707
13159
  execute(params, options) {
12708
13160
  this.database.assertOpen();
12709
13161
  this.reprepareIfSchemaChanged();
12710
13162
  if (this.statements.length === 0) throw new SqliteError("empty statement", "misuse");
13163
+ this.namedPlan ??= planNamedParameters(this.sql);
13164
+ const expected = this.namedPlan.expectedCount;
13165
+ if (params.length > 0 && params.length !== expected) {
13166
+ throw new SqliteError(`SQLite query expected ${expected} values, received ${params.length}`, "misuse");
13167
+ }
12711
13168
  const env = this.obtainEnv(params);
12712
13169
  env.maxRows = options?.maxRows ?? Number.POSITIVE_INFINITY;
12713
13170
  env.includeNamedRows = options?.named !== false;
12714
13171
  env.includeValues = true;
12715
13172
  this.bindNamed(env, params);
12716
13173
  let result;
12717
- let lastQuery;
12718
13174
  for (const statement of this.statements) {
12719
13175
  result = executeStatement(statement, env);
12720
- if (result.columns.length > 0) lastQuery = result;
12721
13176
  }
12722
- return lastQuery ?? result;
13177
+ return result;
12723
13178
  }
12724
13179
  obtainEnv(params) {
12725
13180
  if (this.env) {
@@ -12769,18 +13224,18 @@ function planNamedParameters(sql) {
12769
13224
  }
12770
13225
  }
12771
13226
  }
12772
- return { named };
13227
+ return { named, expectedCount: nextSlot - 1 };
12773
13228
  }
12774
13229
 
12775
13230
  // src/api/database.ts
12776
13231
  var Database = class {
12777
13232
  /** @internal Engine catalog, tables, and mutation counters. */
12778
13233
  state = new DatabaseState();
12779
- /** Seed used to construct the PRNG when `options.prng` is omitted. */
13234
+ /** Seed used to construct the PRNG. */
12780
13235
  seed;
12781
13236
  /**
12782
13237
  * PRNG backing `random()` / `randomblob()` and related builtins.
12783
- * Prefer passing `seed` or `prng` to the constructor.
13238
+ * Prefer passing `seed` to the constructor.
12784
13239
  * @internal
12785
13240
  */
12786
13241
  prng;
@@ -12794,6 +13249,8 @@ var Database = class {
12794
13249
  transactions;
12795
13250
  closed = false;
12796
13251
  transactionSequence = 0;
13252
+ /** Depth of active {@link transaction} callbacks (not SQL BEGIN). */
13253
+ apiTransactionDepth = 0;
12797
13254
  /**
12798
13255
  * Create an empty in-memory database.
12799
13256
  *
@@ -12801,49 +13258,53 @@ var Database = class {
12801
13258
  */
12802
13259
  constructor(options = {}) {
12803
13260
  this.seed = options.seed ?? DEFAULT_DATABASE_SEED;
12804
- this.prng = options.prng ?? new Prng(this.seed);
13261
+ this.prng = new Prng(this.seed);
12805
13262
  this.now = resolveClock(options.now);
12806
13263
  this.transactions = new TransactionManager(this.state, this.prng);
12807
13264
  }
12808
13265
  /**
12809
13266
  * Execute SQL for its side effects (DDL/DML). Multiple statements are allowed.
12810
13267
  *
13268
+ * Does not accept bind parameters — use {@link prepare} or {@link query}.
13269
+ *
12811
13270
  * @param sql - SQL to run (semicolon-separated statements are ok).
12812
- * @param params - Bound parameters for `?` / `:name` placeholders.
12813
- * @throws {SqliteError} If the database is closed or the SQL fails.
13271
+ * @throws {SqliteError} If the database is closed, extra arguments are passed, or the SQL fails.
12814
13272
  */
12815
- exec(sql, params = []) {
13273
+ exec(sql) {
12816
13274
  this.assertOpen();
12817
- Statement.create(this, sql, parse(sql)).run(...params);
13275
+ if (arguments.length > 1) {
13276
+ throw new SqliteError("exec() does not accept parameters; use prepare() or query()", "misuse");
13277
+ }
13278
+ Statement.create(this, sql, parse(sql)).run();
12818
13279
  }
12819
13280
  /**
12820
- * Execute a query and return all rows as objects keyed by column name.
13281
+ * Execute a single-statement query and return all rows as objects keyed by column name.
12821
13282
  *
12822
13283
  * @typeParam T - Row shape. Defaults to {@link QueryRow}.
12823
- * @param sql - SQL SELECT (or any statement that produces a result set).
13284
+ * @param sql - A single SQL statement (trailing `;` is fine).
12824
13285
  * @param params - Bound parameters for `?` / `:name` placeholders.
12825
13286
  * @returns All result rows.
12826
- * @throws {SqliteError} If the database is closed or the SQL fails.
13287
+ * @throws {SqliteError} If the database is closed, `sql` is not a single statement, or execution fails.
12827
13288
  */
12828
13289
  query(sql, params = []) {
12829
13290
  this.assertOpen();
12830
- return Statement.create(this, sql, parse(sql)).all(...params);
13291
+ return this.prepareSingle(sql).all(...params);
12831
13292
  }
12832
13293
  /**
12833
- * Compile `sql` into a reusable {@link Statement}.
13294
+ * Compile a single SQL statement into a reusable {@link Statement}.
12834
13295
  *
12835
- * @param sql - SQL to prepare.
12836
- * @throws {SqliteError} If the database is closed or `sql` cannot be parsed.
13296
+ * @param sql - A single SQL statement (trailing `;` is fine). Multi-statement scripts are rejected.
13297
+ * @throws {SqliteError} If the database is closed or `sql` cannot be prepared as one statement.
12837
13298
  */
12838
13299
  prepare(sql) {
12839
13300
  this.assertOpen();
12840
- return Statement.create(this, sql, parse(sql));
13301
+ return this.prepareSingle(sql);
12841
13302
  }
12842
13303
  /**
12843
13304
  * Run `fn` inside a transaction. Commits on success; rolls back if `fn` throws.
12844
13305
  *
12845
13306
  * Nested calls use SAVEPOINTs so an inner failure does not abort the outer
12846
- * transaction.
13307
+ * transaction. Calling {@link close} from inside `fn` throws `misuse`.
12847
13308
  *
12848
13309
  * @param fn - Work to run while the transaction is open.
12849
13310
  * @returns The value returned by `fn`.
@@ -12851,27 +13312,32 @@ var Database = class {
12851
13312
  */
12852
13313
  transaction(fn) {
12853
13314
  this.assertOpen();
12854
- if (!this.transactions.inTransaction) {
12855
- this.transactions.begin();
13315
+ this.apiTransactionDepth++;
13316
+ try {
13317
+ if (!this.transactions.inTransaction) {
13318
+ this.transactions.begin();
13319
+ try {
13320
+ const value = fn();
13321
+ this.transactions.commit();
13322
+ return value;
13323
+ } catch (error) {
13324
+ this.transactions.rollback();
13325
+ throw error;
13326
+ }
13327
+ }
13328
+ const name = `__api_transaction_${++this.transactionSequence}`;
13329
+ this.transactions.savepoint(name);
12856
13330
  try {
12857
13331
  const value = fn();
12858
- this.transactions.commit();
13332
+ this.transactions.release(name);
12859
13333
  return value;
12860
13334
  } catch (error) {
12861
- this.transactions.rollback();
13335
+ this.transactions.rollback(name);
13336
+ this.transactions.release(name);
12862
13337
  throw error;
12863
13338
  }
12864
- }
12865
- const name = `__api_transaction_${++this.transactionSequence}`;
12866
- this.transactions.savepoint(name);
12867
- try {
12868
- const value = fn();
12869
- this.transactions.release(name);
12870
- return value;
12871
- } catch (error) {
12872
- this.transactions.rollback(name);
12873
- this.transactions.release(name);
12874
- throw error;
13339
+ } finally {
13340
+ this.apiTransactionDepth--;
12875
13341
  }
12876
13342
  }
12877
13343
  /**
@@ -12892,6 +13358,8 @@ var Database = class {
12892
13358
  * Replace this database's contents with a blob from {@link snapshot}.
12893
13359
  *
12894
13360
  * Restores PRNG state and the clock when the snapshot includes them (v2).
13361
+ * Newer library versions can restore older snapshots; older libraries cannot
13362
+ * restore newer format versions.
12895
13363
  *
12896
13364
  * @param snapshot - Bytes previously returned by {@link snapshot}.
12897
13365
  * @throws {SqliteError} If the database is closed, a transaction is open, or the blob is invalid.
@@ -12910,10 +13378,14 @@ var Database = class {
12910
13378
  /**
12911
13379
  * Close the database. Further SQL throws {@link SqliteError}. Idempotent.
12912
13380
  *
12913
- * Rolls back an open transaction, if any.
13381
+ * Rolls back an open SQL transaction, if any. Throws if called from inside
13382
+ * a {@link transaction} callback.
12914
13383
  */
12915
13384
  close() {
12916
13385
  if (this.closed) return;
13386
+ if (this.apiTransactionDepth > 0) {
13387
+ throw new SqliteError("cannot close database inside transaction()", "misuse");
13388
+ }
12917
13389
  if (this.transactions.inTransaction) this.transactions.rollback();
12918
13390
  this.closed = true;
12919
13391
  }
@@ -12943,42 +13415,30 @@ var Database = class {
12943
13415
  assertOpen() {
12944
13416
  if (this.closed) throw new SqliteError("Database is closed", "misuse");
12945
13417
  }
13418
+ prepareSingle(sql) {
13419
+ const statements = parse(sql);
13420
+ if (statements.length === 0) {
13421
+ throw new SqliteError("empty statement", "misuse");
13422
+ }
13423
+ if (statements.length > 1) {
13424
+ throw new SqliteError("query()/prepare() accept a single statement only; use exec() for scripts", "misuse");
13425
+ }
13426
+ return Statement.create(this, sql, statements);
13427
+ }
12946
13428
  };
13429
+ var disposeKey = Symbol.dispose;
13430
+ if (typeof disposeKey === "symbol") {
13431
+ Object.defineProperty(Database.prototype, disposeKey, {
13432
+ value: function() {
13433
+ this.close();
13434
+ },
13435
+ writable: true,
13436
+ configurable: true
13437
+ });
13438
+ }
12947
13439
  export {
12948
- DEFAULT_DATABASE_SEED,
12949
- DEFAULT_NOW,
12950
13440
  Database,
12951
- Prng,
12952
- SqlJsonText,
12953
- SqlReal,
12954
13441
  SqliteError,
12955
- Statement,
12956
- affinityFromTypeName,
12957
- applyAffinity,
12958
- asSqlJsonText,
12959
- asSqlReal,
12960
- canonicalizeNumber,
12961
- cloneSqlValue,
12962
- coerceToNumber,
12963
- compareSql,
12964
- decodeDatabaseState,
12965
- deriveSeed,
12966
- encodeDatabaseState,
12967
- evalExpr,
12968
- fixedClock,
12969
- globMatch,
12970
- isSqlJsonText,
12971
- isSqlReal,
12972
- isTruthySql,
12973
- likeMatch,
12974
- parse,
12975
- resolveClock,
12976
- sqlValueEquals,
12977
- storageClassOf,
12978
- toInteger,
12979
- tokenize,
12980
- typeofSql,
12981
- utf8Decode,
12982
- utf8Encode
13442
+ Statement
12983
13443
  };
12984
13444
  //# sourceMappingURL=index.js.map