@crvouga/sqlite-mem 1.5.0 → 1.6.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/compat/scenarios.ts +5 -0
- package/dist/index.js +46 -12
- package/dist/index.js.map +2 -2
- package/dist/unstable.js +9 -0
- package/dist/unstable.js.map +2 -2
- package/package.json +1 -1
package/compat/scenarios.ts
CHANGED
|
@@ -818,6 +818,11 @@ const TAIL: CatalogSection[] = [
|
|
|
818
818
|
["win-01", "window frame fuzz", F],
|
|
819
819
|
["up-01", "UPSERT fuzz", F],
|
|
820
820
|
["date-01", "date modifier fuzz", F],
|
|
821
|
+
["trig-01", "BEFORE/AFTER trigger + RAISE fuzz", F],
|
|
822
|
+
["genc-01", "STORED/VIRTUAL generated column fuzz", F],
|
|
823
|
+
["notin-01", "NOT IN / IN NULL + scalar cardinality fuzz", F],
|
|
824
|
+
["cnt-01", "changes/total_changes/last_insert_rowid fuzz", F],
|
|
825
|
+
["fkedge-01", "FK SET NULL/DEFAULT/MATCH edge fuzz", F],
|
|
821
826
|
["tlp-01", "ternary logic partitioning metamorphic", F],
|
|
822
827
|
["norec-01", "NoREC metamorphic rewrite", F],
|
|
823
828
|
["robust-01", "SqliteError-only / timeout / SQLM bit-flip", F],
|
package/dist/index.js
CHANGED
|
@@ -1677,10 +1677,19 @@ var Parser = class {
|
|
|
1677
1677
|
parseFkActions() {
|
|
1678
1678
|
let onDelete = null;
|
|
1679
1679
|
let onUpdate = null;
|
|
1680
|
+
while (this.match("MATCH")) {
|
|
1681
|
+
this.parseIdent();
|
|
1682
|
+
}
|
|
1680
1683
|
while (this.at("ON")) {
|
|
1681
1684
|
if (this.peek().kind === "DELETE") onDelete = this.parseFkAction("DELETE");
|
|
1682
1685
|
else if (this.peek().kind === "UPDATE") onUpdate = this.parseFkAction("UPDATE");
|
|
1683
1686
|
else this.syntaxError("expected ON DELETE or ON UPDATE");
|
|
1687
|
+
while (this.match("MATCH")) {
|
|
1688
|
+
this.parseIdent();
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
while (this.match("MATCH")) {
|
|
1692
|
+
this.parseIdent();
|
|
1684
1693
|
}
|
|
1685
1694
|
return { onDelete, onUpdate };
|
|
1686
1695
|
}
|
|
@@ -9899,11 +9908,13 @@ function pragmaTableInfo(args, env, xinfo) {
|
|
|
9899
9908
|
const tableName = requireNameArg(args, "table_info");
|
|
9900
9909
|
const table = env.state.tables.get(tableName.toLowerCase());
|
|
9901
9910
|
if (!table) return { columns: xinfoColumns(xinfo), rows: [] };
|
|
9902
|
-
const
|
|
9911
|
+
const visible = xinfo ? table.columns : table.columns.filter((column) => !column.generated);
|
|
9912
|
+
const rows = visible.map((column, cid) => {
|
|
9903
9913
|
const pkIndex = table.columns.filter((c) => c.primaryKey).findIndex((c) => c.name === column.name);
|
|
9904
9914
|
const pk = column.primaryKey ? pkIndex >= 0 ? pkIndex + 1 : 1 : 0;
|
|
9905
9915
|
const dflt = column.defaultExpr ? defaultLiteral(column.defaultExpr) : null;
|
|
9906
|
-
const
|
|
9916
|
+
const notNull = column.notNull || table.withoutRowid && column.primaryKey ? 1 : 0;
|
|
9917
|
+
const base = [cid, column.name, column.typeName ?? "", notNull, dflt, pk];
|
|
9907
9918
|
if (xinfo) {
|
|
9908
9919
|
let hidden = 0;
|
|
9909
9920
|
if (column.generated && !column.generated.stored) hidden = 2;
|
|
@@ -11362,10 +11373,20 @@ function scanFrom(item, env, parent) {
|
|
|
11362
11373
|
if (item.joinType === "RIGHT" || item.joinType === "FULL") {
|
|
11363
11374
|
right.forEach((rhs, rightIndex) => {
|
|
11364
11375
|
if (matchedRight.has(rightIndex)) return;
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11376
|
+
if (using) {
|
|
11377
|
+
const leftCells = nullLeft.map((cell) => {
|
|
11378
|
+
const shared = using.some((name) => name.toLowerCase() === cell.name.toLowerCase());
|
|
11379
|
+
if (!shared) return cell;
|
|
11380
|
+
const fromRight = rhs.cells.find((c) => c.name.toLowerCase() === cell.name.toLowerCase());
|
|
11381
|
+
return { ...cell, value: fromRight?.value ?? null, hiddenByUsing: false };
|
|
11382
|
+
});
|
|
11383
|
+
const rightOnly = rhs.cells.filter(
|
|
11384
|
+
(cell) => !using.some((name) => name.toLowerCase() === cell.name.toLowerCase())
|
|
11385
|
+
);
|
|
11386
|
+
result.push({ cells: [...leftCells, ...rightOnly] });
|
|
11387
|
+
} else {
|
|
11388
|
+
result.push({ cells: [...nullLeft, ...rhs.cells] });
|
|
11389
|
+
}
|
|
11369
11390
|
});
|
|
11370
11391
|
}
|
|
11371
11392
|
return result;
|
|
@@ -13266,17 +13287,28 @@ function checkForeignKeys(table, row, env) {
|
|
|
13266
13287
|
function fkIsDeferred(constraint, env) {
|
|
13267
13288
|
return env.transactions.inTransaction && constraint.initiallyDeferred;
|
|
13268
13289
|
}
|
|
13269
|
-
function assertForeignKeySatisfied(row, constraint, env) {
|
|
13290
|
+
function assertForeignKeySatisfied(row, constraint, env, excludeParent = null) {
|
|
13270
13291
|
const values = constraint.columns.map((name) => row.values.get(normalizeColumnName(name)) ?? null);
|
|
13292
|
+
assertForeignKeyValues(values, constraint, env, excludeParent);
|
|
13293
|
+
}
|
|
13294
|
+
function assertForeignKeySatisfiedWithUpdates(row, constraint, updates, env, excludeParent) {
|
|
13295
|
+
const values = constraint.columns.map((name) => {
|
|
13296
|
+
const key = normalizeColumnName(name);
|
|
13297
|
+
return updates.has(key) ? updates.get(key) ?? null : row.values.get(key) ?? null;
|
|
13298
|
+
});
|
|
13299
|
+
assertForeignKeyValues(values, constraint, env, excludeParent);
|
|
13300
|
+
}
|
|
13301
|
+
function assertForeignKeyValues(values, constraint, env, excludeParent) {
|
|
13271
13302
|
if (values.some((value) => value === null)) return;
|
|
13272
13303
|
const parent = env.state.getTable(constraint.refTable);
|
|
13273
13304
|
const parentColumns = constraint.refColumns ?? parent.columns.filter((column) => column.primaryKey).map((column) => column.name);
|
|
13274
|
-
if (![...parent.scan()].some(
|
|
13275
|
-
(candidate
|
|
13305
|
+
if (![...parent.scan()].some((candidate) => {
|
|
13306
|
+
if (excludeParent && candidate.rowid === excludeParent.rowid) return false;
|
|
13307
|
+
return values.every((value, index) => {
|
|
13276
13308
|
const parentColumn = parentColumns[index];
|
|
13277
13309
|
return parentColumn !== void 0 && compareSql(value, candidate.values.get(normalizeColumnName(parentColumn)) ?? null) === 0;
|
|
13278
|
-
})
|
|
13279
|
-
)) {
|
|
13310
|
+
});
|
|
13311
|
+
})) {
|
|
13280
13312
|
throw new SqliteError("FOREIGN KEY constraint failed", "constraint_foreign", "SQLITE_CONSTRAINT_FOREIGNKEY");
|
|
13281
13313
|
}
|
|
13282
13314
|
}
|
|
@@ -13317,7 +13349,9 @@ function applyReferentialDelete(parent, row, env) {
|
|
|
13317
13349
|
);
|
|
13318
13350
|
changes += 1 + updated.cascaded;
|
|
13319
13351
|
} else if (constraint.onDelete === "SET DEFAULT") {
|
|
13320
|
-
const
|
|
13352
|
+
const updates = defaultUpdates(child, constraint.columns, env);
|
|
13353
|
+
assertForeignKeySatisfiedWithUpdates(candidate, constraint, updates, env, row);
|
|
13354
|
+
const updated = updateOne(child, candidate, updates, env);
|
|
13321
13355
|
changes += 1 + updated.cascaded;
|
|
13322
13356
|
} else if (constraint.onDelete === "RESTRICT" || !fkIsDeferred(constraint, env)) {
|
|
13323
13357
|
throw new SqliteError("FOREIGN KEY constraint failed", "constraint_foreign", "SQLITE_CONSTRAINT_FOREIGNKEY");
|