@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/AGENTS.md +1 -3
- package/COMPATIBILITY.md +1 -1
- package/README.md +37 -25
- package/dist/api/database.d.ts +20 -13
- package/dist/api/statement.d.ts +7 -17
- package/dist/errors/index.d.ts +14 -5
- package/dist/executor/pragma-engine.d.ts +25 -0
- package/dist/executor/result.d.ts +2 -2
- package/dist/functions/pragma-tvf.d.ts +8 -0
- package/dist/functions/table-valued-registry.d.ts +11 -0
- package/dist/functions/table-valued.d.ts +4 -4
- package/dist/index.d.ts +6 -12
- package/dist/index.js +742 -282
- package/dist/index.js.map +4 -4
- package/dist/runtime/options.d.ts +0 -3
- package/dist/unstable.d.ts +20 -0
- package/dist/unstable.js +8734 -0
- package/dist/unstable.js.map +7 -0
- package/package.json +6 -4
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
|
-
/**
|
|
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 -
|
|
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}`, "
|
|
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
|
-
|
|
8998
|
-
|
|
8999
|
-
throw new SqliteError(`binding parameter :${name} is not supplied`, "misuse");
|
|
8988
|
+
if (!this.named.has(key)) {
|
|
8989
|
+
return null;
|
|
9000
8990
|
}
|
|
9001
|
-
return
|
|
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
|
|
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)
|
|
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)) :
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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 &&
|
|
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
|
|
10608
|
-
for (let i = 1; i <= index; i++) if (!
|
|
10609
|
-
return
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
10699
|
-
while (peerLast + 1 < partition.length &&
|
|
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
|
|
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
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
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
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
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
|
|
12477
|
-
const
|
|
12478
|
-
if (
|
|
12479
|
-
|
|
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
|
|
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 -
|
|
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
|
|
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 -
|
|
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
|
|
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 -
|
|
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
|
|
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 -
|
|
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
|
|
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
|
|
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
|
|
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`
|
|
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 =
|
|
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
|
-
* @
|
|
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
|
|
13273
|
+
exec(sql) {
|
|
12816
13274
|
this.assertOpen();
|
|
12817
|
-
|
|
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 -
|
|
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
|
|
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
|
|
13291
|
+
return this.prepareSingle(sql).all(...params);
|
|
12831
13292
|
}
|
|
12832
13293
|
/**
|
|
12833
|
-
* Compile
|
|
13294
|
+
* Compile a single SQL statement into a reusable {@link Statement}.
|
|
12834
13295
|
*
|
|
12835
|
-
* @param sql - SQL
|
|
12836
|
-
* @throws {SqliteError} If the database is closed or `sql` cannot be
|
|
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
|
|
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
|
-
|
|
12855
|
-
|
|
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.
|
|
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
|
-
|
|
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
|