@crvouga/sqlite-mem 1.8.1 → 1.10.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 -1
- package/README.md +40 -26
- package/compat/divergences.json +5 -5
- package/compat/scenarios.ts +16 -9
- package/dist/api/database.d.ts +7 -15
- package/dist/api/snapshot.d.ts +21 -0
- package/dist/constraints/check.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6490 -5845
- package/dist/index.js.map +4 -4
- package/dist/indexes/index.d.ts +15 -0
- package/dist/indexes/keys.d.ts +20 -0
- package/dist/serialization/codec.d.ts +2 -2
- package/dist/storage/row.d.ts +6 -3
- package/dist/storage/table.d.ts +10 -0
- package/dist/types/value.d.ts +0 -1
- package/dist/unstable.js +630 -133
- package/dist/unstable.js.map +4 -4
- package/package.json +1 -1
package/dist/unstable.js
CHANGED
|
@@ -260,11 +260,13 @@ function comparisonClass(v) {
|
|
|
260
260
|
if (typeof v === "string" || v instanceof SqlJsonText) return 2;
|
|
261
261
|
return 3;
|
|
262
262
|
}
|
|
263
|
+
var TEXT_ENCODER = new TextEncoder();
|
|
264
|
+
var TEXT_DECODER = new TextDecoder();
|
|
263
265
|
function utf8Encode(s) {
|
|
264
|
-
return
|
|
266
|
+
return TEXT_ENCODER.encode(s);
|
|
265
267
|
}
|
|
266
268
|
function utf8Decode(b) {
|
|
267
|
-
return
|
|
269
|
+
return TEXT_DECODER.decode(b);
|
|
268
270
|
}
|
|
269
271
|
function cloneSqlValue(v) {
|
|
270
272
|
if (v instanceof Uint8Array) return new Uint8Array(v);
|
|
@@ -5827,8 +5829,8 @@ var IndexStore = class _IndexStore {
|
|
|
5827
5829
|
}
|
|
5828
5830
|
}
|
|
5829
5831
|
checkUnique(values, rowid) {
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
+
if (values.some((value) => value === null)) return;
|
|
5833
|
+
const key = serializeIndexEntry(values);
|
|
5832
5834
|
const existing = this.entries.get(key);
|
|
5833
5835
|
if (!existing) return;
|
|
5834
5836
|
for (const id of existing) {
|
|
@@ -5843,8 +5845,7 @@ var IndexStore = class _IndexStore {
|
|
|
5843
5845
|
}
|
|
5844
5846
|
insert(values, rowid, unique = true) {
|
|
5845
5847
|
this.assertMutable();
|
|
5846
|
-
const key =
|
|
5847
|
-
if (key === null) return;
|
|
5848
|
+
const key = serializeIndexEntry(values);
|
|
5848
5849
|
if (unique) this.checkUnique(values, rowid);
|
|
5849
5850
|
const existing = this.entries.get(key);
|
|
5850
5851
|
if (!existing) {
|
|
@@ -5857,15 +5858,15 @@ var IndexStore = class _IndexStore {
|
|
|
5857
5858
|
existing.push(rowid);
|
|
5858
5859
|
}
|
|
5859
5860
|
lookup(values) {
|
|
5860
|
-
|
|
5861
|
-
|
|
5861
|
+
if (values.some((value) => value === null)) return [];
|
|
5862
|
+
const key = serializeIndexEntry(values);
|
|
5862
5863
|
return this.entries.get(key) ?? [];
|
|
5863
5864
|
}
|
|
5864
5865
|
/** Leftmost prefix match: INDEX(a,b) used for WHERE a = ?. */
|
|
5865
5866
|
lookupPrefix(values) {
|
|
5866
5867
|
if (values.length === 0) return [];
|
|
5867
|
-
|
|
5868
|
-
|
|
5868
|
+
if (values.some((value) => value === null)) return [];
|
|
5869
|
+
const prefix = serializeIndexEntry(values);
|
|
5869
5870
|
const exact = this.entries.get(prefix);
|
|
5870
5871
|
const needle = `${prefix}|`;
|
|
5871
5872
|
const rowids = exact ? [...exact] : [];
|
|
@@ -5883,7 +5884,7 @@ var IndexStore = class _IndexStore {
|
|
|
5883
5884
|
const keys = this.orderedKeys();
|
|
5884
5885
|
for (const key of keys) {
|
|
5885
5886
|
const values = this.keyValues.get(key);
|
|
5886
|
-
if (!values || values[0] === void 0) continue;
|
|
5887
|
+
if (!values || values[0] === void 0 || values[0] === null) continue;
|
|
5887
5888
|
const cmp = compareSerializedOrder(values[0], bound);
|
|
5888
5889
|
let ok = false;
|
|
5889
5890
|
if (op === ">") ok = cmp > 0;
|
|
@@ -5912,8 +5913,7 @@ var IndexStore = class _IndexStore {
|
|
|
5912
5913
|
}
|
|
5913
5914
|
remove(values, rowid) {
|
|
5914
5915
|
this.assertMutable();
|
|
5915
|
-
const key =
|
|
5916
|
-
if (key === null) return false;
|
|
5916
|
+
const key = serializeIndexEntry(values);
|
|
5917
5917
|
const existing = this.entries.get(key);
|
|
5918
5918
|
if (!existing) return false;
|
|
5919
5919
|
if (rowid === void 0) {
|
|
@@ -5944,6 +5944,26 @@ var IndexStore = class _IndexStore {
|
|
|
5944
5944
|
freeze() {
|
|
5945
5945
|
this.frozen = true;
|
|
5946
5946
|
}
|
|
5947
|
+
/** Sorted entries for SQLM v3 persistence. */
|
|
5948
|
+
snapshotEntries() {
|
|
5949
|
+
const keys = [...this.entries.keys()].sort();
|
|
5950
|
+
return keys.map((key) => ({
|
|
5951
|
+
key,
|
|
5952
|
+
rowids: [...this.entries.get(key) ?? []],
|
|
5953
|
+
values: [...this.keyValues.get(key) ?? []]
|
|
5954
|
+
}));
|
|
5955
|
+
}
|
|
5956
|
+
/** Sorted keys + rowids for SQLM v4 (values rebuilt from the table). */
|
|
5957
|
+
snapshotKeys() {
|
|
5958
|
+
const keys = [...this.entries.keys()].sort();
|
|
5959
|
+
return keys.map((key) => ({
|
|
5960
|
+
key,
|
|
5961
|
+
rowids: [...this.entries.get(key) ?? []]
|
|
5962
|
+
}));
|
|
5963
|
+
}
|
|
5964
|
+
rememberKeyValues(key, values) {
|
|
5965
|
+
this.keyValues.set(key, [...values]);
|
|
5966
|
+
}
|
|
5947
5967
|
get size() {
|
|
5948
5968
|
return this.entries.size;
|
|
5949
5969
|
}
|
|
@@ -5956,7 +5976,12 @@ var IndexStore = class _IndexStore {
|
|
|
5956
5976
|
if (!left || !right) return a < b ? -1 : a > b ? 1 : 0;
|
|
5957
5977
|
const n = Math.min(left.length, right.length);
|
|
5958
5978
|
for (let i = 0; i < n; i++) {
|
|
5959
|
-
const
|
|
5979
|
+
const a2 = left[i] ?? null;
|
|
5980
|
+
const b2 = right[i] ?? null;
|
|
5981
|
+
if (a2 === null && b2 === null) continue;
|
|
5982
|
+
if (a2 === null) return -1;
|
|
5983
|
+
if (b2 === null) return 1;
|
|
5984
|
+
const cmp = compareSql(a2, b2);
|
|
5960
5985
|
if (cmp !== 0) return cmp ?? 0;
|
|
5961
5986
|
}
|
|
5962
5987
|
return left.length - right.length;
|
|
@@ -5970,8 +5995,15 @@ var IndexStore = class _IndexStore {
|
|
|
5970
5995
|
};
|
|
5971
5996
|
function serializeIndexKey(values) {
|
|
5972
5997
|
if (values.some((value) => value === null)) return null;
|
|
5973
|
-
return values
|
|
5998
|
+
return serializeIndexEntry(values);
|
|
5974
5999
|
}
|
|
6000
|
+
function serializeIndexEntry(values) {
|
|
6001
|
+
return values.map((value) => {
|
|
6002
|
+
const part = value === null ? NULL_PART : serializeValue(value);
|
|
6003
|
+
return `${part.length}:${part}`;
|
|
6004
|
+
}).join("|");
|
|
6005
|
+
}
|
|
6006
|
+
var NULL_PART = "z";
|
|
5975
6007
|
function serializeValue(value) {
|
|
5976
6008
|
if (isSqlReal(value)) {
|
|
5977
6009
|
const n = value.value;
|
|
@@ -6001,6 +6033,62 @@ function sameRowid(left, right) {
|
|
|
6001
6033
|
return typeof left === "bigint" || typeof right === "bigint" ? BigInt(left) === BigInt(right) : left === right;
|
|
6002
6034
|
}
|
|
6003
6035
|
|
|
6036
|
+
// src/storage/row.ts
|
|
6037
|
+
function normalizeColumnName(name) {
|
|
6038
|
+
return name.toLowerCase();
|
|
6039
|
+
}
|
|
6040
|
+
function rowValues(values) {
|
|
6041
|
+
const result = /* @__PURE__ */ new Map();
|
|
6042
|
+
const entries = values instanceof Map ? values.entries() : Object.entries(values);
|
|
6043
|
+
for (const [name, value] of entries) {
|
|
6044
|
+
result.set(normalizeColumnName(name), value);
|
|
6045
|
+
}
|
|
6046
|
+
return result;
|
|
6047
|
+
}
|
|
6048
|
+
function cloneRow(row) {
|
|
6049
|
+
const values = new Array(row.values.length);
|
|
6050
|
+
for (let i = 0; i < row.values.length; i++) values[i] = cloneSqlValue(row.values[i]);
|
|
6051
|
+
return { rowid: row.rowid, values };
|
|
6052
|
+
}
|
|
6053
|
+
function isValueArray(values) {
|
|
6054
|
+
return Array.isArray(values);
|
|
6055
|
+
}
|
|
6056
|
+
|
|
6057
|
+
// src/indexes/keys.ts
|
|
6058
|
+
function indexKeyValues(columns, row, ctx, table) {
|
|
6059
|
+
return columns.map((column) => {
|
|
6060
|
+
const raw = column.expr && ctx ? evalExpr(column.expr, ctx) : table ? table.cell(row, normalizeColumnName(column.name)) : null;
|
|
6061
|
+
return normalizeForCollation(raw, column.collate ?? "BINARY");
|
|
6062
|
+
});
|
|
6063
|
+
}
|
|
6064
|
+
function rebuildIndexFromTable(index, table, ctxForRow) {
|
|
6065
|
+
index.store.clear();
|
|
6066
|
+
for (const row of table.scan()) {
|
|
6067
|
+
const ctx = ctxForRow(row);
|
|
6068
|
+
if (index.where && isTruthySql(evalExpr(index.where, ctx)) !== true) continue;
|
|
6069
|
+
index.store.insert(indexKeyValues(index.columns, row, ctx, table), row.rowid, index.unique);
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
function tableRowEvalContext(table, row) {
|
|
6073
|
+
return {
|
|
6074
|
+
functions: defaultFunctionRegistry,
|
|
6075
|
+
resolveColumn: (qualifier, name) => {
|
|
6076
|
+
if (qualifier && qualifier.toLowerCase() !== table.name.toLowerCase()) {
|
|
6077
|
+
throw new SqliteError(`no such column: ${qualifier}.${name}`, "no_such_column");
|
|
6078
|
+
}
|
|
6079
|
+
const key = name.toLowerCase();
|
|
6080
|
+
if (key === "rowid" || key === "_rowid_" || key === "oid") return row.rowid;
|
|
6081
|
+
if (!table.hasColumn(key) && key !== "rowid") {
|
|
6082
|
+
throw new SqliteError(`no such column: ${name}`, "no_such_column");
|
|
6083
|
+
}
|
|
6084
|
+
return table.cell(row, key);
|
|
6085
|
+
},
|
|
6086
|
+
getParameter: () => {
|
|
6087
|
+
throw new SqliteError("parameters are not allowed in index predicates", "misuse");
|
|
6088
|
+
}
|
|
6089
|
+
};
|
|
6090
|
+
}
|
|
6091
|
+
|
|
6004
6092
|
// src/types/strict.ts
|
|
6005
6093
|
var STRICT_TYPES = /* @__PURE__ */ new Set(["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
|
|
6006
6094
|
function isStrictTypeName(typeName) {
|
|
@@ -7607,26 +7695,6 @@ var FtsVocabVirtualTable = class _FtsVocabVirtualTable {
|
|
|
7607
7695
|
}
|
|
7608
7696
|
};
|
|
7609
7697
|
|
|
7610
|
-
// src/storage/row.ts
|
|
7611
|
-
function normalizeColumnName(name) {
|
|
7612
|
-
return name.toLowerCase();
|
|
7613
|
-
}
|
|
7614
|
-
function rowValues(values) {
|
|
7615
|
-
const result = /* @__PURE__ */ new Map();
|
|
7616
|
-
const entries = values instanceof Map ? values.entries() : Object.entries(values);
|
|
7617
|
-
for (const [name, value] of entries) {
|
|
7618
|
-
result.set(normalizeColumnName(name), value);
|
|
7619
|
-
}
|
|
7620
|
-
return result;
|
|
7621
|
-
}
|
|
7622
|
-
function cloneRow(row) {
|
|
7623
|
-
const values = /* @__PURE__ */ new Map();
|
|
7624
|
-
for (const [name, value] of row.values) {
|
|
7625
|
-
values.set(name, cloneSqlValue(value));
|
|
7626
|
-
}
|
|
7627
|
-
return { rowid: row.rowid, values };
|
|
7628
|
-
}
|
|
7629
|
-
|
|
7630
7698
|
// src/storage/table.ts
|
|
7631
7699
|
var EQUALITY_HASH_MIN_ROWS = 16;
|
|
7632
7700
|
var Table = class _Table {
|
|
@@ -7647,6 +7715,8 @@ var Table = class _Table {
|
|
|
7647
7715
|
/** Cached maximum rowid. `undefined` means recompute after deleting the maximum. */
|
|
7648
7716
|
maximumRowid = null;
|
|
7649
7717
|
frozen = false;
|
|
7718
|
+
/** nameLower → column index; rebuilt after ALTER. */
|
|
7719
|
+
colIndex = /* @__PURE__ */ new Map();
|
|
7650
7720
|
constructor(name, columns, options = {}) {
|
|
7651
7721
|
this.name = name;
|
|
7652
7722
|
this.columns = columns.map(cloneColumn);
|
|
@@ -7659,6 +7729,44 @@ var Table = class _Table {
|
|
|
7659
7729
|
this.strict = options.strict ?? false;
|
|
7660
7730
|
this.clusteredRows = /* @__PURE__ */ new Map();
|
|
7661
7731
|
this.scanCache = null;
|
|
7732
|
+
this.rebuildColIndex();
|
|
7733
|
+
}
|
|
7734
|
+
rebuildColIndex() {
|
|
7735
|
+
this.colIndex = /* @__PURE__ */ new Map();
|
|
7736
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
7737
|
+
const column = this.columns[i];
|
|
7738
|
+
this.colIndex.set(column.nameLower ?? column.name.toLowerCase(), i);
|
|
7739
|
+
}
|
|
7740
|
+
}
|
|
7741
|
+
columnOffset(nameLower) {
|
|
7742
|
+
return this.colIndex.get(nameLower);
|
|
7743
|
+
}
|
|
7744
|
+
hasColumn(nameLower) {
|
|
7745
|
+
return this.colIndex.has(nameLower);
|
|
7746
|
+
}
|
|
7747
|
+
cell(row, nameLower) {
|
|
7748
|
+
const i = this.colIndex.get(nameLower);
|
|
7749
|
+
return i === void 0 ? null : row.values[i] ?? null;
|
|
7750
|
+
}
|
|
7751
|
+
setCell(row, nameLower, value) {
|
|
7752
|
+
const i = this.colIndex.get(nameLower);
|
|
7753
|
+
if (i === void 0) throw new SqliteError(`no such column: ${nameLower}`, "no_such_column");
|
|
7754
|
+
row.values[i] = value;
|
|
7755
|
+
}
|
|
7756
|
+
namedValues(row) {
|
|
7757
|
+
const map = /* @__PURE__ */ new Map();
|
|
7758
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
7759
|
+
const column = this.columns[i];
|
|
7760
|
+
map.set(column.nameLower ?? column.name.toLowerCase(), row.values[i] ?? null);
|
|
7761
|
+
}
|
|
7762
|
+
return map;
|
|
7763
|
+
}
|
|
7764
|
+
rowFromNamed(values, rowid = 0) {
|
|
7765
|
+
const cells = [];
|
|
7766
|
+
for (const column of this.columns) {
|
|
7767
|
+
cells.push(values.get(normalizeColumnName(column.name)) ?? null);
|
|
7768
|
+
}
|
|
7769
|
+
return { rowid, values: cells };
|
|
7662
7770
|
}
|
|
7663
7771
|
integerPkColumn() {
|
|
7664
7772
|
return this.integerPrimaryKeyAlias();
|
|
@@ -7727,7 +7835,7 @@ var Table = class _Table {
|
|
|
7727
7835
|
const map = /* @__PURE__ */ new Map();
|
|
7728
7836
|
const collate = column.collate ?? "BINARY";
|
|
7729
7837
|
for (const row of this.rows.values()) {
|
|
7730
|
-
const key = serializeIndexKey([normalizeForCollation(
|
|
7838
|
+
const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), collate)]);
|
|
7731
7839
|
if (key === null) continue;
|
|
7732
7840
|
const bucket = map.get(key);
|
|
7733
7841
|
if (bucket) bucket.push(row.rowid);
|
|
@@ -7743,9 +7851,7 @@ var Table = class _Table {
|
|
|
7743
7851
|
if (!this.equalityHashes) return;
|
|
7744
7852
|
for (const [columnLower, map] of this.equalityHashes) {
|
|
7745
7853
|
const column = this.columns.find((item) => item.nameLower === columnLower);
|
|
7746
|
-
const key = serializeIndexKey([
|
|
7747
|
-
normalizeForCollation(row.values.get(columnLower) ?? null, column?.collate ?? "BINARY")
|
|
7748
|
-
]);
|
|
7854
|
+
const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), column?.collate ?? "BINARY")]);
|
|
7749
7855
|
if (key === null) continue;
|
|
7750
7856
|
const bucket = map.get(key);
|
|
7751
7857
|
if (bucket) {
|
|
@@ -7757,9 +7863,7 @@ var Table = class _Table {
|
|
|
7757
7863
|
if (!this.equalityHashes) return;
|
|
7758
7864
|
for (const [columnLower, map] of this.equalityHashes) {
|
|
7759
7865
|
const column = this.columns.find((item) => item.nameLower === columnLower);
|
|
7760
|
-
const key = serializeIndexKey([
|
|
7761
|
-
normalizeForCollation(row.values.get(columnLower) ?? null, column?.collate ?? "BINARY")
|
|
7762
|
-
]);
|
|
7866
|
+
const key = serializeIndexKey([normalizeForCollation(this.cell(row, columnLower), column?.collate ?? "BINARY")]);
|
|
7763
7867
|
if (key === null) continue;
|
|
7764
7868
|
const bucket = map.get(key);
|
|
7765
7869
|
if (!bucket) continue;
|
|
@@ -7771,7 +7875,7 @@ var Table = class _Table {
|
|
|
7771
7875
|
insert(input, options) {
|
|
7772
7876
|
this.assertMutable();
|
|
7773
7877
|
const supplied = isInsertRow(input) ? input : { values: input };
|
|
7774
|
-
const values =
|
|
7878
|
+
const values = this.cellsFromInput(supplied.values, options?.prepared === true);
|
|
7775
7879
|
if (this.withoutRowid) {
|
|
7776
7880
|
if (supplied.rowid !== void 0) {
|
|
7777
7881
|
throw new SqliteError(`table ${this.name} has no column named rowid`, "other");
|
|
@@ -7792,7 +7896,7 @@ var Table = class _Table {
|
|
|
7792
7896
|
const alias = this.integerPrimaryKeyAlias();
|
|
7793
7897
|
let rowid = supplied.rowid;
|
|
7794
7898
|
if (alias) {
|
|
7795
|
-
const value =
|
|
7899
|
+
const value = this.cell({ rowid: 0, values }, normalizeColumnName(alias.name));
|
|
7796
7900
|
if (rowid === void 0 && value !== null) rowid = asRowid(value, alias.name);
|
|
7797
7901
|
}
|
|
7798
7902
|
rowid = canonicalRowid(rowid ?? this.allocateRowid());
|
|
@@ -7803,7 +7907,7 @@ var Table = class _Table {
|
|
|
7803
7907
|
"SQLITE_CONSTRAINT_PRIMARYKEY"
|
|
7804
7908
|
);
|
|
7805
7909
|
}
|
|
7806
|
-
if (alias)
|
|
7910
|
+
if (alias) this.setCell({ rowid, values }, normalizeColumnName(alias.name), rowid);
|
|
7807
7911
|
const candidate = { rowid, values };
|
|
7808
7912
|
if (!options?.skipValidate) this.validate(candidate);
|
|
7809
7913
|
this.rows.set(rowid, candidate);
|
|
@@ -7816,11 +7920,20 @@ var Table = class _Table {
|
|
|
7816
7920
|
const key = canonicalRowid(rowid);
|
|
7817
7921
|
const existing = this.rows.get(key);
|
|
7818
7922
|
if (!existing) return void 0;
|
|
7819
|
-
const values =
|
|
7820
|
-
const incoming = rowValues(updates);
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7923
|
+
const values = existing.values.slice();
|
|
7924
|
+
const incoming = isValueArray(updates) ? updates : rowValues(updates);
|
|
7925
|
+
if (isValueArray(updates)) {
|
|
7926
|
+
for (let i = 0; i < updates.length && i < this.columns.length; i++) {
|
|
7927
|
+
const column = this.columns[i];
|
|
7928
|
+
values[i] = applyAffinity(cloneSqlValue(updates[i] ?? null), column.affinity);
|
|
7929
|
+
}
|
|
7930
|
+
} else {
|
|
7931
|
+
for (const [name, value] of incoming) {
|
|
7932
|
+
const column = this.column(name);
|
|
7933
|
+
const offset = this.columnOffset(normalizeColumnName(column.name));
|
|
7934
|
+
if (offset === void 0) continue;
|
|
7935
|
+
values[offset] = applyAffinity(cloneSqlValue(value), column.affinity);
|
|
7936
|
+
}
|
|
7824
7937
|
}
|
|
7825
7938
|
if (this.withoutRowid) {
|
|
7826
7939
|
const oldClusterKey = this.makeClusterKey(existing.values);
|
|
@@ -7837,7 +7950,8 @@ var Table = class _Table {
|
|
|
7837
7950
|
return candidate2;
|
|
7838
7951
|
}
|
|
7839
7952
|
const alias = this.integerPrimaryKeyAlias();
|
|
7840
|
-
const
|
|
7953
|
+
const aliasRow = { rowid: key, values };
|
|
7954
|
+
const targetKey = alias ? asRowid(this.cell(aliasRow, normalizeColumnName(alias.name)), alias.name) : key;
|
|
7841
7955
|
if (targetKey !== key && this.rows.has(targetKey)) {
|
|
7842
7956
|
throw new SqliteError(
|
|
7843
7957
|
`UNIQUE constraint failed: ${this.name}.${alias?.name ?? "rowid"}`,
|
|
@@ -7845,7 +7959,7 @@ var Table = class _Table {
|
|
|
7845
7959
|
"SQLITE_CONSTRAINT_UNIQUE"
|
|
7846
7960
|
);
|
|
7847
7961
|
}
|
|
7848
|
-
if (alias)
|
|
7962
|
+
if (alias) this.setCell(aliasRow, normalizeColumnName(alias.name), targetKey);
|
|
7849
7963
|
const candidate = { rowid: targetKey, values };
|
|
7850
7964
|
this.validate(candidate, key);
|
|
7851
7965
|
if (targetKey !== key) {
|
|
@@ -7913,14 +8027,26 @@ var Table = class _Table {
|
|
|
7913
8027
|
this.invalidateScan();
|
|
7914
8028
|
this.clearEqualityHashes();
|
|
7915
8029
|
}
|
|
8030
|
+
cellsFromInput(input, prepared) {
|
|
8031
|
+
if (isValueArray(input)) {
|
|
8032
|
+
if (prepared && input.length === this.columns.length) return [...input];
|
|
8033
|
+
return this.prepareValues(namedFromArray(this, input));
|
|
8034
|
+
}
|
|
8035
|
+
if (prepared) {
|
|
8036
|
+
const named = rowValues(input);
|
|
8037
|
+
const cells = [];
|
|
8038
|
+
for (const column of this.columns) cells.push(named.get(normalizeColumnName(column.name)) ?? null);
|
|
8039
|
+
return cells;
|
|
8040
|
+
}
|
|
8041
|
+
return this.prepareValues(input);
|
|
8042
|
+
}
|
|
7916
8043
|
prepareValues(input) {
|
|
7917
8044
|
const supplied = rowValues(input);
|
|
7918
8045
|
for (const name of supplied.keys()) this.column(name);
|
|
7919
|
-
const result =
|
|
8046
|
+
const result = [];
|
|
7920
8047
|
for (const column of this.columns) {
|
|
7921
8048
|
const key = normalizeColumnName(column.name);
|
|
7922
|
-
result.
|
|
7923
|
-
key,
|
|
8049
|
+
result.push(
|
|
7924
8050
|
this.strict ? applyStrictValue(cloneSqlValue(supplied.get(key) ?? null), column.typeName ?? "", this.name, column.name) : applyAffinity(cloneSqlValue(supplied.get(key) ?? null), column.affinity)
|
|
7925
8051
|
);
|
|
7926
8052
|
}
|
|
@@ -7933,8 +8059,9 @@ var Table = class _Table {
|
|
|
7933
8059
|
return column;
|
|
7934
8060
|
}
|
|
7935
8061
|
validate(row, excludedRowid) {
|
|
7936
|
-
for (
|
|
7937
|
-
const
|
|
8062
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
8063
|
+
const column = this.columns[i];
|
|
8064
|
+
const value = row.values[i] ?? null;
|
|
7938
8065
|
if ((column.notNull || column.primaryKey) && value === null) {
|
|
7939
8066
|
const category = column.primaryKey ? "constraint_primary" : "constraint_notnull";
|
|
7940
8067
|
const code = column.primaryKey ? "SQLITE_CONSTRAINT_PRIMARYKEY" : "SQLITE_CONSTRAINT_NOTNULL";
|
|
@@ -7948,13 +8075,13 @@ var Table = class _Table {
|
|
|
7948
8075
|
const uniqueSets = this.uniqueColumnSets();
|
|
7949
8076
|
if (this.indexes.length === 0) {
|
|
7950
8077
|
for (const names of uniqueSets) {
|
|
7951
|
-
const values = names.map((name) =>
|
|
8078
|
+
const values = names.map((name) => this.cell(row, normalizeColumnName(name)));
|
|
7952
8079
|
if (values.some((value) => value === null)) continue;
|
|
7953
8080
|
for (const other of this.rows.values()) {
|
|
7954
8081
|
if (excludedRowid !== void 0 && other.rowid === excludedRowid) continue;
|
|
7955
8082
|
if (values.every((value, index) => {
|
|
7956
8083
|
const column = this.column(names[index]);
|
|
7957
|
-
const otherValue =
|
|
8084
|
+
const otherValue = this.cell(other, normalizeColumnName(names[index]));
|
|
7958
8085
|
const collation = column.collate ?? "BINARY";
|
|
7959
8086
|
return compareWithCollation(value, otherValue, collation) === 0;
|
|
7960
8087
|
})) {
|
|
@@ -7992,15 +8119,17 @@ var Table = class _Table {
|
|
|
7992
8119
|
}
|
|
7993
8120
|
makeClusterKey(values) {
|
|
7994
8121
|
return this.primaryKeyColumns().map((column) => {
|
|
7995
|
-
const
|
|
8122
|
+
const offset = this.columnOffset(normalizeColumnName(column.name)) ?? 0;
|
|
8123
|
+
const value = values[offset] ?? null;
|
|
7996
8124
|
const normalized = normalizeForCollation(value, column.collate ?? "BINARY");
|
|
7997
8125
|
return serializePkComponent(normalized);
|
|
7998
8126
|
}).join("\0");
|
|
7999
8127
|
}
|
|
8000
8128
|
comparePrimaryKeys(left, right) {
|
|
8001
8129
|
for (const column of this.primaryKeyColumns()) {
|
|
8002
|
-
const
|
|
8003
|
-
const
|
|
8130
|
+
const key = normalizeColumnName(column.name);
|
|
8131
|
+
const leftValue = this.cell(left, key);
|
|
8132
|
+
const rightValue = this.cell(right, key);
|
|
8004
8133
|
const comparison = column.collate ? compareWithCollation(leftValue, rightValue, column.collate) : compareSql(leftValue, rightValue);
|
|
8005
8134
|
if (comparison !== 0) return comparison ?? 0;
|
|
8006
8135
|
}
|
|
@@ -8054,7 +8183,14 @@ function cloneAst(value) {
|
|
|
8054
8183
|
return structuredClone(value);
|
|
8055
8184
|
}
|
|
8056
8185
|
function isInsertRow(input) {
|
|
8057
|
-
return !(input instanceof Map) && "values" in input;
|
|
8186
|
+
return typeof input === "object" && input !== null && !Array.isArray(input) && !(input instanceof Map) && "values" in input;
|
|
8187
|
+
}
|
|
8188
|
+
function namedFromArray(table, values) {
|
|
8189
|
+
const named = /* @__PURE__ */ new Map();
|
|
8190
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
8191
|
+
named.set(normalizeColumnName(table.columns[i].name), values[i] ?? null);
|
|
8192
|
+
}
|
|
8193
|
+
return named;
|
|
8058
8194
|
}
|
|
8059
8195
|
function asRowid(value, column) {
|
|
8060
8196
|
if (typeof value === "bigint") return canonicalRowid(value);
|
|
@@ -8664,10 +8800,13 @@ function keyOf(name) {
|
|
|
8664
8800
|
|
|
8665
8801
|
// src/serialization/codec.ts
|
|
8666
8802
|
var MAGIC = utf8Encode("SQLM");
|
|
8667
|
-
var VERSION =
|
|
8803
|
+
var VERSION = 4;
|
|
8668
8804
|
var VERSION_V1 = 1;
|
|
8805
|
+
var VERSION_V2 = 2;
|
|
8806
|
+
var VERSION_V3 = 3;
|
|
8669
8807
|
var Writer = class {
|
|
8670
|
-
buf = new Uint8Array(
|
|
8808
|
+
buf = new Uint8Array(4096);
|
|
8809
|
+
view = new DataView(this.buf.buffer);
|
|
8671
8810
|
len = 0;
|
|
8672
8811
|
ensure(needed) {
|
|
8673
8812
|
if (this.len + needed <= this.buf.length) return;
|
|
@@ -8676,6 +8815,7 @@ var Writer = class {
|
|
|
8676
8815
|
const next = new Uint8Array(cap);
|
|
8677
8816
|
next.set(this.buf.subarray(0, this.len));
|
|
8678
8817
|
this.buf = next;
|
|
8818
|
+
this.view = new DataView(next.buffer);
|
|
8679
8819
|
}
|
|
8680
8820
|
u8(value) {
|
|
8681
8821
|
this.ensure(1);
|
|
@@ -8683,20 +8823,23 @@ var Writer = class {
|
|
|
8683
8823
|
}
|
|
8684
8824
|
u32(value) {
|
|
8685
8825
|
this.ensure(4);
|
|
8686
|
-
this.
|
|
8687
|
-
this.
|
|
8688
|
-
this.buf[this.len++] = value >>> 16 & 255;
|
|
8689
|
-
this.buf[this.len++] = value >>> 24 & 255;
|
|
8826
|
+
this.view.setUint32(this.len, value >>> 0, true);
|
|
8827
|
+
this.len += 4;
|
|
8690
8828
|
}
|
|
8691
8829
|
u64(value) {
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
this.
|
|
8830
|
+
this.ensure(8);
|
|
8831
|
+
this.view.setBigUint64(this.len, BigInt.asUintN(64, value), true);
|
|
8832
|
+
this.len += 8;
|
|
8695
8833
|
}
|
|
8696
8834
|
i64(value) {
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
this.
|
|
8835
|
+
this.ensure(8);
|
|
8836
|
+
this.view.setBigInt64(this.len, value, true);
|
|
8837
|
+
this.len += 8;
|
|
8838
|
+
}
|
|
8839
|
+
f64(value) {
|
|
8840
|
+
this.ensure(8);
|
|
8841
|
+
this.view.setFloat64(this.len, value, true);
|
|
8842
|
+
this.len += 8;
|
|
8700
8843
|
}
|
|
8701
8844
|
raw(value) {
|
|
8702
8845
|
this.ensure(value.length);
|
|
@@ -8718,23 +8861,17 @@ var Writer = class {
|
|
|
8718
8861
|
}
|
|
8719
8862
|
if (value instanceof SqlReal) {
|
|
8720
8863
|
this.u8(2);
|
|
8721
|
-
|
|
8722
|
-
new DataView(bytes.buffer).setFloat64(0, value.value, true);
|
|
8723
|
-
this.raw(bytes);
|
|
8864
|
+
this.f64(value.value);
|
|
8724
8865
|
return;
|
|
8725
8866
|
}
|
|
8726
8867
|
if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) {
|
|
8727
8868
|
this.u8(1);
|
|
8728
|
-
|
|
8729
|
-
new DataView(bytes.buffer).setBigInt64(0, BigInt(value), true);
|
|
8730
|
-
this.raw(bytes);
|
|
8869
|
+
this.i64(BigInt(value));
|
|
8731
8870
|
return;
|
|
8732
8871
|
}
|
|
8733
8872
|
if (typeof value === "number") {
|
|
8734
8873
|
this.u8(2);
|
|
8735
|
-
|
|
8736
|
-
new DataView(bytes.buffer).setFloat64(0, value, true);
|
|
8737
|
-
this.raw(bytes);
|
|
8874
|
+
this.f64(value);
|
|
8738
8875
|
return;
|
|
8739
8876
|
}
|
|
8740
8877
|
if (typeof value === "string") {
|
|
@@ -8753,39 +8890,54 @@ var Writer = class {
|
|
|
8753
8890
|
}
|
|
8754
8891
|
finish() {
|
|
8755
8892
|
if (this.len === this.buf.length) return this.buf;
|
|
8756
|
-
return this.buf.
|
|
8893
|
+
return this.buf.subarray(0, this.len).slice();
|
|
8757
8894
|
}
|
|
8758
8895
|
};
|
|
8759
8896
|
var Reader = class {
|
|
8760
8897
|
constructor(bytes) {
|
|
8761
8898
|
this.bytes = bytes;
|
|
8899
|
+
this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
8762
8900
|
}
|
|
8763
8901
|
bytes;
|
|
8764
8902
|
offset = 0;
|
|
8903
|
+
view;
|
|
8765
8904
|
u8() {
|
|
8766
8905
|
if (this.offset >= this.bytes.length) this.fail();
|
|
8767
8906
|
return this.bytes[this.offset++];
|
|
8768
8907
|
}
|
|
8769
8908
|
u32() {
|
|
8770
8909
|
if (this.offset + 4 > this.bytes.length) this.fail();
|
|
8771
|
-
const value =
|
|
8910
|
+
const value = this.view.getUint32(this.offset, true);
|
|
8772
8911
|
this.offset += 4;
|
|
8773
8912
|
return value;
|
|
8774
8913
|
}
|
|
8775
8914
|
u64() {
|
|
8776
|
-
|
|
8777
|
-
|
|
8915
|
+
if (this.offset + 8 > this.bytes.length) this.fail();
|
|
8916
|
+
const value = this.view.getBigUint64(this.offset, true);
|
|
8917
|
+
this.offset += 8;
|
|
8918
|
+
return value;
|
|
8778
8919
|
}
|
|
8779
8920
|
i64() {
|
|
8780
|
-
|
|
8781
|
-
|
|
8921
|
+
if (this.offset + 8 > this.bytes.length) this.fail();
|
|
8922
|
+
const value = this.view.getBigInt64(this.offset, true);
|
|
8923
|
+
this.offset += 8;
|
|
8924
|
+
return value;
|
|
8925
|
+
}
|
|
8926
|
+
f64() {
|
|
8927
|
+
if (this.offset + 8 > this.bytes.length) this.fail();
|
|
8928
|
+
const value = this.view.getFloat64(this.offset, true);
|
|
8929
|
+
this.offset += 8;
|
|
8930
|
+
return value;
|
|
8782
8931
|
}
|
|
8783
8932
|
raw(length) {
|
|
8784
8933
|
if (length < 0 || this.offset + length > this.bytes.length) this.fail();
|
|
8785
|
-
const value = this.bytes.
|
|
8934
|
+
const value = this.bytes.subarray(this.offset, this.offset + length);
|
|
8786
8935
|
this.offset += length;
|
|
8787
8936
|
return value;
|
|
8788
8937
|
}
|
|
8938
|
+
owned(length) {
|
|
8939
|
+
return this.raw(length).slice();
|
|
8940
|
+
}
|
|
8789
8941
|
text() {
|
|
8790
8942
|
return utf8Decode(this.raw(this.u32()));
|
|
8791
8943
|
}
|
|
@@ -8800,17 +8952,15 @@ var Reader = class {
|
|
|
8800
8952
|
const tag = this.u8();
|
|
8801
8953
|
if (tag === 0) return null;
|
|
8802
8954
|
if (tag === 1) {
|
|
8803
|
-
const
|
|
8804
|
-
const integer = new DataView(bytes.buffer, bytes.byteOffset, 8).getBigInt64(0, true);
|
|
8955
|
+
const integer = this.i64();
|
|
8805
8956
|
return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
|
|
8806
8957
|
}
|
|
8807
8958
|
if (tag === 2) {
|
|
8808
|
-
const
|
|
8809
|
-
const value = new DataView(bytes.buffer, bytes.byteOffset, 8).getFloat64(0, true);
|
|
8959
|
+
const value = this.f64();
|
|
8810
8960
|
return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
|
|
8811
8961
|
}
|
|
8812
8962
|
if (tag === 3) return this.text();
|
|
8813
|
-
if (tag === 4) return this.
|
|
8963
|
+
if (tag === 4) return this.owned(this.u32());
|
|
8814
8964
|
this.fail();
|
|
8815
8965
|
}
|
|
8816
8966
|
remaining() {
|
|
@@ -8823,10 +8973,14 @@ var Reader = class {
|
|
|
8823
8973
|
throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
|
|
8824
8974
|
}
|
|
8825
8975
|
};
|
|
8826
|
-
function encodeDatabaseState(state, runtime) {
|
|
8976
|
+
function encodeDatabaseState(state, runtime, formatVersion = VERSION) {
|
|
8977
|
+
if (formatVersion >= 4) return encodeV4(state, runtime);
|
|
8978
|
+
return encodeLegacy(state, runtime, formatVersion);
|
|
8979
|
+
}
|
|
8980
|
+
function encodeLegacy(state, runtime, formatVersion) {
|
|
8827
8981
|
const writer = new Writer();
|
|
8828
8982
|
writer.raw(MAGIC);
|
|
8829
|
-
writer.u32(
|
|
8983
|
+
writer.u32(formatVersion);
|
|
8830
8984
|
writer.u8(state.foreignKeysEnabled ? 1 : 0);
|
|
8831
8985
|
writer.u32(state.schemaVersion);
|
|
8832
8986
|
writer.u32(state.changes);
|
|
@@ -8849,7 +9003,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
8849
9003
|
for (const row of rows) {
|
|
8850
9004
|
writer.value(row.rowid);
|
|
8851
9005
|
writer.u32(table.columns.length);
|
|
8852
|
-
for (const column of table.columns) writer.value(
|
|
9006
|
+
for (const column of table.columns) writer.value(table.cell(row, column.nameLower ?? column.name.toLowerCase()));
|
|
8853
9007
|
}
|
|
8854
9008
|
}
|
|
8855
9009
|
const views = sortedValues(state.views);
|
|
@@ -8867,8 +9021,13 @@ function encodeDatabaseState(state, runtime) {
|
|
|
8867
9021
|
originalSql: index.originalSql
|
|
8868
9022
|
});
|
|
8869
9023
|
}
|
|
8870
|
-
|
|
8871
|
-
|
|
9024
|
+
if (formatVersion >= 3) {
|
|
9025
|
+
for (const index of indexes) writeIndexStore(writer, index.store);
|
|
9026
|
+
}
|
|
9027
|
+
if (formatVersion >= VERSION_V2) {
|
|
9028
|
+
writer.u64(runtime.prngState);
|
|
9029
|
+
writer.i64(BigInt(Math.trunc(runtime.nowMs)));
|
|
9030
|
+
}
|
|
8872
9031
|
return writer.finish();
|
|
8873
9032
|
}
|
|
8874
9033
|
function decodeDatabaseState(snapshot) {
|
|
@@ -8885,9 +9044,10 @@ function decodeDatabaseStateInner(snapshot) {
|
|
|
8885
9044
|
if (!magic.every((byte, index) => byte === MAGIC[index]))
|
|
8886
9045
|
throw new SqliteError("invalid sqlite-mem snapshot magic", "other");
|
|
8887
9046
|
const version = reader.u32();
|
|
8888
|
-
if (version
|
|
9047
|
+
if (version < VERSION_V1 || version > VERSION) {
|
|
8889
9048
|
throw new SqliteError(`unsupported sqlite-mem snapshot version: ${version}`, "snapshot_version", "SQLITE_FORMAT");
|
|
8890
9049
|
}
|
|
9050
|
+
if (version > VERSION_V3) return decodeV4(reader);
|
|
8891
9051
|
const state = new DatabaseState();
|
|
8892
9052
|
state.foreignKeysEnabled = reader.u8() !== 0;
|
|
8893
9053
|
state.schemaVersion = reader.u32();
|
|
@@ -8910,8 +9070,8 @@ function decodeDatabaseStateInner(snapshot) {
|
|
|
8910
9070
|
const rowid = asRowid2(reader.value());
|
|
8911
9071
|
const valueCount = reader.u32();
|
|
8912
9072
|
if (valueCount !== table.columns.length) throw new SqliteError("snapshot row column count mismatch", "other");
|
|
8913
|
-
const values =
|
|
8914
|
-
for (
|
|
9073
|
+
const values = [];
|
|
9074
|
+
for (let i = 0; i < valueCount; i++) values.push(reader.value());
|
|
8915
9075
|
table.rows.set(rowid, { rowid, values });
|
|
8916
9076
|
}
|
|
8917
9077
|
table.rebuildClusteredRows();
|
|
@@ -8923,50 +9083,63 @@ function decodeDatabaseStateInner(snapshot) {
|
|
|
8923
9083
|
state.views.set(view.name.toLowerCase(), view);
|
|
8924
9084
|
}
|
|
8925
9085
|
const indexCount = reader.u32();
|
|
9086
|
+
const loadedIndexes = [];
|
|
8926
9087
|
for (let indexPosition = 0; indexPosition < indexCount; indexPosition++) {
|
|
8927
9088
|
const meta = reader.json();
|
|
8928
9089
|
const info = { ...meta, store: new IndexStore(meta.name) };
|
|
8929
9090
|
state.indexes.set(info.name.toLowerCase(), info);
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
resolveColumn: (qualifier, name) => {
|
|
8936
|
-
if (qualifier && qualifier.toLowerCase() !== table.name.toLowerCase()) {
|
|
8937
|
-
throw new SqliteError(`no such column: ${qualifier}.${name}`, "no_such_column");
|
|
8938
|
-
}
|
|
8939
|
-
if (name.toLowerCase() === "rowid") return row.rowid;
|
|
8940
|
-
if (!row.values.has(name.toLowerCase()))
|
|
8941
|
-
throw new SqliteError(`no such column: ${name}`, "no_such_column");
|
|
8942
|
-
return row.values.get(name.toLowerCase()) ?? null;
|
|
8943
|
-
},
|
|
8944
|
-
getParameter: () => {
|
|
8945
|
-
throw new SqliteError("parameters are not allowed in index predicates", "misuse");
|
|
8946
|
-
}
|
|
8947
|
-
})
|
|
8948
|
-
) !== true)
|
|
8949
|
-
continue;
|
|
8950
|
-
info.store.insert(
|
|
8951
|
-
info.columns.map(
|
|
8952
|
-
(column) => normalizeForCollation(row.values.get(column.name.toLowerCase()) ?? null, column.collate ?? "BINARY")
|
|
8953
|
-
),
|
|
8954
|
-
row.rowid,
|
|
8955
|
-
info.unique
|
|
8956
|
-
);
|
|
9091
|
+
loadedIndexes.push(info);
|
|
9092
|
+
}
|
|
9093
|
+
if (version >= 3) {
|
|
9094
|
+
for (const info of loadedIndexes) {
|
|
9095
|
+
info.store = readIndexStore(reader, info.name);
|
|
8957
9096
|
}
|
|
9097
|
+
} else {
|
|
9098
|
+
for (const info of loadedIndexes) rebuildIndexStore(state, info);
|
|
8958
9099
|
}
|
|
8959
9100
|
let runtime = null;
|
|
8960
|
-
if (version >=
|
|
9101
|
+
if (version >= VERSION_V2) {
|
|
8961
9102
|
if (reader.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
|
|
8962
9103
|
runtime = {
|
|
8963
9104
|
prngState: reader.u64(),
|
|
8964
|
-
nowMs: Number(reader.i64())
|
|
9105
|
+
nowMs: finiteNowMs(Number(reader.i64()))
|
|
8965
9106
|
};
|
|
8966
9107
|
}
|
|
8967
9108
|
if (!reader.done()) throw new SqliteError("snapshot has trailing data", "other");
|
|
8968
9109
|
return { state, runtime };
|
|
8969
9110
|
}
|
|
9111
|
+
function writeIndexStore(writer, store) {
|
|
9112
|
+
const entries = store.snapshotEntries();
|
|
9113
|
+
writer.u32(entries.length);
|
|
9114
|
+
for (const entry of entries) {
|
|
9115
|
+
writer.text(entry.key);
|
|
9116
|
+
writer.u32(entry.rowids.length);
|
|
9117
|
+
for (const id of entry.rowids) writer.value(id);
|
|
9118
|
+
writer.u32(entry.values.length);
|
|
9119
|
+
for (const value of entry.values) writer.value(value);
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9122
|
+
function readIndexStore(reader, name) {
|
|
9123
|
+
const count = reader.u32();
|
|
9124
|
+
const entries = /* @__PURE__ */ new Map();
|
|
9125
|
+
const keyValues = /* @__PURE__ */ new Map();
|
|
9126
|
+
for (let i = 0; i < count; i++) {
|
|
9127
|
+
const key = reader.text();
|
|
9128
|
+
const rowidCount = reader.u32();
|
|
9129
|
+
const rowids = [];
|
|
9130
|
+
for (let r = 0; r < rowidCount; r++) rowids.push(asRowid2(reader.value()));
|
|
9131
|
+
const valueCount = reader.u32();
|
|
9132
|
+
const values = [];
|
|
9133
|
+
for (let v = 0; v < valueCount; v++) values.push(reader.value());
|
|
9134
|
+
entries.set(key, rowids);
|
|
9135
|
+
keyValues.set(key, values);
|
|
9136
|
+
}
|
|
9137
|
+
return new IndexStore(name, entries, keyValues);
|
|
9138
|
+
}
|
|
9139
|
+
function rebuildIndexStore(state, info) {
|
|
9140
|
+
const table = state.getTable(info.tableName);
|
|
9141
|
+
rebuildIndexFromTable(info, table, (row) => tableRowEvalContext(table, row));
|
|
9142
|
+
}
|
|
8970
9143
|
function asRowid2(value) {
|
|
8971
9144
|
if (typeof value === "number" && Number.isSafeInteger(value) || typeof value === "bigint") return value;
|
|
8972
9145
|
throw new SqliteError("invalid rowid in snapshot", "other");
|
|
@@ -8974,6 +9147,13 @@ function asRowid2(value) {
|
|
|
8974
9147
|
function compareNames(a, b) {
|
|
8975
9148
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
8976
9149
|
}
|
|
9150
|
+
function finiteNowMs(value) {
|
|
9151
|
+
if (!Number.isFinite(value)) return 0;
|
|
9152
|
+
const max = 864e13;
|
|
9153
|
+
if (value > max) return max;
|
|
9154
|
+
if (value < -max) return -max;
|
|
9155
|
+
return value;
|
|
9156
|
+
}
|
|
8977
9157
|
function compareRowids2(a, b) {
|
|
8978
9158
|
const left = typeof a === "bigint" ? a : BigInt(a);
|
|
8979
9159
|
const right = typeof b === "bigint" ? b : BigInt(b);
|
|
@@ -8996,6 +9176,323 @@ function jsonReviver(_key, value) {
|
|
|
8996
9176
|
if (tagged.$sqlm === "blob") return Uint8Array.from(tagged.value);
|
|
8997
9177
|
return value;
|
|
8998
9178
|
}
|
|
9179
|
+
var PACK_NULL = 0;
|
|
9180
|
+
var PACK_INT = 1;
|
|
9181
|
+
var PACK_FLOAT = 2;
|
|
9182
|
+
var PACK_TEXT = 3;
|
|
9183
|
+
var PACK_BLOB = 4;
|
|
9184
|
+
var PACK_TAGGED = 5;
|
|
9185
|
+
var AFFINITIES = ["TEXT", "NUMERIC", "INTEGER", "REAL", "BLOB"];
|
|
9186
|
+
function encodeV4(state, runtime) {
|
|
9187
|
+
const intern = /* @__PURE__ */ new Map();
|
|
9188
|
+
const internList = [];
|
|
9189
|
+
const internId = (s) => {
|
|
9190
|
+
const hit = intern.get(s);
|
|
9191
|
+
if (hit !== void 0) return hit;
|
|
9192
|
+
const id = internList.length;
|
|
9193
|
+
intern.set(s, id);
|
|
9194
|
+
internList.push(s);
|
|
9195
|
+
return id;
|
|
9196
|
+
};
|
|
9197
|
+
internId("");
|
|
9198
|
+
const tables = sortedValues(state.tables);
|
|
9199
|
+
const views = sortedValues(state.views);
|
|
9200
|
+
const indexes = sortedValues(state.indexes);
|
|
9201
|
+
for (const table of tables) {
|
|
9202
|
+
internId(table.name);
|
|
9203
|
+
internId(table.originalSql ?? "");
|
|
9204
|
+
for (const column of table.columns) {
|
|
9205
|
+
internId(column.name);
|
|
9206
|
+
internId(column.typeName ?? "");
|
|
9207
|
+
internId(column.collate ?? "");
|
|
9208
|
+
}
|
|
9209
|
+
for (const name of table.indexes) internId(name);
|
|
9210
|
+
for (const row of table.rows.values()) {
|
|
9211
|
+
for (const value of row.values) {
|
|
9212
|
+
if (typeof value === "string") internId(value);
|
|
9213
|
+
else if (value instanceof SqlJsonText) internId(value.value);
|
|
9214
|
+
}
|
|
9215
|
+
}
|
|
9216
|
+
}
|
|
9217
|
+
const w = new Writer();
|
|
9218
|
+
w.raw(MAGIC);
|
|
9219
|
+
w.u32(VERSION);
|
|
9220
|
+
w.u8(state.foreignKeysEnabled ? 1 : 0);
|
|
9221
|
+
w.u32(state.schemaVersion);
|
|
9222
|
+
w.u32(state.changes);
|
|
9223
|
+
w.u32(state.totalChanges);
|
|
9224
|
+
w.value(state.lastInsertRowid);
|
|
9225
|
+
w.u32(internList.length);
|
|
9226
|
+
for (const s of internList) w.text(s);
|
|
9227
|
+
w.u32(tables.length);
|
|
9228
|
+
for (const table of tables) {
|
|
9229
|
+
w.u32(internId(table.name));
|
|
9230
|
+
w.u32(table.columns.length);
|
|
9231
|
+
for (const column of table.columns) {
|
|
9232
|
+
w.u32(internId(column.name));
|
|
9233
|
+
w.u32(internId(column.typeName ?? ""));
|
|
9234
|
+
const aff = AFFINITIES.indexOf(column.affinity);
|
|
9235
|
+
w.u8(aff < 0 ? 2 : aff);
|
|
9236
|
+
w.u8(
|
|
9237
|
+
(column.notNull ? 1 : 0) | (column.primaryKey ? 2 : 0) | (column.autoincrement ? 4 : 0) | (column.unique ? 8 : 0)
|
|
9238
|
+
);
|
|
9239
|
+
w.u32(internId(column.collate ?? ""));
|
|
9240
|
+
if (column.defaultExpr) {
|
|
9241
|
+
w.u8(1);
|
|
9242
|
+
w.json(column.defaultExpr);
|
|
9243
|
+
} else w.u8(0);
|
|
9244
|
+
if (column.generated) {
|
|
9245
|
+
w.u8(1);
|
|
9246
|
+
w.json(column.generated);
|
|
9247
|
+
} else w.u8(0);
|
|
9248
|
+
}
|
|
9249
|
+
w.json(table.constraints);
|
|
9250
|
+
w.u32(internId(table.originalSql ?? ""));
|
|
9251
|
+
w.u8((table.withoutRowid ? 1 : 0) | (table.strict ? 2 : 0));
|
|
9252
|
+
const indexNames = [...table.indexes].sort(compareNames);
|
|
9253
|
+
w.u32(indexNames.length);
|
|
9254
|
+
for (const name of indexNames) w.u32(internId(name));
|
|
9255
|
+
w.value(table.nextRowid);
|
|
9256
|
+
const rows = [...table.rows.values()].sort((a, b) => compareRowids2(a.rowid, b.rowid));
|
|
9257
|
+
w.u32(rows.length);
|
|
9258
|
+
for (const row of rows) w.value(row.rowid);
|
|
9259
|
+
for (let c = 0; c < table.columns.length; c++) {
|
|
9260
|
+
writePackedColumn(w, rows, c, internId);
|
|
9261
|
+
}
|
|
9262
|
+
}
|
|
9263
|
+
w.u32(views.length);
|
|
9264
|
+
for (const view of views) w.json(view);
|
|
9265
|
+
w.u32(indexes.length);
|
|
9266
|
+
for (const index of indexes) {
|
|
9267
|
+
w.json({
|
|
9268
|
+
name: index.name,
|
|
9269
|
+
tableName: index.tableName,
|
|
9270
|
+
unique: index.unique,
|
|
9271
|
+
columns: index.columns,
|
|
9272
|
+
where: index.where,
|
|
9273
|
+
originalSql: index.originalSql
|
|
9274
|
+
});
|
|
9275
|
+
}
|
|
9276
|
+
for (const index of indexes) {
|
|
9277
|
+
const entries = index.store.snapshotKeys();
|
|
9278
|
+
w.u32(entries.length);
|
|
9279
|
+
for (const entry of entries) {
|
|
9280
|
+
w.text(entry.key);
|
|
9281
|
+
w.u32(entry.rowids.length);
|
|
9282
|
+
for (const id of entry.rowids) w.value(id);
|
|
9283
|
+
}
|
|
9284
|
+
}
|
|
9285
|
+
w.u64(runtime.prngState);
|
|
9286
|
+
w.i64(BigInt(Math.trunc(runtime.nowMs)));
|
|
9287
|
+
return w.finish();
|
|
9288
|
+
}
|
|
9289
|
+
function writePackedColumn(w, rows, col, internId) {
|
|
9290
|
+
const n = rows.length;
|
|
9291
|
+
if (n === 0) {
|
|
9292
|
+
w.u8(PACK_NULL);
|
|
9293
|
+
return;
|
|
9294
|
+
}
|
|
9295
|
+
const bits = new Uint8Array(n + 7 >> 3);
|
|
9296
|
+
let nulls = 0;
|
|
9297
|
+
let kind = null;
|
|
9298
|
+
for (let i = 0; i < n; i++) {
|
|
9299
|
+
const value = rows[i].values[col] ?? null;
|
|
9300
|
+
if (value === null) {
|
|
9301
|
+
bits[i >> 3] = bits[i >> 3] | 1 << (i & 7);
|
|
9302
|
+
nulls++;
|
|
9303
|
+
continue;
|
|
9304
|
+
}
|
|
9305
|
+
const cellKind = packKindOf(value);
|
|
9306
|
+
if (kind === null) kind = cellKind;
|
|
9307
|
+
else if (kind !== cellKind) kind = PACK_TAGGED;
|
|
9308
|
+
}
|
|
9309
|
+
if (nulls === n) {
|
|
9310
|
+
w.u8(PACK_NULL);
|
|
9311
|
+
return;
|
|
9312
|
+
}
|
|
9313
|
+
const pack = kind ?? PACK_TAGGED;
|
|
9314
|
+
w.u8(pack);
|
|
9315
|
+
w.raw(bits);
|
|
9316
|
+
for (let i = 0; i < n; i++) {
|
|
9317
|
+
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
9318
|
+
const value = rows[i].values[col];
|
|
9319
|
+
writePackedCell(w, pack, value, internId);
|
|
9320
|
+
}
|
|
9321
|
+
}
|
|
9322
|
+
function packKindOf(value) {
|
|
9323
|
+
if (value instanceof SqlReal) return PACK_FLOAT;
|
|
9324
|
+
if (typeof value === "bigint" || typeof value === "number" && Number.isInteger(value)) return PACK_INT;
|
|
9325
|
+
if (typeof value === "number") return PACK_FLOAT;
|
|
9326
|
+
if (value instanceof SqlJsonText) return PACK_TAGGED;
|
|
9327
|
+
if (typeof value === "string") return PACK_TEXT;
|
|
9328
|
+
if (value instanceof Uint8Array) return PACK_BLOB;
|
|
9329
|
+
return PACK_TAGGED;
|
|
9330
|
+
}
|
|
9331
|
+
function writePackedCell(w, pack, value, internId) {
|
|
9332
|
+
if (pack === PACK_INT) {
|
|
9333
|
+
w.i64(typeof value === "bigint" ? value : BigInt(value));
|
|
9334
|
+
return;
|
|
9335
|
+
}
|
|
9336
|
+
if (pack === PACK_FLOAT) {
|
|
9337
|
+
w.f64(value instanceof SqlReal ? value.value : value);
|
|
9338
|
+
return;
|
|
9339
|
+
}
|
|
9340
|
+
if (pack === PACK_TEXT) {
|
|
9341
|
+
const text2 = value instanceof SqlJsonText ? value.value : value;
|
|
9342
|
+
w.u32(internId(text2));
|
|
9343
|
+
return;
|
|
9344
|
+
}
|
|
9345
|
+
if (pack === PACK_BLOB) {
|
|
9346
|
+
const blob = value;
|
|
9347
|
+
w.u32(blob.length);
|
|
9348
|
+
w.raw(blob);
|
|
9349
|
+
return;
|
|
9350
|
+
}
|
|
9351
|
+
w.value(value);
|
|
9352
|
+
}
|
|
9353
|
+
function decodeV4(reader) {
|
|
9354
|
+
const state = new DatabaseState();
|
|
9355
|
+
state.foreignKeysEnabled = reader.u8() !== 0;
|
|
9356
|
+
state.schemaVersion = reader.u32();
|
|
9357
|
+
state.changes = reader.u32();
|
|
9358
|
+
state.totalChanges = reader.u32();
|
|
9359
|
+
state.lastInsertRowid = asRowid2(reader.value());
|
|
9360
|
+
const internCount = reader.u32();
|
|
9361
|
+
const intern = [];
|
|
9362
|
+
for (let i = 0; i < internCount; i++) intern.push(reader.text());
|
|
9363
|
+
const str = (id) => intern[id] ?? "";
|
|
9364
|
+
const tableCount = reader.u32();
|
|
9365
|
+
for (let t = 0; t < tableCount; t++) {
|
|
9366
|
+
const name = str(reader.u32());
|
|
9367
|
+
const colCount = reader.u32();
|
|
9368
|
+
const columns = [];
|
|
9369
|
+
for (let c = 0; c < colCount; c++) {
|
|
9370
|
+
const colName = str(reader.u32());
|
|
9371
|
+
const typeName = str(reader.u32()) || null;
|
|
9372
|
+
const affIndex = reader.u8();
|
|
9373
|
+
const flags = reader.u8();
|
|
9374
|
+
const collate = str(reader.u32()) || null;
|
|
9375
|
+
const hasDefault = reader.u8() === 1;
|
|
9376
|
+
const defaultExpr = hasDefault ? reader.json() : null;
|
|
9377
|
+
const hasGenerated = reader.u8() === 1;
|
|
9378
|
+
const generated = hasGenerated ? reader.json() : null;
|
|
9379
|
+
columns.push({
|
|
9380
|
+
name: colName,
|
|
9381
|
+
nameLower: colName.toLowerCase(),
|
|
9382
|
+
typeName,
|
|
9383
|
+
affinity: AFFINITIES[affIndex] ?? "NUMERIC",
|
|
9384
|
+
notNull: (flags & 1) !== 0,
|
|
9385
|
+
primaryKey: (flags & 2) !== 0,
|
|
9386
|
+
autoincrement: (flags & 4) !== 0,
|
|
9387
|
+
unique: (flags & 8) !== 0,
|
|
9388
|
+
defaultExpr,
|
|
9389
|
+
collate,
|
|
9390
|
+
generated
|
|
9391
|
+
});
|
|
9392
|
+
}
|
|
9393
|
+
const constraints = reader.json();
|
|
9394
|
+
const originalSql = str(reader.u32()) || null;
|
|
9395
|
+
const tableFlags = reader.u8();
|
|
9396
|
+
const indexCount2 = reader.u32();
|
|
9397
|
+
const indexNames = [];
|
|
9398
|
+
for (let i = 0; i < indexCount2; i++) indexNames.push(str(reader.u32()));
|
|
9399
|
+
const table = new Table(name, columns, {
|
|
9400
|
+
constraints,
|
|
9401
|
+
indexes: indexNames,
|
|
9402
|
+
originalSql,
|
|
9403
|
+
withoutRowid: (tableFlags & 1) !== 0,
|
|
9404
|
+
strict: (tableFlags & 2) !== 0
|
|
9405
|
+
});
|
|
9406
|
+
table.nextRowid = asRowid2(reader.value());
|
|
9407
|
+
const rowCount = reader.u32();
|
|
9408
|
+
const rowids = [];
|
|
9409
|
+
for (let r = 0; r < rowCount; r++) rowids.push(asRowid2(reader.value()));
|
|
9410
|
+
const cols = [];
|
|
9411
|
+
for (let c = 0; c < colCount; c++) cols.push(readPackedColumn(reader, rowCount, intern));
|
|
9412
|
+
for (let r = 0; r < rowCount; r++) {
|
|
9413
|
+
const values = [];
|
|
9414
|
+
for (let c = 0; c < colCount; c++) values.push(cols[c][r] ?? null);
|
|
9415
|
+
const rowid = rowids[r];
|
|
9416
|
+
table.rows.set(rowid, { rowid, values });
|
|
9417
|
+
}
|
|
9418
|
+
table.rebuildClusteredRows();
|
|
9419
|
+
state.tables.set(table.name.toLowerCase(), table);
|
|
9420
|
+
}
|
|
9421
|
+
const viewCount = reader.u32();
|
|
9422
|
+
for (let i = 0; i < viewCount; i++) {
|
|
9423
|
+
const view = reader.json();
|
|
9424
|
+
state.views.set(view.name.toLowerCase(), view);
|
|
9425
|
+
}
|
|
9426
|
+
const indexCount = reader.u32();
|
|
9427
|
+
const loadedIndexes = [];
|
|
9428
|
+
for (let i = 0; i < indexCount; i++) {
|
|
9429
|
+
const meta = reader.json();
|
|
9430
|
+
const info = { ...meta, store: new IndexStore(meta.name) };
|
|
9431
|
+
state.indexes.set(info.name.toLowerCase(), info);
|
|
9432
|
+
loadedIndexes.push(info);
|
|
9433
|
+
}
|
|
9434
|
+
for (const info of loadedIndexes) {
|
|
9435
|
+
info.store = readIndexStoreKeys(reader, info.name);
|
|
9436
|
+
const table = state.tables.get(info.tableName.toLowerCase());
|
|
9437
|
+
if (!table) continue;
|
|
9438
|
+
for (const entry of info.store.snapshotKeys()) {
|
|
9439
|
+
const rowid = entry.rowids[0];
|
|
9440
|
+
if (rowid === void 0) continue;
|
|
9441
|
+
const row = table.rows.get(rowid);
|
|
9442
|
+
if (!row) continue;
|
|
9443
|
+
info.store.rememberKeyValues(
|
|
9444
|
+
entry.key,
|
|
9445
|
+
indexKeyValues(info.columns, row, tableRowEvalContext(table, row), table)
|
|
9446
|
+
);
|
|
9447
|
+
}
|
|
9448
|
+
}
|
|
9449
|
+
if (reader.remaining() < 16) throw new SqliteError("invalid or truncated sqlite-mem snapshot", "other");
|
|
9450
|
+
const runtime = { prngState: reader.u64(), nowMs: finiteNowMs(Number(reader.i64())) };
|
|
9451
|
+
if (!reader.done()) throw new SqliteError("snapshot has trailing data", "other");
|
|
9452
|
+
return { state, runtime };
|
|
9453
|
+
}
|
|
9454
|
+
function readPackedColumn(reader, n, intern) {
|
|
9455
|
+
const pack = reader.u8();
|
|
9456
|
+
const out = new Array(n);
|
|
9457
|
+
if (pack === PACK_NULL) {
|
|
9458
|
+
for (let i = 0; i < n; i++) out[i] = null;
|
|
9459
|
+
return out;
|
|
9460
|
+
}
|
|
9461
|
+
const bits = reader.raw(n + 7 >> 3);
|
|
9462
|
+
for (let i = 0; i < n; i++) {
|
|
9463
|
+
if (bits[i >> 3] & 1 << (i & 7)) {
|
|
9464
|
+
out[i] = null;
|
|
9465
|
+
continue;
|
|
9466
|
+
}
|
|
9467
|
+
out[i] = readPackedCell(reader, pack, intern);
|
|
9468
|
+
}
|
|
9469
|
+
return out;
|
|
9470
|
+
}
|
|
9471
|
+
function readPackedCell(reader, pack, intern) {
|
|
9472
|
+
if (pack === PACK_INT) {
|
|
9473
|
+
const integer = reader.i64();
|
|
9474
|
+
return integer <= BigInt(Number.MAX_SAFE_INTEGER) && integer >= BigInt(Number.MIN_SAFE_INTEGER) ? Number(integer) : integer;
|
|
9475
|
+
}
|
|
9476
|
+
if (pack === PACK_FLOAT) {
|
|
9477
|
+
const value = reader.f64();
|
|
9478
|
+
return Number.isInteger(value) && Number.isFinite(value) ? asSqlReal(value) : value;
|
|
9479
|
+
}
|
|
9480
|
+
if (pack === PACK_TEXT) return intern[reader.u32()] ?? "";
|
|
9481
|
+
if (pack === PACK_BLOB) return reader.owned(reader.u32());
|
|
9482
|
+
return reader.value();
|
|
9483
|
+
}
|
|
9484
|
+
function readIndexStoreKeys(reader, name) {
|
|
9485
|
+
const count = reader.u32();
|
|
9486
|
+
const entries = /* @__PURE__ */ new Map();
|
|
9487
|
+
for (let i = 0; i < count; i++) {
|
|
9488
|
+
const key = reader.text();
|
|
9489
|
+
const rowidCount = reader.u32();
|
|
9490
|
+
const rowids = [];
|
|
9491
|
+
for (let r = 0; r < rowidCount; r++) rowids.push(asRowid2(reader.value()));
|
|
9492
|
+
entries.set(key, rowids);
|
|
9493
|
+
}
|
|
9494
|
+
return new IndexStore(name, entries);
|
|
9495
|
+
}
|
|
8999
9496
|
export {
|
|
9000
9497
|
DEFAULT_DATABASE_SEED,
|
|
9001
9498
|
DEFAULT_NOW,
|