@crvouga/sqlite-mem 1.1.2 → 1.2.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 +4 -1
- package/COMPATIBILITY-AUDIT.md +29 -15
- package/COMPATIBILITY.md +16 -8
- package/README.md +15 -12
- package/compat/coverage.json +779 -729
- package/compat/divergences.json +124 -0
- package/compat/requirements.json +43 -43
- package/compat/scenario-types.ts +63 -0
- package/compat/scenarios.ts +851 -0
- package/compat/smoke-baseline.json +15 -0
- package/dist/api/database.d.ts +12 -3
- package/dist/api/statement.d.ts +1 -1
- package/dist/ast/nodes.d.ts +3 -0
- package/dist/executor/env.d.ts +1 -1
- package/dist/executor/select.d.ts +2 -1
- package/dist/executor/triggers.d.ts +2 -2
- package/dist/expressions/context.d.ts +3 -1
- package/dist/expressions/like.d.ts +3 -2
- package/dist/functions/registry.d.ts +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +655 -185
- package/dist/index.js.map +4 -4
- package/dist/parser/parser.d.ts +2 -2
- package/dist/runtime/clock.d.ts +4 -2
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/options.d.ts +11 -3
- package/dist/runtime/prng.d.ts +11 -0
- package/dist/storage/database-state.d.ts +2 -0
- package/dist/storage/table.d.ts +2 -0
- package/dist/types/value.d.ts +5 -0
- package/dist/unstable.d.ts +3 -3
- package/dist/unstable.js +243 -64
- package/dist/unstable.js.map +3 -3
- package/dist/vtable/fts/table.d.ts +2 -3
- package/package.json +5 -2
package/dist/unstable.js
CHANGED
|
@@ -125,6 +125,23 @@ function applyAffinity(value, affinity) {
|
|
|
125
125
|
return value;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
function applyComparisonAffinity(left, right, leftAffinity, rightAffinity) {
|
|
129
|
+
const leftNumeric = leftAffinity === "INTEGER" || leftAffinity === "REAL" || leftAffinity === "NUMERIC";
|
|
130
|
+
const rightNumeric = rightAffinity === "INTEGER" || rightAffinity === "REAL" || rightAffinity === "NUMERIC";
|
|
131
|
+
const leftNone = leftAffinity === null || leftAffinity === "BLOB";
|
|
132
|
+
const rightNone = rightAffinity === null || rightAffinity === "BLOB";
|
|
133
|
+
if (leftNumeric && (rightAffinity === "TEXT" || rightNone)) {
|
|
134
|
+
const affinity = leftAffinity === "REAL" ? "REAL" : "NUMERIC";
|
|
135
|
+
return [left, applyAffinity(right, affinity)];
|
|
136
|
+
}
|
|
137
|
+
if (rightNumeric && (leftAffinity === "TEXT" || leftNone)) {
|
|
138
|
+
const affinity = rightAffinity === "REAL" ? "REAL" : "NUMERIC";
|
|
139
|
+
return [applyAffinity(left, affinity), right];
|
|
140
|
+
}
|
|
141
|
+
if (leftAffinity === "TEXT" && rightNone) return [left, applyAffinity(right, "TEXT")];
|
|
142
|
+
if (rightAffinity === "TEXT" && leftNone) return [applyAffinity(left, "TEXT"), right];
|
|
143
|
+
return [left, right];
|
|
144
|
+
}
|
|
128
145
|
function coerceToNumber(value) {
|
|
129
146
|
if (value === null) return null;
|
|
130
147
|
if (value instanceof SqlReal) return value.value;
|
|
@@ -281,14 +298,18 @@ function jsonErrorPosition(input) {
|
|
|
281
298
|
}
|
|
282
299
|
}
|
|
283
300
|
function isValidJsonText(input, flags = 0) {
|
|
284
|
-
const
|
|
301
|
+
const allowCanonical = flags === 0 || (flags & 1) !== 0;
|
|
302
|
+
const allowJson5 = (flags & 2) !== 0;
|
|
285
303
|
try {
|
|
286
304
|
if (allowJson5) {
|
|
287
305
|
parseJsonText(input);
|
|
288
306
|
return true;
|
|
289
307
|
}
|
|
290
|
-
|
|
291
|
-
|
|
308
|
+
if (allowCanonical) {
|
|
309
|
+
parseJsonText(input, { strictCanonical: true });
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
return false;
|
|
292
313
|
} catch {
|
|
293
314
|
return false;
|
|
294
315
|
}
|
|
@@ -1694,7 +1715,11 @@ function applyModifier(date, modifier) {
|
|
|
1694
1715
|
const normalized = modifier.trim().toLowerCase();
|
|
1695
1716
|
if (normalized === "unixepoch") return new Date((date.getTime() / 864e5 + JULIAN_UNIX_EPOCH) * 1e3);
|
|
1696
1717
|
if (normalized === "utc" || normalized === "localtime") return result;
|
|
1697
|
-
|
|
1718
|
+
const weekday = /^weekday\s+([0-6])$/.exec(normalized);
|
|
1719
|
+
if (weekday) {
|
|
1720
|
+
const target = Number(weekday[1]);
|
|
1721
|
+
result.setUTCDate(result.getUTCDate() + (target - result.getUTCDay() + 7) % 7);
|
|
1722
|
+
} else if (normalized === "start of day") result.setUTCHours(0, 0, 0, 0);
|
|
1698
1723
|
else if (normalized === "start of month") {
|
|
1699
1724
|
result.setUTCDate(1);
|
|
1700
1725
|
result.setUTCHours(0, 0, 0, 0);
|
|
@@ -2152,13 +2177,15 @@ var mathFunctions = {
|
|
|
2152
2177
|
function escapeRegexChar(char) {
|
|
2153
2178
|
return /[\\^$.*+?()[\]{}|]/.test(char) ? `\\${char}` : char;
|
|
2154
2179
|
}
|
|
2155
|
-
function likeLiteral(char) {
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2180
|
+
function likeLiteral(char, caseSensitive) {
|
|
2181
|
+
if (!caseSensitive) {
|
|
2182
|
+
const code = char.codePointAt(0);
|
|
2183
|
+
if (code >= 65 && code <= 90) return `[${char}${char.toLowerCase()}]`;
|
|
2184
|
+
if (code >= 97 && code <= 122) return `[${char}${char.toUpperCase()}]`;
|
|
2185
|
+
}
|
|
2159
2186
|
return escapeRegexChar(char);
|
|
2160
2187
|
}
|
|
2161
|
-
function likeMatch(text2, pattern, escape = null) {
|
|
2188
|
+
function likeMatch(text2, pattern, escape = null, caseSensitive = false) {
|
|
2162
2189
|
if (escape !== null && [...escape].length !== 1) {
|
|
2163
2190
|
throw new SqliteError("ESCAPE expression must be a single character", "other");
|
|
2164
2191
|
}
|
|
@@ -2168,13 +2195,13 @@ function likeMatch(text2, pattern, escape = null) {
|
|
|
2168
2195
|
const char = chars[i];
|
|
2169
2196
|
if (escape !== null && char === escape) {
|
|
2170
2197
|
const next = chars[++i];
|
|
2171
|
-
source += next === void 0 ? likeLiteral(char) : likeLiteral(next);
|
|
2198
|
+
source += next === void 0 ? likeLiteral(char, caseSensitive) : likeLiteral(next, caseSensitive);
|
|
2172
2199
|
} else if (char === "%") {
|
|
2173
2200
|
source += "[\\s\\S]*";
|
|
2174
2201
|
} else if (char === "_") {
|
|
2175
2202
|
source += "[\\s\\S]";
|
|
2176
2203
|
} else {
|
|
2177
|
-
source += likeLiteral(char);
|
|
2204
|
+
source += likeLiteral(char, caseSensitive);
|
|
2178
2205
|
}
|
|
2179
2206
|
}
|
|
2180
2207
|
return new RegExp(`${source}$`).test(text2);
|
|
@@ -2481,11 +2508,11 @@ var scalarFunctions = {
|
|
|
2481
2508
|
requireArgs3("load_extension", args, 1, 2);
|
|
2482
2509
|
throw new SqliteError("not authorized", "misuse");
|
|
2483
2510
|
},
|
|
2484
|
-
like(args) {
|
|
2511
|
+
like(args, context) {
|
|
2485
2512
|
requireArgs3("like", args, 2, 3);
|
|
2486
2513
|
if (args[0] === null || args[1] === null || args[2] === null) return null;
|
|
2487
2514
|
const escape = args[2] === void 0 ? null : text(args[2]);
|
|
2488
|
-
return likeMatch(text(args[1]), text(args[0]), escape) ? 1 : 0;
|
|
2515
|
+
return likeMatch(text(args[1]), text(args[0]), escape, context.caseSensitiveLike === true) ? 1 : 0;
|
|
2489
2516
|
},
|
|
2490
2517
|
glob(args) {
|
|
2491
2518
|
requireArgs3("glob", args, 2);
|
|
@@ -2830,7 +2857,8 @@ function sqlOr(left, right) {
|
|
|
2830
2857
|
if (leftTruth === null || rightTruth === null) return null;
|
|
2831
2858
|
return 0;
|
|
2832
2859
|
}
|
|
2833
|
-
function compareResult(op, left, right, collation) {
|
|
2860
|
+
function compareResult(op, left, right, collation, leftAffinity = null, rightAffinity = null) {
|
|
2861
|
+
[left, right] = applyComparisonAffinity(left, right, leftAffinity, rightAffinity);
|
|
2834
2862
|
if (op === "IS" || op === "IS NOT" || op === "IS DISTINCT FROM" || op === "IS NOT DISTINCT FROM") {
|
|
2835
2863
|
const equal = left === null || right === null ? left === right : (collation ? compareWithCollation(left, right, collation) : compareSql(left, right)) === 0;
|
|
2836
2864
|
if (op === "IS" || op === "IS NOT DISTINCT FROM") return booleanValue(equal);
|
|
@@ -2883,11 +2911,18 @@ function evalBinary(op, leftExpr, rightExpr, ctx) {
|
|
|
2883
2911
|
if (["=", "==", "!=", "<>", "<", "<=", ">", ">=", "IS", "IS NOT", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"].includes(
|
|
2884
2912
|
op
|
|
2885
2913
|
)) {
|
|
2886
|
-
return compareResult(
|
|
2914
|
+
return compareResult(
|
|
2915
|
+
op,
|
|
2916
|
+
left,
|
|
2917
|
+
right,
|
|
2918
|
+
resolveComparisonCollation(leftExpr, rightExpr, ctx) ?? void 0,
|
|
2919
|
+
resolveComparisonAffinity(leftExpr, ctx),
|
|
2920
|
+
resolveComparisonAffinity(rightExpr, ctx)
|
|
2921
|
+
);
|
|
2887
2922
|
}
|
|
2888
2923
|
if (op === "LIKE" || op === "NOT LIKE" || op === "GLOB" || op === "NOT GLOB") {
|
|
2889
2924
|
if (left === null || right === null) return null;
|
|
2890
|
-
const matches = op.includes("LIKE") ? likeMatch(textValue(left), textValue(right)) : globMatch(textValue(left), textValue(right));
|
|
2925
|
+
const matches = op.includes("LIKE") ? likeMatch(textValue(left), textValue(right), null, ctx.functionContext?.caseSensitiveLike === true) : globMatch(textValue(left), textValue(right));
|
|
2891
2926
|
return booleanValue(op.startsWith("NOT") ? !matches : matches);
|
|
2892
2927
|
}
|
|
2893
2928
|
if (left === null || right === null) return null;
|
|
@@ -3062,14 +3097,26 @@ function inheritedCollation(expr, ctx) {
|
|
|
3062
3097
|
return null;
|
|
3063
3098
|
}
|
|
3064
3099
|
}
|
|
3065
|
-
function
|
|
3100
|
+
function resolveComparisonAffinity(expr, ctx) {
|
|
3101
|
+
switch (expr.type) {
|
|
3102
|
+
case "column":
|
|
3103
|
+
return ctx.resolveAffinity?.(expr.table, expr.name) ?? ctx.parent?.resolveAffinity?.(expr.table, expr.name) ?? null;
|
|
3104
|
+
case "cast":
|
|
3105
|
+
return affinityFromTypeName(expr.typeName);
|
|
3106
|
+
case "collate":
|
|
3107
|
+
return resolveComparisonAffinity(expr.expr, ctx);
|
|
3108
|
+
default:
|
|
3109
|
+
return null;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
function evalIn(left, values, not, leftAffinity) {
|
|
3066
3113
|
if (values.length === 0) return booleanValue(not);
|
|
3067
3114
|
if (left === null) return null;
|
|
3068
3115
|
let sawNull = false;
|
|
3069
3116
|
for (const value of values) {
|
|
3070
3117
|
if (value === null) {
|
|
3071
3118
|
sawNull = true;
|
|
3072
|
-
} else if (compareSql(left, value) === 0) {
|
|
3119
|
+
} else if (compareSql(...applyComparisonAffinity(left, value, leftAffinity, null)) === 0) {
|
|
3073
3120
|
return booleanValue(!not);
|
|
3074
3121
|
}
|
|
3075
3122
|
}
|
|
@@ -3115,8 +3162,9 @@ function evalExpr(expr, ctx) {
|
|
|
3115
3162
|
case "between": {
|
|
3116
3163
|
const value = evalExpr(expr.expr, ctx);
|
|
3117
3164
|
const collation = resolveComparisonCollation(expr.expr, expr.lower, ctx) ?? resolveComparisonCollation(expr.expr, expr.upper, ctx) ?? void 0;
|
|
3118
|
-
const
|
|
3119
|
-
const
|
|
3165
|
+
const affinity = resolveComparisonAffinity(expr.expr, ctx);
|
|
3166
|
+
const lower = compareResult(">=", value, evalExpr(expr.lower, ctx), collation, affinity);
|
|
3167
|
+
const result = sqlAnd(lower, () => compareResult("<=", value, evalExpr(expr.upper, ctx), collation, affinity));
|
|
3120
3168
|
if (result === null) return null;
|
|
3121
3169
|
return expr.not ? booleanValue(result === 0) : result;
|
|
3122
3170
|
}
|
|
@@ -3143,14 +3191,19 @@ function evalExpr(expr, ctx) {
|
|
|
3143
3191
|
}
|
|
3144
3192
|
const left = evalExpr(expr.expr, ctx);
|
|
3145
3193
|
const values = Array.isArray(expr.values) ? expr.values.map((value) => evalExpr(value, ctx)) : executeSelect(ctx, expr.values).rows.map((row) => row[0] ?? null);
|
|
3146
|
-
return evalIn(left, values, expr.not);
|
|
3194
|
+
return evalIn(left, values, expr.not, resolveComparisonAffinity(expr.expr, ctx));
|
|
3147
3195
|
}
|
|
3148
3196
|
case "like": {
|
|
3149
3197
|
const value = evalExpr(expr.expr, ctx);
|
|
3150
3198
|
const pattern = evalExpr(expr.pattern, ctx);
|
|
3151
3199
|
const escape = expr.escape === null ? null : evalExpr(expr.escape, ctx);
|
|
3152
3200
|
if (value === null || pattern === null || escape === null && expr.escape !== null) return null;
|
|
3153
|
-
const match = expr.op === "LIKE" ? likeMatch(
|
|
3201
|
+
const match = expr.op === "LIKE" ? likeMatch(
|
|
3202
|
+
textValue(value),
|
|
3203
|
+
textValue(pattern),
|
|
3204
|
+
escape === null ? null : textValue(escape),
|
|
3205
|
+
ctx.functionContext?.caseSensitiveLike === true
|
|
3206
|
+
) : globMatch(textValue(value), textValue(pattern));
|
|
3154
3207
|
return booleanValue(expr.not ? !match : match);
|
|
3155
3208
|
}
|
|
3156
3209
|
case "case": {
|
|
@@ -3942,13 +3995,20 @@ var Parser = class {
|
|
|
3942
3995
|
const stmt = this.parseStatement();
|
|
3943
3996
|
return { type: "explain", queryPlan, statement: stmt };
|
|
3944
3997
|
}
|
|
3945
|
-
if (this.
|
|
3998
|
+
if (this.at("WITH")) {
|
|
3999
|
+
const withClause = this.parseWithClause();
|
|
4000
|
+
if (this.at("SELECT")) return this.parseSelectStmt(withClause);
|
|
4001
|
+
if (this.at("INSERT") || this.at("REPLACE")) return this.parseInsertStmt(withClause);
|
|
4002
|
+
if (this.at("UPDATE")) return this.parseUpdateStmt(withClause);
|
|
4003
|
+
if (this.at("DELETE")) return this.parseDeleteStmt(withClause);
|
|
4004
|
+
this.syntaxError("expected SELECT, INSERT, UPDATE, or DELETE after WITH clause");
|
|
4005
|
+
}
|
|
3946
4006
|
if (this.at("SELECT")) return this.parseSelectStmt();
|
|
3947
|
-
if (this.
|
|
4007
|
+
if (this.at("INSERT") || this.at("REPLACE")) {
|
|
3948
4008
|
return this.parseInsertStmt();
|
|
3949
4009
|
}
|
|
3950
|
-
if (this.
|
|
3951
|
-
if (this.
|
|
4010
|
+
if (this.at("UPDATE")) return this.parseUpdateStmt();
|
|
4011
|
+
if (this.at("DELETE")) return this.parseDeleteStmt();
|
|
3952
4012
|
if (this.at("CREATE")) return this.parseCreateStmt();
|
|
3953
4013
|
if (this.at("DROP")) return this.parseDropStmt();
|
|
3954
4014
|
if (this.at("ALTER")) return this.parseAlterTableStmt();
|
|
@@ -4010,12 +4070,15 @@ var Parser = class {
|
|
|
4010
4070
|
this.expect("RPAREN");
|
|
4011
4071
|
}
|
|
4012
4072
|
this.expect("AS");
|
|
4013
|
-
|
|
4014
|
-
|
|
4073
|
+
let materialized = null;
|
|
4074
|
+
if (this.match("NOT")) {
|
|
4075
|
+
this.expect("MATERIALIZED", "expected MATERIALIZED after NOT");
|
|
4076
|
+
materialized = "not_materialized";
|
|
4077
|
+
} else if (this.match("MATERIALIZED")) materialized = "materialized";
|
|
4015
4078
|
this.expect("LPAREN");
|
|
4016
|
-
const select = this.at("VALUES") ? this.parseValuesAsSelect() : this.parseSelectCore();
|
|
4079
|
+
const select = this.at("VALUES") ? this.parseValuesAsSelect() : this.at("WITH") ? this.parseSelectStmt() : this.parseSelectCore();
|
|
4017
4080
|
this.expect("RPAREN");
|
|
4018
|
-
ctes.push({ name, columns, select });
|
|
4081
|
+
ctes.push({ name, columns, materialized, select });
|
|
4019
4082
|
} while (this.match("COMMA"));
|
|
4020
4083
|
return { recursive, ctes };
|
|
4021
4084
|
}
|
|
@@ -4023,8 +4086,7 @@ var Parser = class {
|
|
|
4023
4086
|
return this.at("WITH") ? this.parseWithClause() : null;
|
|
4024
4087
|
}
|
|
4025
4088
|
// ── SELECT ──────────────────────────────────────────────────────────────
|
|
4026
|
-
parseSelectStmt() {
|
|
4027
|
-
const withClause = this.parseOptionalWith();
|
|
4089
|
+
parseSelectStmt(withClause = this.parseOptionalWith()) {
|
|
4028
4090
|
const select = this.parseSelectCore();
|
|
4029
4091
|
select.with = withClause;
|
|
4030
4092
|
return select;
|
|
@@ -4322,8 +4384,7 @@ var Parser = class {
|
|
|
4322
4384
|
return { limit: first, offset };
|
|
4323
4385
|
}
|
|
4324
4386
|
// ── INSERT / REPLACE ────────────────────────────────────────────────────
|
|
4325
|
-
parseInsertStmt() {
|
|
4326
|
-
const withClause = this.parseOptionalWith();
|
|
4387
|
+
parseInsertStmt(withClause = this.parseOptionalWith()) {
|
|
4327
4388
|
let mode = "insert";
|
|
4328
4389
|
if (this.match("REPLACE")) {
|
|
4329
4390
|
mode = "replace";
|
|
@@ -4426,8 +4487,7 @@ var Parser = class {
|
|
|
4426
4487
|
return this.parseResultColumns();
|
|
4427
4488
|
}
|
|
4428
4489
|
// ── UPDATE ──────────────────────────────────────────────────────────────
|
|
4429
|
-
parseUpdateStmt() {
|
|
4430
|
-
const withClause = this.parseOptionalWith();
|
|
4490
|
+
parseUpdateStmt(withClause = this.parseOptionalWith()) {
|
|
4431
4491
|
this.expect("UPDATE");
|
|
4432
4492
|
const or = this.mapUpdateOr(this.parseOrConflict());
|
|
4433
4493
|
const table = this.parseTableName();
|
|
@@ -4442,8 +4502,7 @@ var Parser = class {
|
|
|
4442
4502
|
return { type: "update", with: withClause, or, table, alias, set, from, where, returning };
|
|
4443
4503
|
}
|
|
4444
4504
|
// ── DELETE ──────────────────────────────────────────────────────────────
|
|
4445
|
-
parseDeleteStmt() {
|
|
4446
|
-
const withClause = this.parseOptionalWith();
|
|
4505
|
+
parseDeleteStmt(withClause = this.parseOptionalWith()) {
|
|
4447
4506
|
this.expect("DELETE");
|
|
4448
4507
|
this.expect("FROM");
|
|
4449
4508
|
const table = this.parseTableName();
|
|
@@ -5112,6 +5171,24 @@ var Parser = class {
|
|
|
5112
5171
|
left = this.parseLikeRhs(left, true, "GLOB");
|
|
5113
5172
|
continue;
|
|
5114
5173
|
}
|
|
5174
|
+
if (n.kind === "REGEXP") {
|
|
5175
|
+
this.advance();
|
|
5176
|
+
this.advance();
|
|
5177
|
+
const pattern = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
|
|
5178
|
+
left = {
|
|
5179
|
+
type: "unary",
|
|
5180
|
+
op: "NOT",
|
|
5181
|
+
expr: {
|
|
5182
|
+
type: "function",
|
|
5183
|
+
name: "REGEXP",
|
|
5184
|
+
distinct: false,
|
|
5185
|
+
args: [pattern, left],
|
|
5186
|
+
orderBy: [],
|
|
5187
|
+
filter: null
|
|
5188
|
+
}
|
|
5189
|
+
};
|
|
5190
|
+
continue;
|
|
5191
|
+
}
|
|
5115
5192
|
if (n.kind === "BETWEEN") {
|
|
5116
5193
|
this.advance();
|
|
5117
5194
|
this.advance();
|
|
@@ -5167,6 +5244,12 @@ var Parser = class {
|
|
|
5167
5244
|
left = this.parseLikeRhs(left, false, "GLOB");
|
|
5168
5245
|
continue;
|
|
5169
5246
|
}
|
|
5247
|
+
if (this.at("REGEXP") && PREC.IS_IN_LIKE >= minPrec) {
|
|
5248
|
+
this.advance();
|
|
5249
|
+
const pattern = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
|
|
5250
|
+
left = { type: "function", name: "REGEXP", distinct: false, args: [pattern, left], orderBy: [], filter: null };
|
|
5251
|
+
continue;
|
|
5252
|
+
}
|
|
5170
5253
|
if (this.at("MATCH") && PREC.IS_IN_LIKE >= minPrec) {
|
|
5171
5254
|
this.advance();
|
|
5172
5255
|
const right2 = this.parseExprPrec(PREC.IS_IN_LIKE + 1);
|
|
@@ -5325,7 +5408,7 @@ var Parser = class {
|
|
|
5325
5408
|
}
|
|
5326
5409
|
if (this.at("CURRENT_DATE") || this.at("CURRENT_TIME") || this.at("CURRENT_TIMESTAMP")) {
|
|
5327
5410
|
const tok = this.advance();
|
|
5328
|
-
return { type: "function", name: tok.value, distinct: false, args: [], filter: null };
|
|
5411
|
+
return { type: "function", name: tok.value, distinct: false, args: [], orderBy: [], filter: null };
|
|
5329
5412
|
}
|
|
5330
5413
|
if (this.at("NUMBER")) {
|
|
5331
5414
|
const tok = this.advance();
|
|
@@ -5408,6 +5491,7 @@ var Parser = class {
|
|
|
5408
5491
|
} while (this.match("COMMA"));
|
|
5409
5492
|
}
|
|
5410
5493
|
}
|
|
5494
|
+
const orderBy = this.parseOrderBy();
|
|
5411
5495
|
this.expect("RPAREN");
|
|
5412
5496
|
if (this.match("FILTER")) {
|
|
5413
5497
|
this.expect("LPAREN");
|
|
@@ -5428,13 +5512,13 @@ var Parser = class {
|
|
|
5428
5512
|
window = this.parseWindowSpec();
|
|
5429
5513
|
this.expect("RPAREN");
|
|
5430
5514
|
}
|
|
5431
|
-
const func = isAgg ? { type: "aggregate", name: upper, distinct, args, filter } : { type: "function", name, distinct, args, filter };
|
|
5515
|
+
const func = isAgg ? { type: "aggregate", name: upper, distinct, args, orderBy, filter } : { type: "function", name, distinct, args, orderBy, filter };
|
|
5432
5516
|
return { type: "window", func, window };
|
|
5433
5517
|
}
|
|
5434
5518
|
if (isAgg) {
|
|
5435
|
-
return { type: "aggregate", name: upper, distinct, args, filter };
|
|
5519
|
+
return { type: "aggregate", name: upper, distinct, args, orderBy, filter };
|
|
5436
5520
|
}
|
|
5437
|
-
return { type: "function", name, distinct, args, filter };
|
|
5521
|
+
return { type: "function", name, distinct, args, orderBy, filter };
|
|
5438
5522
|
}
|
|
5439
5523
|
parseCaseExpr(base) {
|
|
5440
5524
|
const whens = [];
|
|
@@ -5542,8 +5626,12 @@ function fixedClock(instant = DEFAULT_NOW) {
|
|
|
5542
5626
|
if (Number.isNaN(ms)) throw new RangeError("invalid clock instant");
|
|
5543
5627
|
return () => new Date(ms);
|
|
5544
5628
|
}
|
|
5629
|
+
function systemClock() {
|
|
5630
|
+
return () => /* @__PURE__ */ new Date();
|
|
5631
|
+
}
|
|
5545
5632
|
function resolveClock(now) {
|
|
5546
5633
|
if (now === void 0) return fixedClock(DEFAULT_NOW);
|
|
5634
|
+
if (now === "system") return systemClock();
|
|
5547
5635
|
if (typeof now === "function") return () => new Date(now().getTime());
|
|
5548
5636
|
return fixedClock(now);
|
|
5549
5637
|
}
|
|
@@ -5608,6 +5696,28 @@ var Prng = class _Prng {
|
|
|
5608
5696
|
return copy;
|
|
5609
5697
|
}
|
|
5610
5698
|
};
|
|
5699
|
+
var OsEntropy = class _OsEntropy extends Prng {
|
|
5700
|
+
constructor() {
|
|
5701
|
+
super(1);
|
|
5702
|
+
}
|
|
5703
|
+
nextU64() {
|
|
5704
|
+
const bytes = new Uint8Array(8);
|
|
5705
|
+
crypto.getRandomValues(bytes);
|
|
5706
|
+
let value = 0n;
|
|
5707
|
+
for (let i = 0; i < 8; i++) {
|
|
5708
|
+
value |= BigInt(bytes[i]) << BigInt(i * 8);
|
|
5709
|
+
}
|
|
5710
|
+
return BigInt.asUintN(64, value);
|
|
5711
|
+
}
|
|
5712
|
+
getState() {
|
|
5713
|
+
return 0n;
|
|
5714
|
+
}
|
|
5715
|
+
setState(_state) {
|
|
5716
|
+
}
|
|
5717
|
+
clone() {
|
|
5718
|
+
return new _OsEntropy();
|
|
5719
|
+
}
|
|
5720
|
+
};
|
|
5611
5721
|
function deriveSeed(...parts) {
|
|
5612
5722
|
let hash = 2166136261;
|
|
5613
5723
|
for (const part of parts) {
|
|
@@ -6683,7 +6793,7 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
|
|
|
6683
6793
|
insert(values, rowid) {
|
|
6684
6794
|
const command = this.detectCommand(values);
|
|
6685
6795
|
if (command !== null) {
|
|
6686
|
-
this.runCommand(command, values);
|
|
6796
|
+
this.runCommand(command, values, rowid);
|
|
6687
6797
|
return 0;
|
|
6688
6798
|
}
|
|
6689
6799
|
const assigned = rowid ?? this.nextRowid++;
|
|
@@ -6832,18 +6942,63 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
|
|
|
6832
6942
|
}
|
|
6833
6943
|
return parts.join(" ");
|
|
6834
6944
|
}
|
|
6835
|
-
/** FTS3 matchinfo
|
|
6836
|
-
matchinfo(cursor,
|
|
6945
|
+
/** FTS3 matchinfo format encoded as native-style 32-bit little-endian integers. */
|
|
6946
|
+
matchinfo(cursor, format = "pcx") {
|
|
6837
6947
|
const row = this.rows.get(cursor.rowid);
|
|
6838
6948
|
const nPhrase = Math.max(1, cursor.phraseTerms.length);
|
|
6839
6949
|
const nCol = this.columns.length;
|
|
6840
|
-
const values = [
|
|
6841
|
-
for (
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6950
|
+
const values = [];
|
|
6951
|
+
for (const request of format) {
|
|
6952
|
+
switch (request) {
|
|
6953
|
+
case "p":
|
|
6954
|
+
values.push(nPhrase);
|
|
6955
|
+
break;
|
|
6956
|
+
case "c":
|
|
6957
|
+
values.push(nCol);
|
|
6958
|
+
break;
|
|
6959
|
+
case "s":
|
|
6960
|
+
for (let c = 0; c < nCol; c++) {
|
|
6961
|
+
let longest = 0;
|
|
6962
|
+
let run = 0;
|
|
6963
|
+
for (let p = 0; p < nPhrase; p++) {
|
|
6964
|
+
const phrase = cursor.phraseTerms[p] ?? [];
|
|
6965
|
+
if (row && this.phraseFreq(row, this.columns[c], phrase) > 0) {
|
|
6966
|
+
run++;
|
|
6967
|
+
longest = Math.max(longest, run);
|
|
6968
|
+
} else {
|
|
6969
|
+
run = 0;
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6972
|
+
values.push(longest);
|
|
6973
|
+
}
|
|
6974
|
+
break;
|
|
6975
|
+
case "x":
|
|
6976
|
+
for (let p = 0; p < nPhrase; p++) {
|
|
6977
|
+
const phrase = cursor.phraseTerms[p] ?? [];
|
|
6978
|
+
for (let c = 0; c < nCol; c++) {
|
|
6979
|
+
const column = this.columns[c];
|
|
6980
|
+
const localHits = row ? this.phraseFreq(row, column, phrase) : 0;
|
|
6981
|
+
let globalHits = 0;
|
|
6982
|
+
let matchingRows = 0;
|
|
6983
|
+
for (const candidate of this.rows.values()) {
|
|
6984
|
+
const hits = this.phraseFreq(candidate, column, phrase);
|
|
6985
|
+
globalHits += hits;
|
|
6986
|
+
if (hits > 0) matchingRows++;
|
|
6987
|
+
}
|
|
6988
|
+
values.push(localHits, globalHits, matchingRows);
|
|
6989
|
+
}
|
|
6990
|
+
}
|
|
6991
|
+
break;
|
|
6992
|
+
case "y":
|
|
6993
|
+
for (let p = 0; p < nPhrase; p++) {
|
|
6994
|
+
const phrase = cursor.phraseTerms[p] ?? [];
|
|
6995
|
+
for (let c = 0; c < nCol; c++) {
|
|
6996
|
+
values.push(row ? this.phraseFreq(row, this.columns[c], phrase) : 0);
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6999
|
+
break;
|
|
7000
|
+
default:
|
|
7001
|
+
throw new SqliteError(`unrecognized matchinfo request: ${request}`, "other");
|
|
6847
7002
|
}
|
|
6848
7003
|
}
|
|
6849
7004
|
const buf = new Uint8Array(values.length * 4);
|
|
@@ -6891,13 +7046,9 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
|
|
|
6891
7046
|
if (!values.has(key)) return null;
|
|
6892
7047
|
const v = values.get(key);
|
|
6893
7048
|
if (typeof v !== "string") return null;
|
|
6894
|
-
const otherContent = [...values.entries()].some(
|
|
6895
|
-
([k, val]) => k !== key && val !== null && this.columns.some((c) => c.toLowerCase() === k)
|
|
6896
|
-
);
|
|
6897
|
-
if (otherContent) return null;
|
|
6898
7049
|
return v;
|
|
6899
7050
|
}
|
|
6900
|
-
runCommand(command, _values) {
|
|
7051
|
+
runCommand(command, _values, rowid) {
|
|
6901
7052
|
const cmd = command.toLowerCase();
|
|
6902
7053
|
if (cmd === "optimize") return;
|
|
6903
7054
|
if (cmd === "rebuild") {
|
|
@@ -6912,13 +7063,15 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
|
|
|
6912
7063
|
"other"
|
|
6913
7064
|
);
|
|
6914
7065
|
}
|
|
6915
|
-
for (const
|
|
7066
|
+
for (const rowid2 of [...this.rows.keys()]) this.delete(rowid2);
|
|
6916
7067
|
return;
|
|
6917
7068
|
}
|
|
6918
7069
|
if (cmd.startsWith("merge=") || cmd.startsWith("automerge=")) {
|
|
6919
7070
|
throw new SqliteError("SQL logic error", "other");
|
|
6920
7071
|
}
|
|
6921
7072
|
if (cmd === "delete") {
|
|
7073
|
+
if (rowid === void 0) throw new SqliteError("SQL logic error", "other");
|
|
7074
|
+
this.delete(rowid);
|
|
6922
7075
|
return;
|
|
6923
7076
|
}
|
|
6924
7077
|
throw new SqliteError("SQL logic error", "other");
|
|
@@ -7151,11 +7304,6 @@ var Fts5VirtualTable = class _Fts5VirtualTable {
|
|
|
7151
7304
|
}
|
|
7152
7305
|
return n;
|
|
7153
7306
|
}
|
|
7154
|
-
termFreq(row, column, term) {
|
|
7155
|
-
const needle = this.normalizeQueryTerm(term);
|
|
7156
|
-
const tokens = row.tokensByColumn.get(column.toLowerCase()) ?? [];
|
|
7157
|
-
return tokens.filter((t) => t.term === needle || t.term.startsWith(needle)).length;
|
|
7158
|
-
}
|
|
7159
7307
|
docLength(row) {
|
|
7160
7308
|
let n = 0;
|
|
7161
7309
|
for (const col of this.indexedColumns()) n += (row.tokensByColumn.get(col.toLowerCase()) ?? []).length;
|
|
@@ -7419,6 +7567,8 @@ var Table = class _Table {
|
|
|
7419
7567
|
scanCache = null;
|
|
7420
7568
|
/** Lazy covering hashes: column nameLower → serializeIndexKey → rowids. */
|
|
7421
7569
|
equalityHashes = null;
|
|
7570
|
+
/** Cached maximum rowid. `undefined` means recompute after deleting the maximum. */
|
|
7571
|
+
maximumRowid = null;
|
|
7422
7572
|
frozen = false;
|
|
7423
7573
|
constructor(name, columns, options = {}) {
|
|
7424
7574
|
this.name = name;
|
|
@@ -7621,7 +7771,12 @@ var Table = class _Table {
|
|
|
7621
7771
|
if (alias) values.set(normalizeColumnName(alias.name), targetKey);
|
|
7622
7772
|
const candidate = { rowid: targetKey, values };
|
|
7623
7773
|
this.validate(candidate, key);
|
|
7624
|
-
if (targetKey !== key)
|
|
7774
|
+
if (targetKey !== key) {
|
|
7775
|
+
this.rows.delete(key);
|
|
7776
|
+
if (this.maximumRowid !== null && this.maximumRowid !== void 0 && sameRowid2(key, this.maximumRowid)) {
|
|
7777
|
+
this.maximumRowid = void 0;
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7625
7780
|
this.rows.set(targetKey, candidate);
|
|
7626
7781
|
this.advanceNextRowid(targetKey);
|
|
7627
7782
|
this.reindexEquality(existing, candidate);
|
|
@@ -7635,6 +7790,9 @@ var Table = class _Table {
|
|
|
7635
7790
|
if (this.withoutRowid) this.clusteredRows.delete(this.makeClusterKey(existing.values));
|
|
7636
7791
|
this.unindexEquality(existing);
|
|
7637
7792
|
this.invalidateScan();
|
|
7793
|
+
if (this.maximumRowid !== null && this.maximumRowid !== void 0 && sameRowid2(key, this.maximumRowid)) {
|
|
7794
|
+
this.maximumRowid = void 0;
|
|
7795
|
+
}
|
|
7638
7796
|
return this.rows.delete(key);
|
|
7639
7797
|
}
|
|
7640
7798
|
*scan() {
|
|
@@ -7656,6 +7814,7 @@ var Table = class _Table {
|
|
|
7656
7814
|
strict: this.strict
|
|
7657
7815
|
});
|
|
7658
7816
|
copy.nextRowid = this.nextRowid;
|
|
7817
|
+
copy.maximumRowid = this.maximumRowid;
|
|
7659
7818
|
for (const [rowid, row] of this.rows) copy.rows.set(rowid, cloneRow(row));
|
|
7660
7819
|
for (const [clusterKey, row] of this.clusteredRows) copy.clusteredRows.set(clusterKey, cloneRow(row));
|
|
7661
7820
|
return copy;
|
|
@@ -7668,6 +7827,7 @@ var Table = class _Table {
|
|
|
7668
7827
|
}
|
|
7669
7828
|
/** Rebuild clustered storage after snapshot decode or bulk load. */
|
|
7670
7829
|
rebuildClusteredRows() {
|
|
7830
|
+
this.maximumRowid = void 0;
|
|
7671
7831
|
if (!this.withoutRowid) return;
|
|
7672
7832
|
this.clusteredRows.clear();
|
|
7673
7833
|
for (const row of this.rows.values()) {
|
|
@@ -7776,11 +7936,23 @@ var Table = class _Table {
|
|
|
7776
7936
|
return primary[0];
|
|
7777
7937
|
}
|
|
7778
7938
|
allocateRowid() {
|
|
7939
|
+
if (!this.columns.some((column) => column.autoincrement)) {
|
|
7940
|
+
if (this.maximumRowid === void 0) {
|
|
7941
|
+
this.maximumRowid = null;
|
|
7942
|
+
for (const rowid of this.rows.keys()) {
|
|
7943
|
+
if (this.maximumRowid === null || compareRowids(rowid, this.maximumRowid) > 0) this.maximumRowid = rowid;
|
|
7944
|
+
}
|
|
7945
|
+
}
|
|
7946
|
+
return this.maximumRowid === null ? 1 : incrementRowid(this.maximumRowid);
|
|
7947
|
+
}
|
|
7779
7948
|
let candidate = canonicalRowid(this.nextRowid);
|
|
7780
7949
|
while (this.rows.has(candidate)) candidate = incrementRowid(candidate);
|
|
7781
7950
|
return candidate;
|
|
7782
7951
|
}
|
|
7783
7952
|
advanceNextRowid(rowid) {
|
|
7953
|
+
if (this.maximumRowid === null || this.maximumRowid !== void 0 && compareRowids(rowid, this.maximumRowid) > 0) {
|
|
7954
|
+
this.maximumRowid = rowid;
|
|
7955
|
+
}
|
|
7784
7956
|
if (compareRowids(rowid, this.nextRowid) >= 0) this.nextRowid = incrementRowid(rowid);
|
|
7785
7957
|
}
|
|
7786
7958
|
};
|
|
@@ -7855,6 +8027,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
7855
8027
|
changes = 0;
|
|
7856
8028
|
totalChanges = 0;
|
|
7857
8029
|
foreignKeysEnabled = false;
|
|
8030
|
+
/** When true, LIKE / like() are case-sensitive (SQLite `PRAGMA case_sensitive_like`). */
|
|
8031
|
+
caseSensitiveLike = false;
|
|
7858
8032
|
schemaVersion = 0;
|
|
7859
8033
|
userVersion = 0;
|
|
7860
8034
|
databaseForSchema(schema, qualifiedForError) {
|
|
@@ -8299,6 +8473,7 @@ var DatabaseState = class _DatabaseState {
|
|
|
8299
8473
|
copy.changes = this.changes;
|
|
8300
8474
|
copy.totalChanges = this.totalChanges;
|
|
8301
8475
|
copy.foreignKeysEnabled = this.foreignKeysEnabled;
|
|
8476
|
+
copy.caseSensitiveLike = this.caseSensitiveLike;
|
|
8302
8477
|
copy.schemaVersion = this.schemaVersion;
|
|
8303
8478
|
copy.userVersion = this.userVersion;
|
|
8304
8479
|
return copy;
|
|
@@ -8318,6 +8493,7 @@ var DatabaseState = class _DatabaseState {
|
|
|
8318
8493
|
copy.changes = this.changes;
|
|
8319
8494
|
copy.totalChanges = this.totalChanges;
|
|
8320
8495
|
copy.foreignKeysEnabled = this.foreignKeysEnabled;
|
|
8496
|
+
copy.caseSensitiveLike = this.caseSensitiveLike;
|
|
8321
8497
|
copy.schemaVersion = this.schemaVersion;
|
|
8322
8498
|
copy.userVersion = this.userVersion;
|
|
8323
8499
|
return copy;
|
|
@@ -8379,6 +8555,7 @@ var DatabaseState = class _DatabaseState {
|
|
|
8379
8555
|
this.changes = copy.changes;
|
|
8380
8556
|
this.totalChanges = copy.totalChanges;
|
|
8381
8557
|
this.foreignKeysEnabled = copy.foreignKeysEnabled;
|
|
8558
|
+
this.caseSensitiveLike = copy.caseSensitiveLike;
|
|
8382
8559
|
this.schemaVersion = copy.schemaVersion;
|
|
8383
8560
|
this.userVersion = copy.userVersion;
|
|
8384
8561
|
}
|
|
@@ -8723,6 +8900,7 @@ function jsonReviver(_key, value) {
|
|
|
8723
8900
|
export {
|
|
8724
8901
|
DEFAULT_DATABASE_SEED,
|
|
8725
8902
|
DEFAULT_NOW,
|
|
8903
|
+
OsEntropy,
|
|
8726
8904
|
Prng,
|
|
8727
8905
|
SqlJsonText,
|
|
8728
8906
|
SqlReal,
|
|
@@ -8748,6 +8926,7 @@ export {
|
|
|
8748
8926
|
resolveClock,
|
|
8749
8927
|
sqlValueEquals,
|
|
8750
8928
|
storageClassOf,
|
|
8929
|
+
systemClock,
|
|
8751
8930
|
toInteger,
|
|
8752
8931
|
tokenize,
|
|
8753
8932
|
typeofSql,
|