@poe-platform/safe-bash 0.1.839 → 0.1.841

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.
Files changed (68) hide show
  1. package/dist/audio-ast/binary.d.ts +19 -0
  2. package/dist/audio-ast/index.d.ts +1 -0
  3. package/dist/audio-ast/index.js +92 -91
  4. package/dist/audio-ast/mpeg.d.ts +23 -0
  5. package/dist/mp4-ast/containers/adapters.d.ts +1 -0
  6. package/dist/mp4-ast/types.d.ts +8 -2
  7. package/dist/pdf-ast/cos/security.d.ts +10 -0
  8. package/dist/pdf-ast/edit/retained-attachment-edits.d.ts +4 -0
  9. package/dist/pdf-ast/edit/retained-graph.d.ts +1 -1
  10. package/dist/pdf-ast/image.js +1 -1
  11. package/dist/pdf-ast/index.d.ts +2 -1
  12. package/dist/pdf-ast/index.js +7 -1
  13. package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +8 -0
  14. package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +28 -0
  15. package/dist/safe-bash/audio-ast.browser.js +2 -1
  16. package/dist/safe-bash/audio-ast.js +1 -1
  17. package/dist/safe-bash/command-chunks/{chunk-SG2KOOD4.js → chunk-3SAYZFMD.js} +2 -2
  18. package/dist/safe-bash/command-chunks/{chunk-T6OXG7QQ.js → chunk-AAOPVEPF.js} +66 -1
  19. package/dist/safe-bash/command-chunks/{chunk-FH5VMAPS.js → chunk-BZW25LNV.js} +420 -131
  20. package/dist/safe-bash/command-chunks/{chunk-DQVOBGI2.js → chunk-CIV3GER2.js} +6770 -6523
  21. package/dist/safe-bash/command-chunks/{chunk-46GA576V.js → chunk-CPKVUB7S.js} +2 -2
  22. package/dist/safe-bash/command-chunks/{chunk-MBXNG6C3.js → chunk-DLLN3C3Q.js} +1 -1
  23. package/dist/safe-bash/command-chunks/{chunk-ZSQCROFE.js → chunk-DM5T5D2K.js} +5 -1
  24. package/dist/safe-bash/command-chunks/{chunk-3EAZRKI4.js → chunk-G7HQYFIU.js} +10 -1
  25. package/dist/safe-bash/command-chunks/{chunk-GYKQ3IOV.js → chunk-LMYQMJYY.js} +94 -18
  26. package/dist/safe-bash/command-chunks/{chunk-DX7KU6YU.js → chunk-N52AHO6S.js} +1 -1
  27. package/dist/safe-bash/command-chunks/{chunk-4BSD2RGK.js → chunk-QPKL5GWH.js} +102 -42
  28. package/dist/safe-bash/command-chunks/{chunk-Z2T7E4ID.js → chunk-R7QLP5RH.js} +1212 -1119
  29. package/dist/safe-bash/command-chunks/{chunk-77ROD2TR.js → chunk-X3WNWRVT.js} +11 -5
  30. package/dist/safe-bash/command-chunks/{chunk-RSFKQE2U.js → chunk-YAXP4EHP.js} +19 -10
  31. package/dist/safe-bash/command-chunks/{chunk-TCXM7BSZ.js → chunk-YFMNXPLP.js} +4 -4
  32. package/dist/safe-bash-command-exiftool/index.js +25 -1
  33. package/dist/safe-bash-command-ffmpeg/index.js +191 -49
  34. package/dist/safe-bash-command-ffprobe/index.js +2 -2
  35. package/dist/safe-bash-command-ffprobe/media.js +2 -2
  36. package/dist/safe-bash-command-imagemagick/index.js +498 -101
  37. package/dist/safe-bash-command-mdq/index.js +2 -0
  38. package/dist/safe-bash-command-pandoc/citeproc-filters.js +7 -7
  39. package/dist/safe-bash-command-pandoc/command.js +8 -8
  40. package/dist/safe-bash-command-pandoc/index.js +52 -52
  41. package/dist/safe-bash-command-qpdf/index.js +1037 -654
  42. package/dist/safe-bash-command-qpdf/page-range.d.ts +2 -0
  43. package/dist/safe-bash-command-soffice/index.js +28 -8
  44. package/dist/safe-bash-command-sqlite3/btree.d.ts +2 -1
  45. package/dist/safe-bash-command-sqlite3/engine.d.ts +15 -1
  46. package/dist/safe-bash-command-sqlite3/index.js +294 -68
  47. package/dist/safe-bash-command-tar/create.js +2 -2
  48. package/dist/safe-bash-command-tar/extract.js +2 -2
  49. package/dist/safe-bash-command-tar/format.js +1 -1
  50. package/dist/safe-bash-command-tar/index.js +4 -4
  51. package/dist/safe-bash-command-tar/modes.js +4 -4
  52. package/dist/safe-bash-command-unzip/index.js +1 -1
  53. package/dist/safe-bash-command-unzip/unzip.js +1 -1
  54. package/dist/safe-bash-markdown-engine/commonmark-blocks.d.ts +17 -1
  55. package/dist/safe-bash-markdown-engine/commonmark-blocks.js +3 -3
  56. package/dist/safe-bash-markdown-engine/commonmark-inlines.d.ts +1 -1
  57. package/dist/safe-bash-markdown-engine/commonmark-inlines.js +3 -3
  58. package/dist/safe-bash-markdown-engine/commonmark-syntax.d.ts +5 -0
  59. package/dist/safe-bash-markdown-engine/commonmark-syntax.js +5 -1
  60. package/dist/safe-bash-markdown-engine/gfm-syntax.js +2 -2
  61. package/dist/safe-bash-markdown-engine/index.js +4 -4
  62. package/dist/safe-bash-zip-engine/index.js +1 -1
  63. package/dist/safe-bash-zip-engine/zip/repair.js +1 -1
  64. package/dist/safe-bash-zip-engine/zip/sfx.js +1 -1
  65. package/dist/safe-bash-zip-engine/zip-format.d.ts +2 -0
  66. package/dist/safe-bash-zip-engine/zip-format.js +1 -1
  67. package/package.json +2 -2
  68. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +2 -0
@@ -3,6 +3,75 @@ import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
3
3
  // packages/safe-bash-command-sqlite3/src/engine.ts
4
4
  import { yieldTurn as yieldTurn2 } from "../safe-bash-contracts/yield.js";
5
5
 
6
+ // packages/safe-bash-command-sqlite3/src/real-output.ts
7
+ function formatReal(value, precision) {
8
+ if (!Number.isFinite(value)) return Number.isNaN(value) ? "NaN" : value < 0 ? "-Inf" : "Inf";
9
+ if (value === 0) return "0.0";
10
+ let high = Math.abs(value), low = 0, exponent = 0;
11
+ const bits = new DataView(new ArrayBuffer(8));
12
+ function upper(x) {
13
+ bits.setFloat64(0, x);
14
+ bits.setUint32(4, bits.getUint32(4) & 4227858432);
15
+ return bits.getFloat64(0);
16
+ }
17
+ function multiply(y, error) {
18
+ const hx = upper(high), hy = upper(y), tx = high - hx, ty = y - hy;
19
+ const p = hx * hy, q = hx * ty + tx * hy, c = p + q;
20
+ let cc = p - c + q + tx * ty;
21
+ cc = high * error + low * y + cc;
22
+ high = c + cc;
23
+ low = c - high + cc;
24
+ }
25
+ if (high > 9223372036854775e3) {
26
+ while (high > 9223372036854774e103) {
27
+ exponent += 100;
28
+ multiply(1e-100, -19991899802602883e-133);
29
+ }
30
+ while (high > 9223372036854774e13) {
31
+ exponent += 10;
32
+ multiply(1e-10, -3643219731549774e-42);
33
+ }
34
+ while (high > 9223372036854775e3) {
35
+ exponent++;
36
+ multiply(0.1, -5551115123125783e-33);
37
+ }
38
+ } else {
39
+ while (high < 9223372036854775e-98) {
40
+ exponent -= 100;
41
+ multiply(1e100, -15902891109759918e67);
42
+ }
43
+ while (high < 9223372036854775e-8) {
44
+ exponent -= 10;
45
+ multiply(1e10, 0);
46
+ }
47
+ while (high < 922337203685477500) {
48
+ exponent--;
49
+ multiply(10, 0);
50
+ }
51
+ }
52
+ let digits = (BigInt(Math.trunc(high)) + BigInt(Math.trunc(low))).toString();
53
+ if (precision === 20 && Number(`${digits}e${exponent}`) !== Math.abs(value)) {
54
+ const [mantissa, power] = Math.abs(value).toExponential(19).split("e");
55
+ digits = mantissa.replace(".", "");
56
+ exponent = Number(power) - digits.length + 1;
57
+ }
58
+ let point = digits.length + exponent;
59
+ if (digits.length > precision) {
60
+ const roundUp = digits[precision] >= "5";
61
+ digits = (BigInt(digits.slice(0, precision)) + (roundUp ? 1n : 0n)).toString();
62
+ if (digits.length > precision) point++;
63
+ }
64
+ while (digits.endsWith("0")) digits = digits.slice(0, -1);
65
+ const sign = value < 0 ? "-" : "";
66
+ exponent = point - 1;
67
+ if (exponent < -4 || exponent >= precision) {
68
+ return `${sign}${digits[0]}.${digits.slice(1) || "0"}e${exponent < 0 ? "-" : "+"}${String(Math.abs(exponent)).padStart(2, "0")}`;
69
+ }
70
+ if (point <= 0) return `${sign}0.${"0".repeat(-point)}${digits}`;
71
+ if (point >= digits.length) return `${sign}${digits}${"0".repeat(point - digits.length)}.0`;
72
+ return `${sign}${digits.slice(0, point)}.${digits.slice(point)}`;
73
+ }
74
+
6
75
  // packages/safe-bash-command-sqlite3/src/execution.ts
7
76
  import { yieldTurn } from "../safe-bash-contracts/yield.js";
8
77
  function runSynchronously(steps) {
@@ -725,7 +794,7 @@ function writeSqliteDatabaseBytes(image) {
725
794
  });
726
795
  } else if (item.type === "index") {
727
796
  const idxRows = image.indexRows?.get(item.name) ?? [];
728
- const built = buildIndexPages(idxRows, nextPageNumber);
797
+ const built = buildIndexPages(idxRows, nextPageNumber, item.indexPresorted);
729
798
  extraPageChunks.push(...built.pages);
730
799
  nextPageNumber += built.pages.length;
731
800
  masterEntries.push({
@@ -763,7 +832,7 @@ function writeSqliteDatabaseBytes(image) {
763
832
  reMasterEntries.push({ ...item, rootpage: built.rootPage });
764
833
  } else if (item.type === "index") {
765
834
  const idxRows = image.indexRows?.get(item.name) ?? [];
766
- const built = buildIndexPages(idxRows, pNum);
835
+ const built = buildIndexPages(idxRows, pNum, item.indexPresorted);
767
836
  reExtraChunks.push(...built.pages);
768
837
  pNum += built.pages.length;
769
838
  reMasterEntries.push({ ...item, rootpage: built.rootPage });
@@ -857,6 +926,7 @@ function tableStorageColumns(table) {
857
926
  var textEncoder2 = new TextEncoder();
858
927
  var textDecoder2 = new TextDecoder("utf-8", { fatal: false });
859
928
  var SqliteConstraintError = class extends Error {
929
+ code = 19;
860
930
  };
861
931
  function cloneSqlValue(v) {
862
932
  if (v instanceof Uint8Array) {
@@ -887,6 +957,7 @@ function cloneTableDef(t) {
887
957
  strict: t.strict,
888
958
  primaryKeyCols: [...t.primaryKeyCols],
889
959
  primaryKeyOrder: t.primaryKeyOrder?.map((key) => ({ ...key })),
960
+ implicitIndexes: t.implicitIndexes?.map((index) => ({ ...index, columns: [...index.columns], order: index.order.map((key) => ({ ...key })) })),
890
961
  uniqueColSets: t.uniqueColSets.map((u) => [...u])
891
962
  };
892
963
  }
@@ -1173,6 +1244,13 @@ function reconstructTokensSql(tokens) {
1173
1244
  }
1174
1245
  return out;
1175
1246
  }
1247
+ function isFromClause(tokens, index) {
1248
+ const isWord = (offset, word) => {
1249
+ const token = tokens[index + offset];
1250
+ return token?.type === "word" && token.value.toUpperCase() === word;
1251
+ };
1252
+ return isWord(0, "FROM") && !(isWord(-1, "DISTINCT") && (isWord(-2, "IS") || isWord(-2, "NOT") && isWord(-3, "IS")));
1253
+ }
1176
1254
  var ExprParser = class {
1177
1255
  constructor(tokens) {
1178
1256
  this.tokens = tokens;
@@ -1496,11 +1574,11 @@ var ExprParser = class {
1496
1574
  }
1497
1575
  if (upper === "TRUE") {
1498
1576
  this.pos += 1;
1499
- return { kind: "literal", value: 1 };
1577
+ return { kind: "literal", value: 1, booleanLiteral: true };
1500
1578
  }
1501
1579
  if (upper === "FALSE") {
1502
1580
  this.pos += 1;
1503
- return { kind: "literal", value: 0 };
1581
+ return { kind: "literal", value: 0, booleanLiteral: true };
1504
1582
  }
1505
1583
  if (upper === "CURRENT_TIMESTAMP") {
1506
1584
  this.pos += 1;
@@ -1771,17 +1849,25 @@ function arithmeticNumber(value) {
1771
1849
  }
1772
1850
  return real ? new Number(Number(text.slice(0, end))) : integerResult(BigInt(text.slice(0, end)));
1773
1851
  }
1852
+ function columnAffinity(declaredType) {
1853
+ const type = declaredType.toUpperCase();
1854
+ if (type.includes("INT")) return "INTEGER";
1855
+ if (["CHAR", "CLOB", "TEXT"].some((part) => type.includes(part))) return "TEXT";
1856
+ if (type === "" || type.includes("BLOB")) return "BLOB";
1857
+ if (["REAL", "FLOA", "DOUB"].some((part) => type.includes(part))) return "REAL";
1858
+ return "NUMERIC";
1859
+ }
1774
1860
  function applyColumnAffinity(storedValue, declaredType, strict) {
1775
1861
  let value = storedValue instanceof String ? storedValue.valueOf() : storedValue;
1776
1862
  if (value === null || value instanceof Uint8Array) return value;
1777
1863
  const type = declaredType.toUpperCase();
1778
1864
  if (strict && type === "ANY") return value;
1779
- const integer = type.includes("INT");
1780
- if (!integer && ["CHAR", "CLOB", "TEXT"].some((part) => type.includes(part))) {
1865
+ const affinity = columnAffinity(type);
1866
+ if (affinity === "TEXT") {
1781
1867
  return toSqlString(value);
1782
1868
  }
1783
- if (!integer && (type === "" || type.includes("BLOB"))) return value;
1784
- const real = !integer && ["REAL", "FLOA", "DOUB"].some((part) => type.includes(part));
1869
+ if (affinity === "BLOB") return value;
1870
+ const real = affinity === "REAL";
1785
1871
  if (typeof value === "string") {
1786
1872
  const text = value.trim();
1787
1873
  if (!text || ![...text].every((char) => "0123456789.+-eE".includes(char)) || Number.isNaN(Number(text))) return value;
@@ -1812,11 +1898,10 @@ function toSqlString(v) {
1812
1898
  return v.toString();
1813
1899
  }
1814
1900
  if (v instanceof Number) {
1815
- const n = v.valueOf();
1816
- return Number.isFinite(n) && Number.isInteger(n) ? `${n}.0` : String(Number(n.toPrecision(15)));
1901
+ return formatReal(v.valueOf(), 15);
1817
1902
  }
1818
1903
  if (typeof v === "number") {
1819
- return Number.isInteger(v) ? String(v) : String(Number(v.toPrecision(15)));
1904
+ return Number.isInteger(v) ? String(v) : formatReal(v, 15);
1820
1905
  }
1821
1906
  const nulIdx = v.indexOf(0);
1822
1907
  const sub = nulIdx === -1 ? v : v.subarray(0, nulIdx);
@@ -1861,22 +1946,24 @@ function sqlEquals(a, b, collation = "BINARY") {
1861
1946
  function matchLike(str, pattern, caseInsensitive, escapeChar = "") {
1862
1947
  let regexStr = "^";
1863
1948
  for (let i = 0; i < pattern.length; i += 1) {
1864
- const c = pattern[i];
1865
- if (escapeChar && c === escapeChar && i + 1 < pattern.length) {
1866
- regexStr += pattern[i + 1].replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1949
+ let c = pattern[i];
1950
+ const escaped = escapeChar && c === escapeChar && i + 1 < pattern.length;
1951
+ if (escaped) {
1867
1952
  i += 1;
1868
- continue;
1953
+ c = pattern[i];
1869
1954
  }
1870
- if (c === "%") {
1955
+ if (!escaped && c === "%") {
1871
1956
  regexStr += "[\\s\\S]*";
1872
- } else if (c === "_") {
1957
+ } else if (!escaped && c === "_") {
1873
1958
  regexStr += "[\\s\\S]";
1959
+ } else if (caseInsensitive && (c >= "a" && c <= "z" || c >= "A" && c <= "Z")) {
1960
+ regexStr += `[${c.toUpperCase()}${c.toLowerCase()}]`;
1874
1961
  } else {
1875
1962
  regexStr += c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1876
1963
  }
1877
1964
  }
1878
1965
  regexStr += "$";
1879
- return new RegExp(regexStr, caseInsensitive ? "i" : "").test(str);
1966
+ return new RegExp(regexStr).test(str);
1880
1967
  }
1881
1968
  function matchGlob(str, pattern) {
1882
1969
  let regexStr = "^";
@@ -2231,6 +2318,7 @@ var SqliteDatabase = class {
2231
2318
  async executeStatementAsync(sql, signal) {
2232
2319
  return runCooperatively(this.executeStatementSteps(sql), signal);
2233
2320
  }
2321
+ rowTables = /* @__PURE__ */ new WeakMap();
2234
2322
  tables = /* @__PURE__ */ new Map();
2235
2323
  indexes = /* @__PURE__ */ new Map();
2236
2324
  views = /* @__PURE__ */ new Map();
@@ -2246,7 +2334,9 @@ var SqliteDatabase = class {
2246
2334
  lastInsertRowid = 0;
2247
2335
  lastChanges = 0;
2248
2336
  totalChanges = 0;
2249
- inTransaction = false;
2337
+ get inTransaction() {
2338
+ return this.txSnapshot !== null || this.savepoints.size > 0;
2339
+ }
2250
2340
  foreignKeyDepth = 0;
2251
2341
  outerRows = [];
2252
2342
  preparing = false;
@@ -2448,6 +2538,41 @@ var SqliteDatabase = class {
2448
2538
  };
2449
2539
  }, this);
2450
2540
  tableRows.set(tbl.name, rows);
2541
+ const indexes = [];
2542
+ for (const index of tbl.implicitIndexes ?? []) {
2543
+ yield;
2544
+ const columns = index.columns.map((name2) => tbl.columns.find((column) => column.name.toLowerCase() === name2.toLowerCase()));
2545
+ if (index.primary && !tbl.withoutRowId && columns.length === 1 && columns[0].type.toUpperCase() === "INTEGER") continue;
2546
+ if (indexes.some((existing) => existing.columns.length === index.columns.length && existing.columns.every((name2, i) => name2.toLowerCase() === index.columns[i].toLowerCase() && (existing.order[i]?.collation ?? columns[i].collate ?? "BINARY").toUpperCase() === (index.order[i]?.collation ?? columns[i].collate ?? "BINARY").toUpperCase()))) continue;
2547
+ indexes.push(index);
2548
+ if (index.primary && tbl.withoutRowId) continue;
2549
+ const name = `sqlite_autoindex_${tbl.name}_${indexes.length}`;
2550
+ const keyColumns = [...columns];
2551
+ const order = [...index.order];
2552
+ if (tbl.withoutRowId) {
2553
+ for (let i = 0; i < tbl.primaryKeyCols.length; i++) {
2554
+ const column = tbl.columns.find((column2) => column2.name.toLowerCase() === tbl.primaryKeyCols[i].toLowerCase());
2555
+ if (keyColumns.includes(column)) continue;
2556
+ keyColumns.push(column);
2557
+ order.push(tbl.primaryKeyOrder?.[i] ?? { desc: false, collation: column.collate });
2558
+ }
2559
+ }
2560
+ const entries = yield* stepMap(tbl.rows, function* (row) {
2561
+ yield;
2562
+ const values = keyColumns.map((column) => row.data[column.name] ?? null);
2563
+ if (!tbl.withoutRowId) values.push(row.rowid);
2564
+ return values;
2565
+ }, this);
2566
+ indexRows.set(name, yield* stepSort(entries, function* (left, right) {
2567
+ for (let i = 0; i < left.length; i++) {
2568
+ yield;
2569
+ const comparison = compareSqlValues(left[i], right[i], order[i]?.collation ?? keyColumns[i]?.collate ?? "BINARY");
2570
+ if (comparison) return order[i]?.desc ? -comparison : comparison;
2571
+ }
2572
+ return 0;
2573
+ }, this));
2574
+ master.push({ type: "index", name, tbl_name: tbl.name, rootpage: rootPageCounter++, sql: null, indexPresorted: true });
2575
+ }
2451
2576
  }
2452
2577
  if ((hasAutoIncTable || seqRows.length > 0) && !this.findTable("sqlite_sequence")) {
2453
2578
  master.push({
@@ -2545,7 +2670,7 @@ var SqliteDatabase = class {
2545
2670
  const candidate = { rowid, data };
2546
2671
  const conflict = yield* this.checkConstraintsAndConflicts(tbl, candidate);
2547
2672
  if (conflict) {
2548
- throw new Error(`UNIQUE constraint failed: ${tbl.name}`);
2673
+ throw new SqliteConstraintError(`UNIQUE constraint failed: ${conflict.columns.map((column) => `${tbl.name}.${column}`).join(", ")}`);
2549
2674
  }
2550
2675
  this.checkRowCount(tbl.rows.length + 1);
2551
2676
  tbl.rows.push(candidate);
@@ -2636,12 +2761,10 @@ var SqliteDatabase = class {
2636
2761
  if (first === "BEGIN") {
2637
2762
  if (!this.inTransaction) {
2638
2763
  this.txSnapshot = yield* this.captureSnapshot();
2639
- this.inTransaction = true;
2640
2764
  }
2641
2765
  return null;
2642
2766
  }
2643
2767
  if (first === "COMMIT" || first === "END") {
2644
- this.inTransaction = false;
2645
2768
  this.txSnapshot = null;
2646
2769
  this.savepoints.clear();
2647
2770
  return null;
@@ -2663,10 +2786,10 @@ var SqliteDatabase = class {
2663
2786
  yield* this.restoreSnapshot(snap);
2664
2787
  return null;
2665
2788
  }
2666
- if (this.txSnapshot) {
2667
- yield* this.restoreSnapshot(this.txSnapshot);
2789
+ const snapshot = this.txSnapshot ?? this.savepoints.values().next().value;
2790
+ if (snapshot) {
2791
+ yield* this.restoreSnapshot(snapshot);
2668
2792
  }
2669
- this.inTransaction = false;
2670
2793
  this.txSnapshot = null;
2671
2794
  this.savepoints.clear();
2672
2795
  return null;
@@ -2679,7 +2802,11 @@ var SqliteDatabase = class {
2679
2802
  if (first === "RELEASE") {
2680
2803
  const spIdx = tokens[1]?.value.toUpperCase() === "SAVEPOINT" ? 2 : 1;
2681
2804
  const spName = (tokens[spIdx]?.value ?? "").toLowerCase();
2682
- this.savepoints.delete(spName);
2805
+ let releasing = false;
2806
+ for (const name of this.savepoints.keys()) {
2807
+ if (name === spName) releasing = true;
2808
+ if (releasing) this.savepoints.delete(name);
2809
+ }
2683
2810
  return null;
2684
2811
  }
2685
2812
  if (first === "VACUUM" || first === "ANALYZE" || first === "REINDEX" || first === "ATTACH" || first === "DETACH") {
@@ -2704,9 +2831,12 @@ var SqliteDatabase = class {
2704
2831
  return null;
2705
2832
  }
2706
2833
  if (["INSERT", "REPLACE", "UPDATE", "DELETE"].includes(first)) {
2707
- const snapshot = this.foreignKeys && this.foreignKeyDepth === 0 ? yield* this.captureSnapshot() : null;
2834
+ const rollbackOnConflict = first === "INSERT" && tokens[1]?.value.toUpperCase() === "OR" && tokens[2]?.value.toUpperCase() === "ROLLBACK";
2835
+ const rollbackSnapshot = rollbackOnConflict ? this.txSnapshot ?? this.savepoints.values().next().value ?? (yield* this.captureSnapshot()) : null;
2836
+ const failOnConflict = tokens[1]?.value.toUpperCase() === "OR" && tokens[2]?.value.toUpperCase() === "FAIL";
2837
+ const snapshot = this.foreignKeyDepth === 0 ? yield* this.captureSnapshot() : null;
2708
2838
  const existingRows = /* @__PURE__ */ new Set();
2709
- if (snapshot) {
2839
+ if (this.foreignKeys && snapshot) {
2710
2840
  for (const table of this.tables.values()) {
2711
2841
  for (const row of table.rows) {
2712
2842
  yield;
@@ -2721,10 +2851,22 @@ var SqliteDatabase = class {
2721
2851
  if (first === "UPDATE") result = yield* this.executeUpdate(tokens, positionalParams, cteScope);
2722
2852
  else if (first === "DELETE") result = yield* this.executeDelete(tokens, positionalParams, cteScope);
2723
2853
  else result = yield* this.executeInsert(sql, tokens, positionalParams, cteScope);
2724
- if (snapshot) yield* this.validateForeignKeys(snapshot, existingRows);
2854
+ if (this.foreignKeys && snapshot) yield* this.validateForeignKeys(snapshot, existingRows);
2725
2855
  return result;
2726
- } catch (error) {
2727
- if (snapshot) {
2856
+ } catch (caughtError) {
2857
+ let error = caughtError;
2858
+ if (this.foreignKeys && snapshot && failOnConflict && error instanceof SqliteConstraintError && error.message !== "FOREIGN KEY constraint failed") {
2859
+ try {
2860
+ yield* this.validateForeignKeys(snapshot, existingRows);
2861
+ } catch (foreignKeyError) {
2862
+ error = foreignKeyError;
2863
+ }
2864
+ }
2865
+ if (rollbackSnapshot && error instanceof SqliteConstraintError && error.message !== "FOREIGN KEY constraint failed") {
2866
+ yield* this.restoreSnapshot(rollbackSnapshot);
2867
+ this.txSnapshot = null;
2868
+ this.savepoints.clear();
2869
+ } else if (snapshot && !(failOnConflict && error instanceof SqliteConstraintError && error.message !== "FOREIGN KEY constraint failed")) {
2728
2870
  yield* this.restoreSnapshot(snapshot);
2729
2871
  [this.lastChanges, this.totalChanges, this.lastInsertRowid] = counters;
2730
2872
  }
@@ -3046,6 +3188,7 @@ var SqliteDatabase = class {
3046
3188
  const primaryKeyCols = [];
3047
3189
  const primaryKeyOrder = [];
3048
3190
  const uniqueColSets = [];
3191
+ const implicitIndexes = [];
3049
3192
  const foreignKeys = [];
3050
3193
  for (const part of bodyParts) {
3051
3194
  yield;
@@ -3111,24 +3254,35 @@ var SqliteDatabase = class {
3111
3254
  if (direction === "ASC" || direction === "DESC") pIdx++;
3112
3255
  }
3113
3256
  }
3257
+ implicitIndexes.push({ columns: primaryKeyCols, order: primaryKeyOrder, primary: true });
3114
3258
  continue;
3115
3259
  }
3116
3260
  if (firstWord === "UNIQUE") {
3117
3261
  pIdx += 1;
3118
3262
  const uCols = [];
3263
+ const order = [];
3119
3264
  if (part[pIdx]?.value === "(") {
3120
- pIdx += 1;
3265
+ pIdx++;
3121
3266
  while (pIdx < part.length && part[pIdx]?.value !== ")") {
3122
3267
  yield;
3123
- const colName = part[pIdx].value;
3124
- if (colName !== "," && colName.toUpperCase() !== "ASC" && colName.toUpperCase() !== "DESC") {
3125
- uCols.push(colName);
3268
+ if (part[pIdx].value === ",") {
3269
+ pIdx++;
3270
+ continue;
3126
3271
  }
3127
- pIdx += 1;
3272
+ uCols.push(part[pIdx++].value);
3273
+ let collation;
3274
+ if (part[pIdx]?.value.toUpperCase() === "COLLATE") {
3275
+ collation = part[pIdx + 1]?.value;
3276
+ pIdx += 2;
3277
+ }
3278
+ const direction = part[pIdx]?.value.toUpperCase();
3279
+ order.push({ desc: direction === "DESC", collation });
3280
+ if (direction === "ASC" || direction === "DESC") pIdx++;
3128
3281
  }
3129
3282
  }
3130
3283
  if (uCols.length > 0) {
3131
3284
  uniqueColSets.push(uCols);
3285
+ implicitIndexes.push({ columns: uCols, order, primary: false });
3132
3286
  }
3133
3287
  continue;
3134
3288
  }
@@ -3145,6 +3299,17 @@ var SqliteDatabase = class {
3145
3299
  if (colDef.unique) {
3146
3300
  uniqueColSets.push([colDef.name]);
3147
3301
  }
3302
+ for (let i = 1; i < part.length; i++) {
3303
+ if (part[i]?.type !== "word") continue;
3304
+ const keyword = part[i].value.toUpperCase();
3305
+ if (keyword === "UNIQUE" || keyword === "PRIMARY" && part[i + 1]?.value.toUpperCase() === "KEY") {
3306
+ implicitIndexes.push({
3307
+ columns: [colDef.name],
3308
+ primary: keyword === "PRIMARY",
3309
+ order: [{ desc: keyword === "PRIMARY" && part[i + 2]?.value.toUpperCase() === "DESC", collation: colDef.collate }]
3310
+ });
3311
+ }
3312
+ }
3148
3313
  }
3149
3314
  if (primaryKeyCols.length === 1) {
3150
3315
  const pkCol = columns.find((c) => {
@@ -3166,6 +3331,7 @@ var SqliteDatabase = class {
3166
3331
  primaryKeyCols,
3167
3332
  primaryKeyOrder,
3168
3333
  uniqueColSets,
3334
+ implicitIndexes,
3169
3335
  foreignKeys
3170
3336
  });
3171
3337
  return;
@@ -3226,7 +3392,7 @@ var SqliteDatabase = class {
3226
3392
  }
3227
3393
  yield* stepSort(keys, compareKeys, this);
3228
3394
  for (let i = 1; i < keys.length; i++) {
3229
- if ((yield* compareKeys(keys[i - 1], keys[i])) === 0) throw new SqliteConstraintError(`UNIQUE constraint failed: ${tbl.name}`);
3395
+ if ((yield* compareKeys(keys[i - 1], keys[i])) === 0) throw new SqliteConstraintError(`UNIQUE constraint failed: ${cols.map((column) => `${tbl.name}.${column}`).join(", ")}`);
3230
3396
  }
3231
3397
  }
3232
3398
  this.indexes.set(objName, { name: objName, tableName: tbl.name, unique, columns: cols, collations, sql });
@@ -3812,7 +3978,7 @@ var SqliteDatabase = class {
3812
3978
  }
3813
3979
  if (!previouslyValid) continue;
3814
3980
  }
3815
- throw new Error("FOREIGN KEY constraint failed");
3981
+ throw new SqliteConstraintError("FOREIGN KEY constraint failed");
3816
3982
  }
3817
3983
  }
3818
3984
  }
@@ -3835,7 +4001,7 @@ var SqliteDatabase = class {
3835
4001
  yield;
3836
4002
  if (this.foreignKeyMatches(child, row, key, columns, oldData)) matches.push(row);
3837
4003
  }
3838
- if (action === "RESTRICT" && matches.length) throw new Error("FOREIGN KEY constraint failed");
4004
+ if (action === "RESTRICT" && matches.length) throw new SqliteConstraintError("FOREIGN KEY constraint failed");
3839
4005
  for (const row of matches) {
3840
4006
  yield;
3841
4007
  const where = child.withoutRowId ? child.primaryKeyCols.map((name) => `${quote(name)} IS ${this.toSqlLiteral(row.data[name] ?? null)}`).join(" AND ") : `rowid = ${row.rowid}`;
@@ -3945,12 +4111,12 @@ var SqliteDatabase = class {
3945
4111
  fastIdx.lastRow = added;
3946
4112
  }
3947
4113
  const byId = fastIdx.byRowid.get(candidate.rowid);
3948
- if (byId) return byId;
4114
+ if (byId) return { row: byId, columns: [tbl.columns.find((col) => col.primaryKey && col.type.toUpperCase() === "INTEGER")?.name ?? "rowid"] };
3949
4115
  for (let i = 0; i < resolvedKeySets.length; i += 1) {
3950
4116
  const k = encodeKey(candidate, resolvedKeySets[i]);
3951
4117
  if (k !== null) {
3952
4118
  const hit = fastIdx.byKeySets[i].get(k);
3953
- if (hit) return hit;
4119
+ if (hit) return { row: hit, columns: resolvedKeySets[i].map((key) => key.cKey) };
3954
4120
  }
3955
4121
  }
3956
4122
  return null;
@@ -3961,7 +4127,7 @@ var SqliteDatabase = class {
3961
4127
  continue;
3962
4128
  }
3963
4129
  if (existing.rowid === candidate.rowid) {
3964
- return existing;
4130
+ return { row: existing, columns: [tbl.columns.find((col) => col.primaryKey && col.type.toUpperCase() === "INTEGER")?.name ?? "rowid"] };
3965
4131
  }
3966
4132
  for (const kSet of resolvedKeySets) {
3967
4133
  yield;
@@ -3976,7 +4142,7 @@ var SqliteDatabase = class {
3976
4142
  }
3977
4143
  }
3978
4144
  if (allEqual) {
3979
- return existing;
4145
+ return { row: existing, columns: kSet.map((key) => key.cKey) };
3980
4146
  }
3981
4147
  }
3982
4148
  }
@@ -4229,8 +4395,9 @@ var SqliteDatabase = class {
4229
4395
  if (!(yield* this.fireTriggers(tbl.name, "BEFORE", "INSERT", void 0, candidate.data))) {
4230
4396
  continue;
4231
4397
  }
4232
- const conflictRow = yield* this.checkConstraintsAndConflicts(tbl, candidate);
4233
- if (conflictRow) {
4398
+ const conflict = yield* this.checkConstraintsAndConflicts(tbl, candidate);
4399
+ if (conflict) {
4400
+ const conflictRow = conflict.row;
4234
4401
  if (upsertDoNothing || conflictAction === "IGNORE") {
4235
4402
  continue;
4236
4403
  }
@@ -4282,7 +4449,7 @@ var SqliteDatabase = class {
4282
4449
  yield* this.applyForeignKeyActions(tbl, conflictRow.data);
4283
4450
  }
4284
4451
  } else {
4285
- throw new Error(`UNIQUE constraint failed: ${tbl.name}`);
4452
+ throw new SqliteConstraintError(`UNIQUE constraint failed: ${conflict.columns.map((column) => `${tbl.name}.${column}`).join(", ")}`);
4286
4453
  }
4287
4454
  }
4288
4455
  tbl.rows.push(candidate);
@@ -4315,7 +4482,7 @@ var SqliteDatabase = class {
4315
4482
  let i = 0;
4316
4483
  let whereExpr;
4317
4484
  while (i < tokens.length) {
4318
- if (tokens[i].value.toUpperCase() === "WHERE" || tokens[i].value.toUpperCase() === "FROM") {
4485
+ if (tokens[i].value.toUpperCase() === "WHERE" || isFromClause(tokens, i)) {
4319
4486
  if (tokens[i].value.toUpperCase() === "WHERE") {
4320
4487
  whereExpr = new ExprParser(tokens.slice(i + 1)).parseExpression();
4321
4488
  }
@@ -4374,7 +4541,7 @@ var SqliteDatabase = class {
4374
4541
  d += 1;
4375
4542
  } else if (t.value === ")") {
4376
4543
  d -= 1;
4377
- } else if (d === 0 && (t.value === "," || t.value.toUpperCase() === "WHERE" || t.value.toUpperCase() === "FROM")) {
4544
+ } else if (d === 0 && (t.value === "," || t.value.toUpperCase() === "WHERE" || isFromClause(tokens, i))) {
4378
4545
  break;
4379
4546
  }
4380
4547
  exprToks.push(t);
@@ -4395,6 +4562,7 @@ var SqliteDatabase = class {
4395
4562
  bindings[`${tbl.name}.${column}`] = value;
4396
4563
  if (alias) bindings[`${alias}.${column}`] = value;
4397
4564
  }
4565
+ this.rowTables.set(bindings, tbl);
4398
4566
  return bindings;
4399
4567
  }
4400
4568
  *executeUpdate(tokens, positionalParams, _cteScope) {
@@ -4440,7 +4608,7 @@ var SqliteDatabase = class {
4440
4608
  const token = tokens[i].value.toUpperCase();
4441
4609
  if (token === "(") depth += 1;
4442
4610
  else if (token === ")") depth -= 1;
4443
- else if (depth === 0 && token === "FROM") fromIdx = i;
4611
+ else if (depth === 0 && isFromClause(tokens, i)) fromIdx = i;
4444
4612
  else if (depth === 0 && token === "WHERE") whereIdx = i;
4445
4613
  }
4446
4614
  const setTokens = fromIdx === -1 ? tokens.slice(idx, sliceEnd) : [...tokens.slice(idx, fromIdx), ...tokens.slice(whereIdx, sliceEnd)];
@@ -4486,6 +4654,7 @@ var SqliteDatabase = class {
4486
4654
  for (const other of source.rows) {
4487
4655
  yield;
4488
4656
  const ctx = { ...other, ...target };
4657
+ this.rowTables.set(ctx, tbl);
4489
4658
  if (!whereExpr || isTruthy(yield* this.evalExprSteps(whereExpr, ctx, positionalParams, _cteScope)))
4490
4659
  return [{ row, ctx }];
4491
4660
  }
@@ -4533,10 +4702,10 @@ var SqliteDatabase = class {
4533
4702
  }
4534
4703
  if (conflict && conflictAction === "IGNORE") continue;
4535
4704
  while (conflict) {
4536
- if (conflictAction !== "REPLACE") throw new Error(`UNIQUE constraint failed: ${tbl.name}`);
4537
- replacedRows.add(conflict);
4538
- tbl.rows.splice(tbl.rows.indexOf(conflict), 1);
4539
- yield* this.applyForeignKeyActions(tbl, conflict.data);
4705
+ if (conflictAction !== "REPLACE") throw new SqliteConstraintError(`UNIQUE constraint failed: ${conflict.columns.map((column) => `${tbl.name}.${column}`).join(", ")}`);
4706
+ replacedRows.add(conflict.row);
4707
+ tbl.rows.splice(tbl.rows.indexOf(conflict.row), 1);
4708
+ yield* this.applyForeignKeyActions(tbl, conflict.row.data);
4540
4709
  conflict = yield* this.checkConstraintsAndConflicts(tbl, candidate, row.rowid);
4541
4710
  }
4542
4711
  row.data = newData;
@@ -5024,7 +5193,7 @@ var SqliteDatabase = class {
5024
5193
  d -= 1;
5025
5194
  } else if (d === 0 && t.type === "word") {
5026
5195
  const u = t.value.toUpperCase();
5027
- if (u === "FROM" || u === "WHERE" || u === "HAVING" || u === "WINDOW" || u === "LIMIT") {
5196
+ if (isFromClause(tokens, i) || u === "WHERE" || u === "HAVING" || u === "WINDOW" || u === "LIMIT") {
5028
5197
  clausePositions.push({ name: u, pos: i });
5029
5198
  } else if (u === "GROUP" && tokens[i + 1]?.value.toUpperCase() === "BY") {
5030
5199
  clausePositions.push({ name: "GROUP BY", pos: i });
@@ -5308,7 +5477,7 @@ var SqliteDatabase = class {
5308
5477
  const firstWindow = windowResults.keys().next().value;
5309
5478
  if (!orderByTokens?.length && firstWindow?.kind === "func" && firstWindow.over) {
5310
5479
  const sortSpecs = [
5311
- ...firstWindow.over.partitionBy.map((expr) => ({ expr, desc: false })),
5480
+ ...firstWindow.over.partitionBy.map((expr) => ({ expr, desc: false, nulls: void 0 })),
5312
5481
  ...firstWindow.over.orderBy
5313
5482
  ];
5314
5483
  if (sortSpecs.length > 0) {
@@ -5321,7 +5490,13 @@ var SqliteDatabase = class {
5321
5490
  yield* stepSort(keyed, function* (a, b) {
5322
5491
  for (let i = 0; i < sortSpecs.length; i++) {
5323
5492
  yield;
5324
- const cmp = compareSqlValues(a.keys[i], b.keys[i]);
5493
+ const vA = a.keys[i];
5494
+ const vB = b.keys[i];
5495
+ const nulls = sortSpecs[i].nulls;
5496
+ if (nulls && vA === null !== (vB === null)) {
5497
+ return vA === null === (nulls === "FIRST") ? -1 : 1;
5498
+ }
5499
+ const cmp = compareSqlValues(vA, vB);
5325
5500
  if (cmp !== 0) return sortSpecs[i].desc ? -cmp : cmp;
5326
5501
  }
5327
5502
  return 0;
@@ -6194,6 +6369,7 @@ var SqliteDatabase = class {
6194
6369
  const sameAliasAndName = alias.toLowerCase() === name.toLowerCase();
6195
6370
  const rows = yield* stepMap(this.preparing ? [] : tbl.rows, function* (r) {
6196
6371
  yield;
6372
+ this.rowTables.set(r.data, tbl);
6197
6373
  const tablesMap = sameAliasAndName ? { [alias]: r.data } : { [alias]: r.data, [name]: r.data };
6198
6374
  const rowidsMap = sameAliasAndName ? { [alias]: r.rowid } : { [alias]: r.rowid, [name]: r.rowid };
6199
6375
  return {
@@ -6398,6 +6574,9 @@ var SqliteDatabase = class {
6398
6574
  yield;
6399
6575
  const vA = yield* this.evalExprSteps(ob.expr, gA.representative, positionalParams, cteScope, { group: gA.group });
6400
6576
  const vB = yield* this.evalExprSteps(ob.expr, gB.representative, positionalParams, cteScope, { group: gB.group });
6577
+ if (ob.nulls && vA === null !== (vB === null)) {
6578
+ return vA === null === (ob.nulls === "FIRST") ? -1 : 1;
6579
+ }
6401
6580
  const cmp = compareSqlValues(vA, vB);
6402
6581
  if (cmp !== 0) {
6403
6582
  return ob.desc ? -cmp : cmp;
@@ -6994,7 +7173,16 @@ var SqliteDatabase = class {
6994
7173
  return 0;
6995
7174
  }
6996
7175
  const collation = expr.left.kind === "collate" ? expr.left.collation : expr.right.kind === "collate" ? expr.right.collation : "BINARY";
6997
- const l = yield* this.evalExprSteps(expr.left, row, positionalParams, cteScope, evaluation);
7176
+ let l = yield* this.evalExprSteps(expr.left, row, positionalParams, cteScope, evaluation);
7177
+ if (expr.op === "IS" || expr.op === "IS NOT") {
7178
+ let right = expr.right;
7179
+ while (right.kind === "collate") right = right.expr;
7180
+ if (right.kind === "literal" && right.booleanLiteral) {
7181
+ const truth = isTruthy(l instanceof Uint8Array ? toSqlString(l) : l);
7182
+ const matches = l !== null && truth === (right.value === 1);
7183
+ return matches !== (expr.op === "IS NOT") ? 1 : 0;
7184
+ }
7185
+ }
6998
7186
  if ((expr.op === "LIKE" || expr.op === "GLOB") && expr.right.kind === "func" && expr.right.name === "__like_escape__") {
6999
7187
  const pat = yield* this.evalExprSteps(
7000
7188
  expr.right.args[0],
@@ -7015,7 +7203,15 @@ var SqliteDatabase = class {
7015
7203
  }
7016
7204
  return matchLike(toSqlString(l), toSqlString(pat), expr.op === "LIKE", toSqlString(esc)) ? 1 : 0;
7017
7205
  }
7018
- const r = yield* this.evalExprSteps(expr.right, row, positionalParams, cteScope, evaluation);
7206
+ let r = yield* this.evalExprSteps(expr.right, row, positionalParams, cteScope, evaluation);
7207
+ if (["=", "==", "!=", "<>", "<", "<=", ">", ">=", "IS", "IS NOT"].includes(expr.op)) {
7208
+ const leftAffinity = this.expressionAffinity(expr.left, row);
7209
+ const rightAffinity = this.expressionAffinity(expr.right, row);
7210
+ if (leftAffinity === "NUMERIC" && rightAffinity !== "NUMERIC") r = applyColumnAffinity(r, "NUMERIC", false);
7211
+ else if (rightAffinity === "NUMERIC" && leftAffinity !== "NUMERIC") l = applyColumnAffinity(l, "NUMERIC", false);
7212
+ else if (leftAffinity === "TEXT" && rightAffinity === void 0) r = applyColumnAffinity(r, "TEXT", false);
7213
+ else if (rightAffinity === "TEXT" && leftAffinity === void 0) l = applyColumnAffinity(l, "TEXT", false);
7214
+ }
7019
7215
  return this.applyBinary(expr.op, l, r, collation);
7020
7216
  }
7021
7217
  case "between": {
@@ -7138,10 +7334,10 @@ var SqliteDatabase = class {
7138
7334
  yield* this.evalExprSteps(expr.args[1], row, positionalParams, cteScope, evaluation)
7139
7335
  ) : mode;
7140
7336
  if (mode === "ROLLBACK" && this.inTransaction) {
7141
- if (this.txSnapshot) {
7142
- yield* this.restoreSnapshot(this.txSnapshot);
7337
+ const snapshot = this.txSnapshot ?? this.savepoints.values().next().value;
7338
+ if (snapshot) {
7339
+ yield* this.restoreSnapshot(snapshot);
7143
7340
  }
7144
- this.inTransaction = false;
7145
7341
  this.txSnapshot = null;
7146
7342
  this.savepoints.clear();
7147
7343
  }
@@ -7174,6 +7370,31 @@ var SqliteDatabase = class {
7174
7370
  }
7175
7371
  }
7176
7372
  }
7373
+ expressionAffinity(expr, row) {
7374
+ if (expr.kind === "collate") return this.expressionAffinity(expr.expr, row);
7375
+ let type;
7376
+ if (expr.kind === "cast") {
7377
+ type = expr.targetType;
7378
+ } else if (expr.kind === "column") {
7379
+ for (const scope of [row, ...this.outerRows.slice().reverse()]) {
7380
+ const tables = scope.__tables;
7381
+ const sources = expr.table ? Object.entries(tables ?? {}).filter(([name]) => name.toLowerCase() === expr.table.toLowerCase()).map(([, data]) => data) : scope.__sources ?? [];
7382
+ for (const source of this.rowTables.has(scope) || sources.length === 0 ? [scope, ...sources] : sources) {
7383
+ const key = expr.table && source === scope ? `${expr.table}.${expr.name}` : expr.name;
7384
+ if (!Object.keys(source).some((name) => name.toLowerCase() === key.toLowerCase())) continue;
7385
+ const table = this.rowTables.get(source);
7386
+ const column = table?.columns.find((column2) => column2.name.toLowerCase() === expr.name.toLowerCase());
7387
+ type = column?.type;
7388
+ if (!column && table && ["rowid", "_rowid_", "oid"].includes(expr.name.toLowerCase())) type = "INTEGER";
7389
+ break;
7390
+ }
7391
+ if (type !== void 0) break;
7392
+ }
7393
+ }
7394
+ if (type === void 0) return void 0;
7395
+ const affinity = columnAffinity(type);
7396
+ return affinity === "BLOB" ? void 0 : affinity === "TEXT" ? "TEXT" : "NUMERIC";
7397
+ }
7177
7398
  applyUnary(op, v) {
7178
7399
  if (op === "NOT") {
7179
7400
  if (v === null) {
@@ -7260,10 +7481,10 @@ var SqliteDatabase = class {
7260
7481
  return integerResult(BigInt.asIntN(64, integerPrefix(l) | integerPrefix(r)));
7261
7482
  case "=":
7262
7483
  case "==":
7263
- return sqlEquals(l, r, collation) ? 1 : 0;
7484
+ return compareSqlValues(l, r, collation) === 0 ? 1 : 0;
7264
7485
  case "!=":
7265
7486
  case "<>":
7266
- return sqlEquals(l, r, collation) ? 0 : 1;
7487
+ return compareSqlValues(l, r, collation) !== 0 ? 1 : 0;
7267
7488
  case "<":
7268
7489
  return compareSqlValues(l, r, collation) < 0 ? 1 : 0;
7269
7490
  case "<=":
@@ -8024,8 +8245,10 @@ function* jsonString(parts) {
8024
8245
  function* jsonValue(value) {
8025
8246
  if (value instanceof JsonText) yield* textParts(value.valueOf());
8026
8247
  else if (typeof value === "string" || value instanceof String || value instanceof Uint8Array) yield* jsonString(cellParts(value, ""));
8027
- else if (value instanceof Number) yield Number.isFinite(value.valueOf()) ? toSqlString(value) : "null";
8028
- else if (typeof value === "bigint") yield value.toString();
8248
+ else if (value instanceof Number || typeof value === "number" && !Number.isInteger(value)) {
8249
+ const number = value.valueOf();
8250
+ yield Number.isFinite(number) ? formatReal(number, 20) : "null";
8251
+ } else if (typeof value === "bigint") yield value.toString();
8029
8252
  else yield JSON.stringify(value ?? null);
8030
8253
  }
8031
8254
  function* formatQueryParts({ columns, rows }, state) {
@@ -9341,13 +9564,14 @@ Options:
9341
9564
  } catch (err) {
9342
9565
  context.signal.throwIfAborted();
9343
9566
  const msg = err instanceof Error ? err.message : String(err);
9344
- await writeText(context.stderr, `Error: ${msg}
9567
+ const constraint = err instanceof SqliteConstraintError;
9568
+ await writeText(context.stderr, constraint ? `Error: stepping, ${msg} (${err.code})
9569
+ ` : `Error: ${msg}
9345
9570
  `);
9571
+ state.exitCode = constraint ? err.code : 1;
9346
9572
  if (state.bail || positional.length >= 2) {
9347
- state.exitCode = 1;
9348
9573
  return false;
9349
9574
  }
9350
- state.exitCode = 1;
9351
9575
  }
9352
9576
  if (state.exitRequested) {
9353
9577
  return false;
@@ -9415,6 +9639,7 @@ Options:
9415
9639
  }
9416
9640
  }
9417
9641
  if (!limitExceeded && state.dirty && state.dbPath !== ":memory:" && !state.readonly) {
9642
+ if (db.inTransaction) await execSingleStmt("ROLLBACK");
9418
9643
  await saveDbToDisk(state.dbPath);
9419
9644
  }
9420
9645
  return { exitCode: limitExceeded ? 1 : state.exitCode };
@@ -9922,6 +10147,7 @@ Options:
9922
10147
  if (!writeFileSync || !writeFileSync(save.file, save.bytes)) return void 0;
9923
10148
  }
9924
10149
  if (state.dirty && state.dbPath !== ":memory:") {
10150
+ if (db.inTransaction) db.executeStatement("ROLLBACK");
9925
10151
  if (!writeFileSync || !writeFileSync(state.dbPath, db.serializeToBytes())) return void 0;
9926
10152
  }
9927
10153
  return out;