@crvouga/sqlite-mem 1.0.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
@@ -9190,8 +9190,579 @@ function executeDetach(stmt, env) {
9190
9190
  return emptyResult(0, env.state.lastInsertRowid);
9191
9191
  }
9192
9192
 
9193
- // 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
9194
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
9195
9766
  var JSON_TVF_COLUMNS = ["key", "value", "type", "atom", "id", "parent", "fullkey", "path"];
9196
9767
  function jsonTvfResult(alias, defaultName, rows) {
9197
9768
  const table = alias ?? defaultName;
@@ -9206,7 +9777,7 @@ function jsonTvfResult(alias, defaultName, rows) {
9206
9777
  }))
9207
9778
  };
9208
9779
  }
9209
- registry.set("generate_series", (args, alias) => {
9780
+ registerTableValuedFunction("generate_series", (args, alias) => {
9210
9781
  if (args.length < 2 || args.length > 3) {
9211
9782
  throw new SqliteError("wrong number of arguments to function generate_series()", "misuse");
9212
9783
  }
@@ -9237,13 +9808,13 @@ registry.set("generate_series", (args, alias) => {
9237
9808
  }
9238
9809
  return { columns: ["value"], rows };
9239
9810
  });
9240
- registry.set("json_each", (args, alias) => {
9811
+ registerTableValuedFunction("json_each", (args, alias) => {
9241
9812
  if (args.length < 1 || args.length > 2) {
9242
9813
  throw new SqliteError("wrong number of arguments to function json_each()", "misuse");
9243
9814
  }
9244
9815
  return jsonTvfResult(alias, "json_each", jsonEachRows(args[0], args[1]));
9245
9816
  });
9246
- registry.set("json_tree", (args, alias) => {
9817
+ registerTableValuedFunction("json_tree", (args, alias) => {
9247
9818
  if (args.length < 1 || args.length > 2) {
9248
9819
  throw new SqliteError("wrong number of arguments to function json_tree()", "misuse");
9249
9820
  }
@@ -9253,11 +9824,16 @@ function safeInt(value) {
9253
9824
  return value <= BigInt(Number.MAX_SAFE_INTEGER) && value >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(value) : value;
9254
9825
  }
9255
9826
  function evaluateTableFunction(name, args, alias, env, scope, parent) {
9256
- const fn = registry.get(name.toLowerCase());
9827
+ ensurePragmaTvfsRegistered();
9828
+ const fn = getTableValuedFunction(name);
9257
9829
  if (!fn) throw new SqliteError(`no such table-valued function: ${name}`, "no_such_table");
9258
9830
  const values = args.map((arg) => evalExpr(arg, env.createEvalContext(scope ?? null, parent)));
9259
9831
  return fn(values, alias, env);
9260
9832
  }
9833
+ function hasTableValuedFunction(name) {
9834
+ ensurePragmaTvfsRegistered();
9835
+ return hasRegisteredTableValuedFunction(name);
9836
+ }
9261
9837
 
9262
9838
  // src/schema/catalog.ts
9263
9839
  function schemaCatalogRows(state) {
@@ -9988,10 +10564,10 @@ function executeSelect2(stmt, env, parent) {
9988
10564
  rows = uniqueRows([...leftRows, ...rightRows]);
9989
10565
  break;
9990
10566
  case "INTERSECT":
9991
- rows = uniqueRows(leftRows).filter((row) => rightRows.some((other) => rowsEqual(row, other)));
10567
+ rows = uniqueRows(leftRows).filter((row) => rightRows.some((other) => rowsEqual2(row, other)));
9992
10568
  break;
9993
10569
  case "EXCEPT":
9994
- rows = uniqueRows(leftRows).filter((row) => !rightRows.some((other) => rowsEqual(row, other)));
10570
+ rows = uniqueRows(leftRows).filter((row) => !rightRows.some((other) => rowsEqual2(row, other)));
9995
10571
  break;
9996
10572
  }
9997
10573
  if (stmt.orderBy.length > 0) rows.sort((a, b) => compareCompoundRows(a, b, stmt.orderBy, base.columns));
@@ -10025,7 +10601,7 @@ function executeWith(stmt, env, parent) {
10025
10601
  env.ctes.set(key, valuesToResult(columns, delta));
10026
10602
  const nextResult = executeSelect2(cte.select.compound.select, env, parent);
10027
10603
  const candidates = resultValues(nextResult);
10028
- 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)));
10029
10605
  if (additions.length === 0) break;
10030
10606
  accumulated = [...accumulated, ...additions];
10031
10607
  delta = additions;
@@ -10327,6 +10903,9 @@ function scanFrom(item, env, parent) {
10327
10903
  if (item.type === "table_func") {
10328
10904
  return evaluateTableFunction(item.name, item.args, item.alias, env).rows;
10329
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
+ }
10330
10909
  const alias = item.alias ?? item.name;
10331
10910
  const qualified = item.schema ? `${item.schema}.${item.name}` : item.name;
10332
10911
  const db = env.state.databaseForSchema(item.schema, qualified);
@@ -10499,6 +11078,14 @@ function shapeOf(item, env) {
10499
11078
  value: null
10500
11079
  }));
10501
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
+ }
10502
11089
  const alias = item.alias ?? item.name;
10503
11090
  const qualified = item.schema ? `${item.schema}.${item.name}` : item.name;
10504
11091
  const db = env.state.databaseForSchema(item.schema, qualified);
@@ -10568,7 +11155,7 @@ function aggregateValue(expr, rows, env, parent) {
10568
11155
  const ctx = env.createEvalContext(row, parent);
10569
11156
  if (expr.filter && isTruthySql(evalExpr(expr.filter, ctx)) !== true) continue;
10570
11157
  const args = expr.args === "*" ? [] : expr.args.map((arg) => evalExpr(arg, ctx));
10571
- if (expr.distinct && seen.some((values) => rowsEqual(values, args))) continue;
11158
+ if (expr.distinct && seen.some((values) => rowsEqual2(values, args))) continue;
10572
11159
  seen.push(args);
10573
11160
  accumulator.step(args);
10574
11161
  }
@@ -10579,7 +11166,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10579
11166
  const currentCtx = env.createEvalContext(current, parent);
10580
11167
  const partitionKey = spec.partitionBy.map((item) => evalExpr(item, currentCtx));
10581
11168
  const partition = rows.filter(
10582
- (row) => rowsEqual(
11169
+ (row) => rowsEqual2(
10583
11170
  partitionKey,
10584
11171
  spec.partitionBy.map((item) => evalExpr(item, env.createEvalContext(row, parent)))
10585
11172
  )
@@ -10608,13 +11195,13 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10608
11195
  if (name === "row_number") return index + 1;
10609
11196
  if (name === "rank") {
10610
11197
  let first = index;
10611
- while (first > 0 && rowsEqual(orderKeys[first], orderKeys[first - 1])) first--;
11198
+ while (first > 0 && rowsEqual2(orderKeys[first], orderKeys[first - 1])) first--;
10612
11199
  return first + 1;
10613
11200
  }
10614
11201
  if (name === "dense_rank") {
10615
- let rank = 1;
10616
- for (let i = 1; i <= index; i++) if (!rowsEqual(orderKeys[i], orderKeys[i - 1])) rank++;
10617
- 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;
10618
11205
  }
10619
11206
  const evaluated = args.map((arg) => evalExpr(arg, currentCtx));
10620
11207
  if (name === "lag" || name === "lead") {
@@ -10648,7 +11235,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10648
11235
  if (name === "cume_dist") {
10649
11236
  if (partition.length === 0) return null;
10650
11237
  let lastPeer = index;
10651
- while (lastPeer + 1 < partition.length && rowsEqual(orderKeys[lastPeer + 1], orderKeys[index])) {
11238
+ while (lastPeer + 1 < partition.length && rowsEqual2(orderKeys[lastPeer + 1], orderKeys[index])) {
10652
11239
  lastPeer++;
10653
11240
  }
10654
11241
  return (lastPeer + 1) / partition.length;
@@ -10656,7 +11243,7 @@ function windowValue(expr, current, rows, env, parent, namedWindows) {
10656
11243
  if (name === "percent_rank") {
10657
11244
  if (partition.length <= 1) return 0;
10658
11245
  let first = index;
10659
- while (first > 0 && rowsEqual(orderKeys[first], orderKeys[first - 1])) first--;
11246
+ while (first > 0 && rowsEqual2(orderKeys[first], orderKeys[first - 1])) first--;
10660
11247
  return first / (partition.length - 1);
10661
11248
  }
10662
11249
  throw new SqliteError(`no such window function: ${expr.func.name}`, "other");
@@ -10681,7 +11268,7 @@ function frameBounds(spec, index, length, ctx, defaultFrameEnd, orderKeys) {
10681
11268
  const isRangeLike = spec.frame.type === "RANGE" || spec.frame.type === "GROUPS";
10682
11269
  let peerFirst = index;
10683
11270
  if (isRangeLike && spec.orderBy.length > 0) {
10684
- while (peerFirst > 0 && rowsEqual(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
11271
+ while (peerFirst > 0 && rowsEqual2(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
10685
11272
  }
10686
11273
  const bound = (item, isStart) => {
10687
11274
  switch (item.kind) {
@@ -10703,8 +11290,8 @@ function frameBounds(spec, index, length, ctx, defaultFrameEnd, orderKeys) {
10703
11290
  function frameRows(partition, start, end, index, orderKeys, exclude) {
10704
11291
  let peerFirst = index;
10705
11292
  let peerLast = index;
10706
- while (peerFirst > 0 && rowsEqual(orderKeys[peerFirst], orderKeys[peerFirst - 1])) peerFirst--;
10707
- 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++;
10708
11295
  const rows = [];
10709
11296
  for (let i = Math.max(0, start); i <= end && i < partition.length; i++) {
10710
11297
  if (exclude === "current_row" && i === index) continue;
@@ -10930,7 +11517,7 @@ function referencesTable(select, name) {
10930
11517
  };
10931
11518
  return visit(select.from) || (select.compound ? referencesTable(select.compound.select, name) : false);
10932
11519
  }
10933
- function rowsEqual(left, right) {
11520
+ function rowsEqual2(left, right) {
10934
11521
  return left.length === right.length && left.every((value, index) => {
10935
11522
  const other = right[index] ?? null;
10936
11523
  return value === null && other === null || value !== null && other !== null && sqlValueEquals(value, other);
@@ -12355,154 +12942,24 @@ function asExplicitRowid(value) {
12355
12942
  // src/executor/pragma.ts
12356
12943
  function executePragma(name, expr, env) {
12357
12944
  const key = name.toLowerCase();
12358
- switch (key) {
12359
- case "foreign_keys":
12360
- return pragmaForeignKeys(expr, env);
12361
- case "table_info":
12362
- return pragmaTableInfo(expr, env, false);
12363
- case "table_xinfo":
12364
- return pragmaTableInfo(expr, env, true);
12365
- case "index_list":
12366
- return pragmaIndexList(expr, env);
12367
- case "index_info":
12368
- return pragmaIndexInfo(expr, env);
12369
- case "foreign_key_list":
12370
- return pragmaForeignKeyList(expr, env);
12371
- case "database_list":
12372
- return pragmaDatabaseList(env);
12373
- case "user_version":
12374
- return pragmaIntVersion("user_version", expr, env, "userVersion");
12375
- case "schema_version":
12376
- return pragmaIntVersion("schema_version", expr, env, "schemaVersion");
12377
- default:
12378
- return emptyResult(0, env.state.lastInsertRowid);
12379
- }
12380
- }
12381
- function pragmaForeignKeys(expr, env) {
12382
- if (expr === null) {
12383
- return valuesToResult(["foreign_keys"], [[env.state.foreignKeysEnabled ? 1 : 0]], 0, env.state.lastInsertRowid);
12384
- }
12385
- const value = pragmaValue(expr, env);
12386
- if (!env.transactions.inTransaction) env.state.foreignKeysEnabled = isTruthySql(value) === true;
12387
- return emptyResult(0, env.state.lastInsertRowid);
12388
- }
12389
- function pragmaTableInfo(expr, env, xinfo) {
12390
- const tableName = pragmaTableArg(expr, env);
12391
- const table = env.state.tables.get(tableName.toLowerCase());
12392
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12393
- const columns = xinfo ? ["cid", "name", "type", "notnull", "dflt_value", "pk", "hidden"] : ["cid", "name", "type", "notnull", "dflt_value", "pk"];
12394
- const rows = table.columns.map((column, cid) => {
12395
- const pkIndex = table.columns.filter((c) => c.primaryKey).findIndex((c) => c.name === column.name);
12396
- const pk = column.primaryKey ? pkIndex >= 0 ? pkIndex + 1 : 1 : 0;
12397
- const dflt = column.defaultExpr ? defaultLiteral(column.defaultExpr) : null;
12398
- const base = [cid, column.name, column.typeName ?? "", column.notNull ? 1 : 0, dflt, pk];
12399
- if (xinfo) {
12400
- let hidden = 0;
12401
- if (column.generated?.stored) hidden = 2;
12402
- else if (column.generated) hidden = 2;
12403
- if (column.generated && !column.generated.stored) hidden = 2;
12404
- if (column.generated?.stored) hidden = 3;
12405
- base.push(hidden);
12406
- }
12407
- return base;
12408
- });
12409
- return valuesToResult(columns, rows, 0, env.state.lastInsertRowid);
12410
- }
12411
- function defaultLiteral(expr) {
12412
- if (expr.type === "literal")
12413
- return typeof expr.value === "string" ? `'${expr.value.replace(/'/g, "''")}'` : expr.value;
12414
- if (expr.type === "null") return "NULL";
12415
- return null;
12416
- }
12417
- function pragmaIndexList(expr, env) {
12418
- const tableName = pragmaTableArg(expr, env);
12419
- const table = env.state.tables.get(tableName.toLowerCase());
12420
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12421
- const rows = [];
12422
- let seq = 0;
12423
- for (const name of table.indexes) {
12424
- const index = env.state.indexes.get(name.toLowerCase());
12425
- if (!index) continue;
12426
- rows.push([seq++, index.name, index.unique ? 1 : 0, "c", 0]);
12427
- }
12428
- return valuesToResult(["seq", "name", "unique", "origin", "partial"], rows, 0, env.state.lastInsertRowid);
12429
- }
12430
- function pragmaIndexInfo(expr, env) {
12431
- const indexName = pragmaTableArg(expr, env);
12432
- const index = env.state.indexes.get(indexName.toLowerCase());
12433
- if (!index) return emptyResult(0, env.state.lastInsertRowid);
12434
- const table = env.state.getTable(index.tableName);
12435
- const rows = index.columns.map((column, seqno) => {
12436
- const cid = table.columns.findIndex((c) => c.name.toLowerCase() === column.name.toLowerCase());
12437
- return [seqno, cid, column.name];
12438
- });
12439
- return valuesToResult(["seqno", "cid", "name"], rows, 0, env.state.lastInsertRowid);
12440
- }
12441
- function pragmaForeignKeyList(expr, env) {
12442
- const tableName = pragmaTableArg(expr, env);
12443
- const table = env.state.tables.get(tableName.toLowerCase());
12444
- if (!table) return emptyResult(0, env.state.lastInsertRowid);
12445
- const rows = [];
12446
- let id = 0;
12447
- for (const constraint of table.constraints) {
12448
- if (constraint.type !== "foreign_key") continue;
12449
- const refColumns = constraint.refColumns ?? env.state.tables.get(constraint.refTable.toLowerCase())?.columns.filter((c) => c.primaryKey).map((c) => c.name) ?? [];
12450
- constraint.columns.forEach((column, seq) => {
12451
- rows.push([
12452
- id,
12453
- seq,
12454
- constraint.refTable,
12455
- column,
12456
- refColumns[seq] ?? null,
12457
- constraint.onUpdate ?? "NO ACTION",
12458
- constraint.onDelete ?? "NO ACTION",
12459
- "NONE"
12460
- ]);
12461
- });
12462
- id++;
12463
- }
12464
- return valuesToResult(
12465
- ["id", "seq", "table", "from", "to", "on_update", "on_delete", "match"],
12466
- rows,
12467
- 0,
12468
- env.state.lastInsertRowid
12469
- );
12470
- }
12471
- function pragmaDatabaseList(env) {
12472
- const rows = [[0, "main", ""]];
12473
- let seq = 2;
12474
- for (const [name, attached] of env.state.attached) {
12475
- const file = attached.filename === ":memory:" ? "" : attached.filename;
12476
- 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);
12477
12949
  }
12478
- return valuesToResult(["seq", "name", "file"], rows, 0, env.state.lastInsertRowid);
12479
- }
12480
- function pragmaIntVersion(label, expr, env, field) {
12481
- if (expr === null) {
12482
- 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);
12483
12956
  }
12484
- const value = pragmaValue(expr, env);
12485
- const num2 = typeof value === "number" ? Math.trunc(value) : typeof value === "bigint" ? Number(value) : typeof value === "string" ? Number.parseInt(value, 10) : 0;
12486
- if (field === "userVersion") env.state.userVersion = Number.isFinite(num2) ? num2 : 0;
12487
- else env.state.schemaVersion = Number.isFinite(num2) ? num2 : 0;
12488
- return emptyResult(0, env.state.lastInsertRowid);
12489
- }
12490
- function pragmaTableArg(expr, env) {
12491
- if (!expr) throw new SqliteError("missing pragma argument", "misuse");
12492
- if (expr.type === "column" && expr.table === null) return expr.name;
12493
- if (expr.type === "literal" && typeof expr.value === "string") return expr.value;
12494
- const value = evalExpr(expr, env.createEvalContext());
12495
- if (typeof value === "string") return value;
12496
- throw new SqliteError("invalid pragma argument", "misuse");
12497
- }
12498
- function pragmaValue(expr, env) {
12499
- if (expr.type === "column" && expr.table === null) {
12500
- const keyword = expr.name.toLowerCase();
12501
- if (keyword === "on" || keyword === "true" || keyword === "yes") return 1;
12502
- if (keyword === "off" || keyword === "false" || keyword === "no") return 0;
12503
- 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);
12504
12961
  }
12505
- return evalExpr(expr, env.createEvalContext());
12962
+ return valuesToResult(result.columns, result.rows, 0, env.state.lastInsertRowid);
12506
12963
  }
12507
12964
 
12508
12965
  // src/executor/execute.ts