@minnowdb/core 0.7.10 → 0.9.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/dist/engine/artifact-cache.js +3 -2
- package/dist/engine/buffered-writer.js +12 -2
- package/dist/engine/client.d.ts +9 -0
- package/dist/engine/client.js +112 -20
- package/dist/engine/database.d.ts +5 -3
- package/dist/engine/database.js +2199 -1675
- package/dist/engine/errors.d.ts +21 -2
- package/dist/engine/errors.js +30 -1
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +4 -0
- package/dist/engine/live-accept.js +13 -0
- package/dist/engine/live-aggregate.js +264 -0
- package/dist/engine/live-patch.d.ts +21 -0
- package/dist/engine/live-patch.js +31 -0
- package/dist/engine/live.d.ts +14 -0
- package/dist/engine/live.js +146 -142
- package/dist/engine/optimizer.js +11 -6
- package/dist/engine/query-cache.js +19 -15
- package/dist/engine/query-generations.js +61 -0
- package/dist/engine/query-identity.js +41 -0
- package/dist/engine/query.d.ts +7 -13
- package/dist/engine/query.js +298 -435
- package/dist/engine/result-state.d.ts +7 -0
- package/dist/engine/result-state.js +15 -0
- package/dist/engine/sql-domains.js +121 -0
- package/dist/engine/sql-semantics.js +7 -4
- package/dist/engine/typed-live.js +28 -20
- package/dist/engine/vector.d.ts +4 -0
- package/dist/engine/vector.js +14 -14
- package/dist/engine/windows.d.ts +12 -0
- package/dist/engine/windows.js +387 -0
- package/dist/engine/worker-server.d.ts +1 -1
- package/dist/engine/worker-server.js +28 -15
- package/dist/engine/write-coordinator.js +54 -0
- package/dist/plan/model.d.ts +1 -1
- package/dist/storage/indexeddb.js +134 -89
- package/dist/storage/opfs/index.d.ts +1 -1
- package/dist/storage/opfs/index.js +3 -1
- package/dist/storage/opfs/leader.js +20 -9
- package/dist/storage/opfs/rpc.js +3 -1
- package/dist/storage/opfs/store.d.ts +2 -0
- package/dist/storage/opfs/store.js +119 -43
- package/dist/storage/toolkit/record-core.js +2 -1
- package/dist/storage/types.d.ts +14 -0
- package/dist/storage/types.js +21 -0
- package/dist/transactions/index.d.ts +3 -0
- package/dist/transactions/index.js +4 -1
- package/dist/worker-protocol/index.d.ts +1 -1
- package/dist/worker-protocol/index.js +1 -1
- package/package.json +2 -2
- package/postgres-feature-profile.json +6 -1
- package/sql-feature-matrix.json +20 -27
- package/dist/date-value.d.ts +0 -20
- package/dist/engine/artifact-cache.d.ts +0 -29
- package/dist/engine/byte-estimates.d.ts +0 -11
- package/dist/engine/cancellation.d.ts +0 -2
- package/dist/engine/defaults.d.ts +0 -29
- package/dist/engine/group-index.d.ts +0 -33
- package/dist/engine/join-index.d.ts +0 -10
- package/dist/engine/live-equal.d.ts +0 -7
- package/dist/engine/point-read.d.ts +0 -59
- package/dist/engine/query-cache.d.ts +0 -21
- package/dist/engine/result-wire.d.ts +0 -70
- package/dist/engine/sort-keys.d.ts +0 -73
- package/dist/engine/sql-domains.d.ts +0 -93
- package/dist/engine/sql-functions.d.ts +0 -11
- package/dist/engine/sql-json.d.ts +0 -40
- package/dist/engine/sql-semantics.d.ts +0 -66
- package/dist/engine/worker-store-indexeddb.d.ts +0 -2
- package/dist/engine/worker-store-memory.d.ts +0 -2
- package/dist/engine/worker-store-opfs.d.ts +0 -2
- package/dist/engine/write-block-planner.d.ts +0 -19
- package/dist/storage/opfs/leader.d.ts +0 -460
- package/dist/storage/opfs/rpc.d.ts +0 -82
- package/dist/storage/opfs/snapshot-ledger.d.ts +0 -41
package/dist/engine/query.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { encodeQueryIdentity } from "./query-identity.js";
|
|
2
|
+
import { alreadyExternalResults, copyQueryResultExternalization } from "./result-state.js";
|
|
3
|
+
import { copyQueryResultExternalization as copyQueryResultExternalization2, markQueryResultExternal } from "./result-state.js";
|
|
1
4
|
import { civilFromDays, copyDate, dateIsoString, dateMilliseconds, daysFromCivil, epochDays, dateUtcDate, dateUtcFullYear, dateUtcMonth, setDateUtcDate, setDateUtcMonth } from "../date-value.js";
|
|
2
5
|
import { crossJoinPlan } from "../plan/model.js";
|
|
3
6
|
import { assertWellFormedString, wellFormedUtf8ByteLength } from "../block-format/unicode.js";
|
|
@@ -5,13 +8,14 @@ import { MAX_SQL_NESTING_DEPTH, MAX_SQL_PARAMETERS, MAX_SQL_SCALAR_RESULT_CHARAC
|
|
|
5
8
|
import { SqlCompileError } from "./errors.js";
|
|
6
9
|
import { cachedQueryTerms, ftsBm25Row, FtsStatsAccumulator, ftsMatchTruth, renderDocumentValue, tokenize as ftsTokenize, validateFtsQuery } from "./fts.js";
|
|
7
10
|
import { QueryMemoryContext } from "./memory.js";
|
|
8
|
-
import {
|
|
11
|
+
import { applyWindowFunctions } from "./windows.js";
|
|
12
|
+
import { applyWindowFunctions as applyWindowFunctions2 } from "./windows.js";
|
|
9
13
|
import { coerceComparisonOperands, coercedComparable, parseSqlTimestampText, stringArgument, readUntypedText } from "./sql-semantics.js";
|
|
10
14
|
import { simpleScalarFunctions } from "./sql-functions.js";
|
|
11
15
|
import { jsonArrowStep, jsonAtPath, jsonConstructor, jsonIsValid, parseJsonPath, jsonDocumentOf } from "./sql-json.js";
|
|
12
16
|
import { optimizePlan, rewriteBoundCalendarEqualities } from "./optimizer.js";
|
|
13
17
|
import { compareSqlValues as compareValues, compileLikePattern, compileSimilarPattern, encodeSqlEqualityValue, roundSqlNumber } from "./sql-semantics.js";
|
|
14
|
-
import { arrayDomainValue, boundedJsonText, collatedDomainValue, concatenatedSqlValue, dateDomainValue, exactNumericAsNumber, exactNumericBinary, exactNumericLiteral, decimalScaleOfNumber, exactNumericRounded, exactNumericUnary, exactNumericValue, externalSqlDomainColumnValue, externalSqlDomainValue, intervalDomainValue, isDateDomainValue, isExactNumeric, isSqlDomainValue, jsonDomainValue, normalizeSqlDomainValue, preservedJsonDomainValue, protectedSqlTextValue, timeDomainValue, uuidDomainValue } from "./sql-domains.js";
|
|
18
|
+
import { arrayDomainValue, boundedJsonText, collatedDomainValue, concatenatedSqlValue, dateDomainValue, exactNumericAsNumber, exactNumericBinary, exactNumericLiteral, decimalScaleOfNumber, exactNumericRounded, exactNumericUnary, exactNumericValue, externalSqlDomainColumnValue, externalSqlDomainValue, intervalDomainValue, temporalDomainPart, isDateDomainValue, isExactNumeric, isSqlDomainValue, jsonDomainValue, normalizeSqlDomainValue, preservedJsonDomainValue, protectedSqlTextValue, timeDomainValue, uuidDomainValue } from "./sql-domains.js";
|
|
15
19
|
import { columnarTableFromRows, prepareVectorQuery } from "./vector.js";
|
|
16
20
|
function unknownColumnDomains(columns) {
|
|
17
21
|
return columns.map(() => null);
|
|
@@ -64,6 +68,9 @@ const scalarFunctionNames = /* @__PURE__ */ new Set([
|
|
|
64
68
|
"TO_JSON",
|
|
65
69
|
"IS_JSON",
|
|
66
70
|
"ARRAY",
|
|
71
|
+
"MINNOW_ARRAY_AT",
|
|
72
|
+
"MINNOW_ARRAY_FROM_JSON",
|
|
73
|
+
"MINNOW_ARRAY_ELEMENT",
|
|
67
74
|
"MINNOW_JSON_GET",
|
|
68
75
|
"MINNOW_JSON_GET_TEXT",
|
|
69
76
|
"MINNOW_TUPLE_KEY",
|
|
@@ -90,6 +97,7 @@ const functionSpellings = /* @__PURE__ */ new Map([
|
|
|
90
97
|
["CHAR_LENGTH", "LENGTH"],
|
|
91
98
|
["CHARACTER_LENGTH", "LENGTH"],
|
|
92
99
|
["POW", "POWER"],
|
|
100
|
+
["ARRAY_AGG", "JSON_ARRAYAGG"],
|
|
93
101
|
["JSON_AGG", "JSON_ARRAYAGG"],
|
|
94
102
|
["JSONB_AGG", "JSON_ARRAYAGG"],
|
|
95
103
|
["JSON_BUILD_ARRAY", "JSON_ARRAY"],
|
|
@@ -159,6 +167,12 @@ function castValue(value, target) {
|
|
|
159
167
|
if (value instanceof Date)
|
|
160
168
|
return protectedSqlTextValue(dateIsoString(value));
|
|
161
169
|
}
|
|
170
|
+
if (target === "number-integer" && isExactNumeric(value)) {
|
|
171
|
+
const integer = Number(externalSqlDomainValue(exactNumericRounded(value, 0, "round")));
|
|
172
|
+
if (!Number.isSafeInteger(integer))
|
|
173
|
+
throw new RangeError("Integer cast is outside the exact safe range");
|
|
174
|
+
return integer;
|
|
175
|
+
}
|
|
162
176
|
if (target === "number" || target === "number-integer") {
|
|
163
177
|
const external = externalSqlDomainValue(value);
|
|
164
178
|
let parsed;
|
|
@@ -168,6 +182,9 @@ function castValue(value, target) {
|
|
|
168
182
|
parsed = external ? 1 : 0;
|
|
169
183
|
else if (typeof external === "string") {
|
|
170
184
|
const text = external.trim();
|
|
185
|
+
if (target === "number-integer" && !/^[+-]?\d+$/.test(text)) {
|
|
186
|
+
throw new TypeError(`Cannot cast this string to a number: ${text} (expected integer text)`);
|
|
187
|
+
}
|
|
171
188
|
const candidate = text === "" ? Number.NaN : Number(text);
|
|
172
189
|
if (!Number.isFinite(candidate)) {
|
|
173
190
|
throw new TypeError(`Cannot cast this string to a number: ${text}`);
|
|
@@ -197,10 +214,9 @@ function castValue(value, target) {
|
|
|
197
214
|
if (typeof value === "string") {
|
|
198
215
|
const external = externalSqlDomainValue(value);
|
|
199
216
|
const text = typeof external === "string" ? external.trim().toLowerCase() : "";
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return false;
|
|
217
|
+
const parsed = readUntypedText("boolean", text);
|
|
218
|
+
if (typeof parsed === "boolean")
|
|
219
|
+
return parsed;
|
|
204
220
|
throw new TypeError(`Cannot cast this string to a boolean: ${typeof external === "string" ? external : value}`);
|
|
205
221
|
}
|
|
206
222
|
}
|
|
@@ -344,6 +360,32 @@ function scalarFunctionValueGeneric(name, values) {
|
|
|
344
360
|
}
|
|
345
361
|
if (name === "ARRAY")
|
|
346
362
|
return arrayDomainValue(values);
|
|
363
|
+
if (name === "MINNOW_ARRAY_ELEMENT") {
|
|
364
|
+
const value = externalSqlDomainValue(values[0]);
|
|
365
|
+
return typeof value === "string" ? protectedSqlTextValue(value) : value;
|
|
366
|
+
}
|
|
367
|
+
if (name === "MINNOW_ARRAY_FROM_JSON") {
|
|
368
|
+
if (values[0] === null)
|
|
369
|
+
return null;
|
|
370
|
+
return normalizeSqlDomainValue({ kind: "array", element: "TEXT" }, externalSqlDomainValue(values[0]));
|
|
371
|
+
}
|
|
372
|
+
if (name === "MINNOW_ARRAY_AT") {
|
|
373
|
+
if (values[0] === null || values[1] === null)
|
|
374
|
+
return null;
|
|
375
|
+
const source = externalSqlDomainValue(values[0]);
|
|
376
|
+
const index = values[1];
|
|
377
|
+
if (typeof source !== "string" || typeof index !== "number" || !Number.isSafeInteger(index))
|
|
378
|
+
throw new TypeError("Array subscripts require an array and an integer position");
|
|
379
|
+
const array = JSON.parse(source);
|
|
380
|
+
if (!Array.isArray(array))
|
|
381
|
+
throw new TypeError("Array subscripts require an array");
|
|
382
|
+
const selected = array[index - 1] ?? null;
|
|
383
|
+
if (typeof selected === "string")
|
|
384
|
+
return protectedSqlTextValue(selected);
|
|
385
|
+
if (selected === null || typeof selected === "number" || typeof selected === "boolean")
|
|
386
|
+
return selected;
|
|
387
|
+
throw new TypeError("Array subscripts currently require one-dimensional scalar arrays");
|
|
388
|
+
}
|
|
347
389
|
if (name === "MINNOW_COLLATE")
|
|
348
390
|
return collatedDomainValue(values[0], values[1]);
|
|
349
391
|
if (name === "NEXTVAL" || name === "CURRVAL") {
|
|
@@ -720,7 +762,7 @@ function dateAddValue(value, months, milliseconds) {
|
|
|
720
762
|
setDateUtcDate(shifted, Math.min(day, dateUtcDate(lastDay)));
|
|
721
763
|
}
|
|
722
764
|
const result = new Date(dateMilliseconds(shifted) + millisecondCount);
|
|
723
|
-
return
|
|
765
|
+
return result;
|
|
724
766
|
}
|
|
725
767
|
function dateTruncValue(unit, value) {
|
|
726
768
|
if (typeof unit !== "string" || !dateTruncUnits.has(unit.toLowerCase())) {
|
|
@@ -1902,6 +1944,7 @@ function inferBlockSchema(plan, schemas) {
|
|
|
1902
1944
|
const wildcardSchema = (source) => (schemas.get(source.table) ?? []).filter((column) => !column.name.startsWith("\0")).map((column) => ({
|
|
1903
1945
|
name: multipleSources ? `${source.alias}.${column.name}` : column.name,
|
|
1904
1946
|
type: column.type,
|
|
1947
|
+
...column.unknown === true ? { unknown: true } : {},
|
|
1905
1948
|
...column.integer === true ? { integer: true } : {},
|
|
1906
1949
|
...column.sqlDomain === void 0 ? {} : { sqlDomain: column.sqlDomain }
|
|
1907
1950
|
}));
|
|
@@ -1916,9 +1959,9 @@ function inferBlockSchema(plan, schemas) {
|
|
|
1916
1959
|
const column = (schemas.get(source.table) ?? []).find(({ name }) => name === parts[1]);
|
|
1917
1960
|
if (column === void 0)
|
|
1918
1961
|
throw new TypeError(`Unknown column: ${reference}`);
|
|
1919
|
-
return column.type;
|
|
1962
|
+
return column.unknown === true ? "null" : column.type;
|
|
1920
1963
|
}
|
|
1921
|
-
const matches = sources.flatMap((source) => (schemas.get(source.table) ?? []).filter(({ name }) => name === parts[0]).map((column) => column.type));
|
|
1964
|
+
const matches = sources.flatMap((source) => (schemas.get(source.table) ?? []).filter(({ name }) => name === parts[0]).map((column) => column.unknown === true ? "null" : column.type));
|
|
1922
1965
|
if (matches.length !== 1)
|
|
1923
1966
|
throw new TypeError(`Ambiguous or missing column: ${reference}`);
|
|
1924
1967
|
return matches[0] ?? "string";
|
|
@@ -2007,6 +2050,16 @@ function inferBlockSchema(plan, schemas) {
|
|
|
2007
2050
|
return void 0;
|
|
2008
2051
|
if (expression.name === "CURRENT_DATE")
|
|
2009
2052
|
return { kind: "date" };
|
|
2053
|
+
if (expression.name === "ARRAY" || expression.name === "MINNOW_ARRAY_FROM_JSON") {
|
|
2054
|
+
let argument = expression.name === "ARRAY" ? expression.arguments[0] : expression.arguments[0]?.kind === "call" ? expression.arguments[0].arguments[0] : void 0;
|
|
2055
|
+
if (argument?.kind === "call" && argument.name === "MINNOW_ARRAY_ELEMENT")
|
|
2056
|
+
argument = argument.arguments[0];
|
|
2057
|
+
const type = argument === void 0 ? "string" : infer(argument);
|
|
2058
|
+
return {
|
|
2059
|
+
kind: "array",
|
|
2060
|
+
element: type === "number" ? "DOUBLE" : type === "boolean" ? "BOOLEAN" : type === "datetime" ? "TIMESTAMP" : "TEXT"
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2010
2063
|
const simple = simpleScalarFunctions.get(expression.name);
|
|
2011
2064
|
if (simple?.returns === "date")
|
|
2012
2065
|
return { kind: "date" };
|
|
@@ -2040,11 +2093,8 @@ function inferBlockSchema(plan, schemas) {
|
|
|
2040
2093
|
const sides = expression.arguments.map((argument) => [argument, inferDomain(argument)]);
|
|
2041
2094
|
return sides.some(([, domain]) => domain?.kind === "numeric") ? numericResultDomain("%", sides) : void 0;
|
|
2042
2095
|
}
|
|
2043
|
-
if (expression.name === "DATE_ADD")
|
|
2044
|
-
|
|
2045
|
-
const milliseconds = expression.arguments[2];
|
|
2046
|
-
return input?.kind === "date" && milliseconds?.kind === "literal" && typeof milliseconds.value === "number" && milliseconds.value % 864e5 === 0 ? input : void 0;
|
|
2047
|
-
}
|
|
2096
|
+
if (expression.name === "DATE_ADD")
|
|
2097
|
+
return void 0;
|
|
2048
2098
|
if (expression.name === "SUM" || expression.name === "AVG" || expression.name === "MIN" || expression.name === "MAX" || expression.name === "MINNOW_SINGLE_VALUE" || expression.name === "COALESCE" || expression.name === "NULLIF" || expression.name === "GREATEST" || expression.name === "LEAST") {
|
|
2049
2099
|
return expression.arguments.map(inferDomain).find((domain) => domain !== void 0);
|
|
2050
2100
|
}
|
|
@@ -2143,7 +2193,12 @@ function inferBlockSchema(plan, schemas) {
|
|
|
2143
2193
|
if (expression.name === "LENGTH" || expression.name === "POWER" || expression.name === "SQRT" || expression.name === "INSTR" || expression.name === "EXTRACT" || expression.name === "OCTET_LENGTH" || expression.name === "GROUPING" || expression.name === "NEXTVAL" || expression.name === "CURRVAL" || expression.name === "RANDOM") {
|
|
2144
2194
|
return "number";
|
|
2145
2195
|
}
|
|
2146
|
-
if (expression.name === "
|
|
2196
|
+
if (expression.name === "MINNOW_ARRAY_AT") {
|
|
2197
|
+
const argument2 = expression.arguments[0];
|
|
2198
|
+
const domain = argument2 === void 0 ? void 0 : inferDomain(argument2);
|
|
2199
|
+
return domain?.kind === "array" ? createTableTypeNames.get(domain.element.toUpperCase()) ?? "string" : "string";
|
|
2200
|
+
}
|
|
2201
|
+
if (expression.name === "MINNOW_ARRAY_FROM_JSON" || expression.name === "JSON_ARRAYAGG" || expression.name === "STRING_AGG" || expression.name === "JSON_VALUE" || expression.name === "JSON_QUERY" || expression.name === "JSON_OBJECT" || expression.name === "JSON_ARRAY" || expression.name === "TO_JSON" || expression.name === "ARRAY" || expression.name === "MINNOW_JSON_GET" || expression.name === "MINNOW_JSON_GET_TEXT" || expression.name === "MINNOW_TUPLE_KEY" || expression.name === "MINNOW_COLLATE" || expression.name === "GEN_RANDOM_UUID") {
|
|
2147
2202
|
return "string";
|
|
2148
2203
|
}
|
|
2149
2204
|
if (expression.name === "JSON_EXISTS" || expression.name === "IS_JSON")
|
|
@@ -2161,9 +2216,8 @@ function inferBlockSchema(plan, schemas) {
|
|
|
2161
2216
|
}
|
|
2162
2217
|
if (expression.name === "DATE_TRUNC")
|
|
2163
2218
|
return "datetime";
|
|
2164
|
-
if (expression.name === "DATE_ADD")
|
|
2165
|
-
return
|
|
2166
|
-
}
|
|
2219
|
+
if (expression.name === "DATE_ADD")
|
|
2220
|
+
return "datetime";
|
|
2167
2221
|
if (expression.name === "CURRENT_DATE")
|
|
2168
2222
|
return "string";
|
|
2169
2223
|
if (expression.name === "CURRENT_TIMESTAMP")
|
|
@@ -2238,9 +2292,8 @@ function inferBlockSchema(plan, schemas) {
|
|
|
2238
2292
|
return wildcardSchema(source);
|
|
2239
2293
|
}
|
|
2240
2294
|
const type = infer(item.expression);
|
|
2241
|
-
if (type === "null")
|
|
2242
|
-
|
|
2243
|
-
}
|
|
2295
|
+
if (type === "null")
|
|
2296
|
+
return [{ name: item.alias, type: "string", unknown: true }];
|
|
2244
2297
|
const integer = integerTypedExpression(item.expression, resolveColumnInteger);
|
|
2245
2298
|
const sqlDomain = inferDomain(item.expression);
|
|
2246
2299
|
return [
|
|
@@ -2974,22 +3027,29 @@ function planMayHaveIntegerDivision(plan) {
|
|
|
2974
3027
|
return state.found;
|
|
2975
3028
|
}
|
|
2976
3029
|
function foldIdentifierCase(plan, tables) {
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
bucket.
|
|
2985
|
-
|
|
3030
|
+
let lowerTables;
|
|
3031
|
+
const caseInsensitiveTables = () => {
|
|
3032
|
+
if (lowerTables !== void 0)
|
|
3033
|
+
return lowerTables;
|
|
3034
|
+
const indexed = /* @__PURE__ */ new Map();
|
|
3035
|
+
for (const name of tables.keys()) {
|
|
3036
|
+
const lowered = name.toLowerCase();
|
|
3037
|
+
const bucket = indexed.get(lowered);
|
|
3038
|
+
if (bucket === void 0)
|
|
3039
|
+
indexed.set(lowered, [name]);
|
|
3040
|
+
else
|
|
3041
|
+
bucket.push(name);
|
|
3042
|
+
}
|
|
3043
|
+
lowerTables = indexed;
|
|
3044
|
+
return indexed;
|
|
3045
|
+
};
|
|
2986
3046
|
const foldTable = (name) => {
|
|
2987
3047
|
if (tables.has(name))
|
|
2988
3048
|
return void 0;
|
|
2989
3049
|
const lowered = name.toLowerCase();
|
|
2990
3050
|
if (tables.has(lowered))
|
|
2991
3051
|
return lowered;
|
|
2992
|
-
const candidates =
|
|
3052
|
+
const candidates = caseInsensitiveTables().get(lowered);
|
|
2993
3053
|
return candidates?.length === 1 ? candidates[0] : void 0;
|
|
2994
3054
|
};
|
|
2995
3055
|
const foldColumn = (columns, name) => {
|
|
@@ -3127,16 +3187,7 @@ function expandRowReferences(plan, tableColumns) {
|
|
|
3127
3187
|
const sourceColumns = (source) => {
|
|
3128
3188
|
if (source.columnAliases !== void 0)
|
|
3129
3189
|
return source.columnAliases;
|
|
3130
|
-
|
|
3131
|
-
return source.derived.select.map((item) => item.alias);
|
|
3132
|
-
if (source.union !== void 0) {
|
|
3133
|
-
return source.union.blocks[0]?.select.map((item) => item.alias) ?? [];
|
|
3134
|
-
}
|
|
3135
|
-
if (source.windowed !== void 0)
|
|
3136
|
-
return source.windowed.block.select.map((item) => item.alias);
|
|
3137
|
-
if (source.recursive !== void 0)
|
|
3138
|
-
return [];
|
|
3139
|
-
return tableColumns(source.table) ?? [];
|
|
3190
|
+
return sourceWildcardColumns(source, tableColumns) ?? [];
|
|
3140
3191
|
};
|
|
3141
3192
|
const rewriteBlock = (block) => {
|
|
3142
3193
|
if (pass.probing && pass.needed)
|
|
@@ -3483,6 +3534,26 @@ function exactConstantFold(expression) {
|
|
|
3483
3534
|
return folded === void 0 ? void 0 : { value: folded, seeded };
|
|
3484
3535
|
}
|
|
3485
3536
|
function resolveExactNumericConstants(expression) {
|
|
3537
|
+
if (expression.kind === "call" && expression.name === "CAST") {
|
|
3538
|
+
const [source, target] = expression.arguments;
|
|
3539
|
+
if (source !== void 0 && target?.kind === "literal" && target.value === "number-integer") {
|
|
3540
|
+
const exact = exactConstantFold(source);
|
|
3541
|
+
if (exact?.seeded === true && exact.value !== null) {
|
|
3542
|
+
return {
|
|
3543
|
+
...expression,
|
|
3544
|
+
arguments: [
|
|
3545
|
+
{
|
|
3546
|
+
kind: "literal",
|
|
3547
|
+
value: exactNumericValue(exact.value),
|
|
3548
|
+
internalSqlValue: true,
|
|
3549
|
+
sqlDomain: { kind: "numeric" }
|
|
3550
|
+
},
|
|
3551
|
+
target
|
|
3552
|
+
]
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3486
3557
|
let folded;
|
|
3487
3558
|
try {
|
|
3488
3559
|
folded = exactConstantFold(expression);
|
|
@@ -3578,296 +3649,6 @@ function resolveStatementExactNumericConstants(statement) {
|
|
|
3578
3649
|
}
|
|
3579
3650
|
}
|
|
3580
3651
|
}
|
|
3581
|
-
function aggregateWindowMembers(window, values, members, avgScale) {
|
|
3582
|
-
const present = members.filter((member) => {
|
|
3583
|
-
const value = values[member];
|
|
3584
|
-
return value !== null && value !== void 0;
|
|
3585
|
-
});
|
|
3586
|
-
if (window.name === "COUNT") {
|
|
3587
|
-
return window.argumentAlias === void 0 ? members.length : present.length;
|
|
3588
|
-
}
|
|
3589
|
-
if (window.name === "FIRST_VALUE")
|
|
3590
|
-
return values[members[0] ?? -1] ?? null;
|
|
3591
|
-
if (window.name === "LAST_VALUE")
|
|
3592
|
-
return values[members[members.length - 1] ?? -1] ?? null;
|
|
3593
|
-
if (window.name === "NTH_VALUE")
|
|
3594
|
-
return values[members[(window.offset ?? 1) - 1] ?? -1] ?? null;
|
|
3595
|
-
if (present.length === 0)
|
|
3596
|
-
return null;
|
|
3597
|
-
if (window.name === "SUM" || window.name === "AVG") {
|
|
3598
|
-
const exact = present.some((member) => isExactNumeric(values[member]));
|
|
3599
|
-
if (exact) {
|
|
3600
|
-
let total2 = exactNumericValue(0);
|
|
3601
|
-
for (const member of present) {
|
|
3602
|
-
const value = values[member];
|
|
3603
|
-
if (!isExactNumeric(value)) {
|
|
3604
|
-
throw new TypeError("Exact NUMERIC window input mixed with an approximate number");
|
|
3605
|
-
}
|
|
3606
|
-
const next = exactNumericBinary("+", total2, value);
|
|
3607
|
-
if (next === null || next === void 0)
|
|
3608
|
-
throw new Error("Exact NUMERIC sum disappeared");
|
|
3609
|
-
total2 = next;
|
|
3610
|
-
}
|
|
3611
|
-
return window.name === "SUM" ? total2 : exactNumericBinary("/", total2, present.length, avgScale);
|
|
3612
|
-
}
|
|
3613
|
-
const total = present.reduce((sum, member) => sum + numeric(values[member]), 0);
|
|
3614
|
-
return window.name === "SUM" ? total : total / present.length;
|
|
3615
|
-
}
|
|
3616
|
-
let best;
|
|
3617
|
-
for (const member of present) {
|
|
3618
|
-
const candidate = values[member];
|
|
3619
|
-
if (best === void 0 || (window.name === "MIN" ? compareValues(candidate, best) < 0 : compareValues(candidate, best) > 0)) {
|
|
3620
|
-
best = candidate;
|
|
3621
|
-
}
|
|
3622
|
-
}
|
|
3623
|
-
return best ?? null;
|
|
3624
|
-
}
|
|
3625
|
-
function applyAggregateWindow(rows, indexes, window, samePartition, sameOrderKeys, avgScale) {
|
|
3626
|
-
const frame = window.frame ?? {
|
|
3627
|
-
unit: "range",
|
|
3628
|
-
start: { kind: "unbounded-preceding" },
|
|
3629
|
-
end: window.orderAliases.length === 0 ? { kind: "unbounded-following" } : { kind: "current-row" }
|
|
3630
|
-
};
|
|
3631
|
-
let start = 0;
|
|
3632
|
-
while (start < indexes.length) {
|
|
3633
|
-
let end = start + 1;
|
|
3634
|
-
while (end < indexes.length && samePartition(indexes[start] ?? 0, indexes[end] ?? 0)) {
|
|
3635
|
-
end += 1;
|
|
3636
|
-
}
|
|
3637
|
-
applyAggregateWindowPartition(rows, indexes, window, frame, sameOrderKeys, start, end, avgScale);
|
|
3638
|
-
start = end;
|
|
3639
|
-
}
|
|
3640
|
-
}
|
|
3641
|
-
function applyAggregateWindowPartition(rows, indexes, window, frame, sameOrderKeys, start, end, avgScale) {
|
|
3642
|
-
const size = end - start;
|
|
3643
|
-
const peerStart = new Array(size).fill(0);
|
|
3644
|
-
const peerEnd = new Array(size).fill(size);
|
|
3645
|
-
if (window.orderAliases.length > 0) {
|
|
3646
|
-
let groupBegin = 0;
|
|
3647
|
-
for (let position = 1; position <= size; position += 1) {
|
|
3648
|
-
if (position === size || !sameOrderKeys(indexes[start + groupBegin] ?? 0, indexes[start + position] ?? 0)) {
|
|
3649
|
-
for (let member = groupBegin; member < position; member += 1) {
|
|
3650
|
-
peerStart[member] = groupBegin;
|
|
3651
|
-
peerEnd[member] = position;
|
|
3652
|
-
}
|
|
3653
|
-
groupBegin = position;
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
}
|
|
3657
|
-
const values = [];
|
|
3658
|
-
const sums = window.name === "SUM" || window.name === "AVG";
|
|
3659
|
-
for (let position = 0; position < size; position += 1) {
|
|
3660
|
-
const value = window.argumentAlias === void 0 ? void 0 : rows[indexes[start + position] ?? -1]?.[window.argumentAlias] ?? null;
|
|
3661
|
-
values.push(value);
|
|
3662
|
-
}
|
|
3663
|
-
const exactSums = sums && values.some((value) => isExactNumeric(value));
|
|
3664
|
-
const prefixNonNull = new Float64Array(size + 1);
|
|
3665
|
-
const prefixSum = exactSums ? void 0 : new Float64Array(size + 1);
|
|
3666
|
-
const prefixExact = exactSums ? new Array(size + 1) : void 0;
|
|
3667
|
-
const exactZero = exactNumericValue(0);
|
|
3668
|
-
if (exactZero === null)
|
|
3669
|
-
throw new Error("Exact NUMERIC zero disappeared");
|
|
3670
|
-
if (prefixExact !== void 0)
|
|
3671
|
-
prefixExact[0] = exactZero;
|
|
3672
|
-
for (let position = 0; position < size; position += 1) {
|
|
3673
|
-
const value = values[position];
|
|
3674
|
-
const nonNull = window.argumentAlias !== void 0 && value !== null && value !== void 0;
|
|
3675
|
-
prefixNonNull[position + 1] = (prefixNonNull[position] ?? 0) + (nonNull ? 1 : 0);
|
|
3676
|
-
if (prefixExact !== void 0) {
|
|
3677
|
-
if (nonNull && !isExactNumeric(value)) {
|
|
3678
|
-
throw new TypeError("Exact NUMERIC window input mixed with an approximate number");
|
|
3679
|
-
}
|
|
3680
|
-
const previous = prefixExact[position] ?? exactZero;
|
|
3681
|
-
const next = nonNull ? exactNumericBinary("+", previous, value) : previous;
|
|
3682
|
-
if (next === null || next === void 0)
|
|
3683
|
-
throw new Error("Exact NUMERIC sum disappeared");
|
|
3684
|
-
prefixExact[position + 1] = next;
|
|
3685
|
-
} else if (prefixSum !== void 0) {
|
|
3686
|
-
prefixSum[position + 1] = (prefixSum[position] ?? 0) + (sums && nonNull ? numeric(value) : 0);
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3689
|
-
const groupOrdinal = new Array(size).fill(0);
|
|
3690
|
-
const groupStarts = [];
|
|
3691
|
-
if (frame.unit === "groups") {
|
|
3692
|
-
for (let position = 0; position < size; position += 1) {
|
|
3693
|
-
if (position === 0 || peerStart[position] !== peerStart[position - 1]) {
|
|
3694
|
-
groupStarts.push(peerStart[position] ?? position);
|
|
3695
|
-
}
|
|
3696
|
-
groupOrdinal[position] = groupStarts.length - 1;
|
|
3697
|
-
}
|
|
3698
|
-
}
|
|
3699
|
-
const groupEdge = (ordinal, isStart) => {
|
|
3700
|
-
if (ordinal < 0)
|
|
3701
|
-
return isStart ? 0 : 0;
|
|
3702
|
-
if (ordinal >= groupStarts.length)
|
|
3703
|
-
return size;
|
|
3704
|
-
return isStart ? groupStarts[ordinal] ?? 0 : groupStarts[ordinal + 1] ?? size;
|
|
3705
|
-
};
|
|
3706
|
-
const bound = (edge, position, isStart) => {
|
|
3707
|
-
switch (edge.kind) {
|
|
3708
|
-
case "unbounded-preceding":
|
|
3709
|
-
return 0;
|
|
3710
|
-
case "unbounded-following":
|
|
3711
|
-
return size;
|
|
3712
|
-
case "preceding":
|
|
3713
|
-
if (frame.unit === "groups") {
|
|
3714
|
-
return groupEdge((groupOrdinal[position] ?? 0) - (edge.offset ?? 0), isStart);
|
|
3715
|
-
}
|
|
3716
|
-
return position - (edge.offset ?? 0) + (isStart ? 0 : 1);
|
|
3717
|
-
case "following":
|
|
3718
|
-
if (frame.unit === "groups") {
|
|
3719
|
-
return groupEdge((groupOrdinal[position] ?? 0) + (edge.offset ?? 0), isStart);
|
|
3720
|
-
}
|
|
3721
|
-
return position + (edge.offset ?? 0) + (isStart ? 0 : 1);
|
|
3722
|
-
case "current-row":
|
|
3723
|
-
if (frame.unit === "range" || frame.unit === "groups") {
|
|
3724
|
-
return (isStart ? peerStart[position] : peerEnd[position]) ?? position;
|
|
3725
|
-
}
|
|
3726
|
-
return position + (isStart ? 0 : 1);
|
|
3727
|
-
}
|
|
3728
|
-
};
|
|
3729
|
-
const excluded = (position) => {
|
|
3730
|
-
switch (frame.exclude) {
|
|
3731
|
-
case "current-row":
|
|
3732
|
-
return { from: position, to: position + 1, keepCurrent: false };
|
|
3733
|
-
case "group":
|
|
3734
|
-
return {
|
|
3735
|
-
from: peerStart[position] ?? position,
|
|
3736
|
-
to: peerEnd[position] ?? position + 1,
|
|
3737
|
-
keepCurrent: false
|
|
3738
|
-
};
|
|
3739
|
-
case "ties":
|
|
3740
|
-
return {
|
|
3741
|
-
from: peerStart[position] ?? position,
|
|
3742
|
-
to: peerEnd[position] ?? position + 1,
|
|
3743
|
-
keepCurrent: true
|
|
3744
|
-
};
|
|
3745
|
-
default:
|
|
3746
|
-
return { from: 0, to: 0, keepCurrent: true };
|
|
3747
|
-
}
|
|
3748
|
-
};
|
|
3749
|
-
for (let position = 0; position < size; position += 1) {
|
|
3750
|
-
const low = Math.max(0, Math.min(size, bound(frame.start, position, true)));
|
|
3751
|
-
const high = Math.max(0, Math.min(size, bound(frame.end, position, false)));
|
|
3752
|
-
let value;
|
|
3753
|
-
if (frame.exclude !== void 0) {
|
|
3754
|
-
const skip = excluded(position);
|
|
3755
|
-
const members = [];
|
|
3756
|
-
for (let member = low; member < high; member += 1) {
|
|
3757
|
-
const dropped = member >= skip.from && member < skip.to && !(skip.keepCurrent && member === position);
|
|
3758
|
-
if (!dropped)
|
|
3759
|
-
members.push(member);
|
|
3760
|
-
}
|
|
3761
|
-
value = aggregateWindowMembers(window, values, members, avgScale);
|
|
3762
|
-
const row2 = rows[indexes[start + position] ?? -1];
|
|
3763
|
-
if (row2 !== void 0)
|
|
3764
|
-
row2[window.alias] = asQueryValue(value);
|
|
3765
|
-
continue;
|
|
3766
|
-
}
|
|
3767
|
-
if (high <= low) {
|
|
3768
|
-
value = window.name === "COUNT" ? 0 : null;
|
|
3769
|
-
} else if (window.name === "FIRST_VALUE") {
|
|
3770
|
-
value = values[low] ?? null;
|
|
3771
|
-
} else if (window.name === "NTH_VALUE") {
|
|
3772
|
-
const position2 = low + (window.offset ?? 1) - 1;
|
|
3773
|
-
value = position2 < high ? values[position2] ?? null : null;
|
|
3774
|
-
} else if (window.name === "LAST_VALUE") {
|
|
3775
|
-
value = values[high - 1] ?? null;
|
|
3776
|
-
} else if (window.name === "COUNT") {
|
|
3777
|
-
value = window.argumentAlias === void 0 ? high - low : (prefixNonNull[high] ?? 0) - (prefixNonNull[low] ?? 0);
|
|
3778
|
-
} else if (sums) {
|
|
3779
|
-
const nonNull = (prefixNonNull[high] ?? 0) - (prefixNonNull[low] ?? 0);
|
|
3780
|
-
if (nonNull === 0) {
|
|
3781
|
-
value = null;
|
|
3782
|
-
} else if (prefixExact !== void 0) {
|
|
3783
|
-
const total = exactNumericBinary("-", prefixExact[high] ?? exactZero, prefixExact[low] ?? exactZero);
|
|
3784
|
-
value = window.name === "SUM" ? total : exactNumericBinary("/", total, nonNull, avgScale);
|
|
3785
|
-
} else {
|
|
3786
|
-
const total = (prefixSum?.[high] ?? 0) - (prefixSum?.[low] ?? 0);
|
|
3787
|
-
value = window.name === "SUM" ? total : total / nonNull;
|
|
3788
|
-
}
|
|
3789
|
-
} else {
|
|
3790
|
-
let best;
|
|
3791
|
-
for (let member = low; member < high; member += 1) {
|
|
3792
|
-
const candidate = values[member];
|
|
3793
|
-
if (candidate === null || candidate === void 0)
|
|
3794
|
-
continue;
|
|
3795
|
-
if (best === void 0 || (window.name === "MIN" ? compareValues(candidate, best) < 0 : compareValues(candidate, best) > 0)) {
|
|
3796
|
-
best = candidate;
|
|
3797
|
-
}
|
|
3798
|
-
}
|
|
3799
|
-
value = best ?? null;
|
|
3800
|
-
}
|
|
3801
|
-
const row = rows[indexes[start + position] ?? -1];
|
|
3802
|
-
if (row !== void 0)
|
|
3803
|
-
row[window.alias] = asQueryValue(value);
|
|
3804
|
-
}
|
|
3805
|
-
}
|
|
3806
|
-
function applyDistributionWindow(rows, indexes, window, samePartition, sameOrderKeys) {
|
|
3807
|
-
let start = 0;
|
|
3808
|
-
while (start < indexes.length) {
|
|
3809
|
-
let end = start + 1;
|
|
3810
|
-
while (end < indexes.length && samePartition(indexes[start] ?? 0, indexes[end] ?? 0)) {
|
|
3811
|
-
end += 1;
|
|
3812
|
-
}
|
|
3813
|
-
const size = end - start;
|
|
3814
|
-
let groupBegin = 0;
|
|
3815
|
-
const assign = (position, value) => {
|
|
3816
|
-
const row = rows[indexes[start + position] ?? -1];
|
|
3817
|
-
if (row !== void 0)
|
|
3818
|
-
row[window.alias] = value;
|
|
3819
|
-
};
|
|
3820
|
-
for (let position = 1; position <= size; position += 1) {
|
|
3821
|
-
if (position === size || !sameOrderKeys(indexes[start + groupBegin] ?? 0, indexes[start + position] ?? 0)) {
|
|
3822
|
-
for (let member = groupBegin; member < position; member += 1) {
|
|
3823
|
-
if (window.name === "PERCENT_RANK") {
|
|
3824
|
-
assign(member, size === 1 ? 0 : groupBegin / (size - 1));
|
|
3825
|
-
} else if (window.name === "CUME_DIST") {
|
|
3826
|
-
assign(member, position / size);
|
|
3827
|
-
}
|
|
3828
|
-
}
|
|
3829
|
-
groupBegin = position;
|
|
3830
|
-
}
|
|
3831
|
-
}
|
|
3832
|
-
if (window.name === "NTILE") {
|
|
3833
|
-
const buckets = window.offset ?? 1;
|
|
3834
|
-
const bucketSize = Math.floor(size / buckets);
|
|
3835
|
-
const remainder = size % buckets;
|
|
3836
|
-
let position = 0;
|
|
3837
|
-
for (let bucket = 1; bucket <= buckets && position < size; bucket += 1) {
|
|
3838
|
-
const width = bucketSize + (bucket <= remainder ? 1 : 0);
|
|
3839
|
-
for (let member = 0; member < width && position < size; member += 1, position += 1) {
|
|
3840
|
-
assign(position, bucket);
|
|
3841
|
-
}
|
|
3842
|
-
}
|
|
3843
|
-
}
|
|
3844
|
-
start = end;
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
function applyOffsetWindow(rows, indexes, window, samePartition) {
|
|
3848
|
-
const offset = window.offset ?? 1;
|
|
3849
|
-
const fallback = window.fallback ?? null;
|
|
3850
|
-
let start = 0;
|
|
3851
|
-
while (start < indexes.length) {
|
|
3852
|
-
let end = start + 1;
|
|
3853
|
-
while (end < indexes.length && samePartition(indexes[start] ?? 0, indexes[end] ?? 0)) {
|
|
3854
|
-
end += 1;
|
|
3855
|
-
}
|
|
3856
|
-
for (let position = start; position < end; position += 1) {
|
|
3857
|
-
const source = window.name === "LAG" ? position - offset : position + offset;
|
|
3858
|
-
const row = rows[indexes[position] ?? -1];
|
|
3859
|
-
if (row === void 0)
|
|
3860
|
-
continue;
|
|
3861
|
-
if (source < start || source >= end) {
|
|
3862
|
-
row[window.alias] = fallback;
|
|
3863
|
-
continue;
|
|
3864
|
-
}
|
|
3865
|
-
const sourceRow = rows[indexes[source] ?? -1];
|
|
3866
|
-
row[window.alias] = window.argumentAlias === void 0 ? fallback : sourceRow?.[window.argumentAlias] ?? null;
|
|
3867
|
-
}
|
|
3868
|
-
start = end;
|
|
3869
|
-
}
|
|
3870
|
-
}
|
|
3871
3652
|
function containsDistinctCount(expression) {
|
|
3872
3653
|
if (expression.kind === "call" && expression.distinct === true)
|
|
3873
3654
|
return true;
|
|
@@ -3888,75 +3669,6 @@ function containsFtsExpression(expression) {
|
|
|
3888
3669
|
return true;
|
|
3889
3670
|
return childExpressions(expression).some(containsFtsExpression);
|
|
3890
3671
|
}
|
|
3891
|
-
function applyWindowFunctions(result, windows, options = {}) {
|
|
3892
|
-
const rows = options.copyRows === false ? result.rows : result.rows.map((row) => ({ ...row }));
|
|
3893
|
-
for (const window of windows) {
|
|
3894
|
-
const partitionKeys = window.partitionAliases.map((alias) => rows.map((row) => comparable(row[alias] ?? null)));
|
|
3895
|
-
const orderKeys = window.orderAliases.map(({ alias }) => rows.map((row) => comparable(row[alias] ?? null)));
|
|
3896
|
-
const partitionColumns = partitionKeys.map((keys) => buildSortKeyColumn(keys.length, (index) => keys[index]));
|
|
3897
|
-
const orderColumns = orderKeys.map((keys) => buildSortKeyColumn(keys.length, (index) => keys[index]));
|
|
3898
|
-
const indexes = sortKeyIndexes(rows.length, [
|
|
3899
|
-
...partitionColumns.map((column) => ({ column, descending: false, nulls: void 0 })),
|
|
3900
|
-
...orderColumns.map((column, index) => {
|
|
3901
|
-
const term = window.orderAliases[index];
|
|
3902
|
-
return { column, descending: term?.direction === "desc", nulls: term?.nulls };
|
|
3903
|
-
})
|
|
3904
|
-
]);
|
|
3905
|
-
const samePartition = (left, right) => {
|
|
3906
|
-
for (const column of partitionColumns) {
|
|
3907
|
-
if (column.compare(left, right) !== 0)
|
|
3908
|
-
return false;
|
|
3909
|
-
}
|
|
3910
|
-
return true;
|
|
3911
|
-
};
|
|
3912
|
-
const sameOrderKeys = (left, right) => {
|
|
3913
|
-
for (const column of orderColumns) {
|
|
3914
|
-
if (column.compare(left, right) !== 0)
|
|
3915
|
-
return false;
|
|
3916
|
-
}
|
|
3917
|
-
return true;
|
|
3918
|
-
};
|
|
3919
|
-
if (window.name === "LAG" || window.name === "LEAD") {
|
|
3920
|
-
applyOffsetWindow(rows, indexes, window, samePartition);
|
|
3921
|
-
continue;
|
|
3922
|
-
}
|
|
3923
|
-
if (window.name === "NTILE" || window.name === "PERCENT_RANK" || window.name === "CUME_DIST") {
|
|
3924
|
-
applyDistributionWindow(rows, indexes, window, samePartition, sameOrderKeys);
|
|
3925
|
-
continue;
|
|
3926
|
-
}
|
|
3927
|
-
if (window.name !== "ROW_NUMBER" && window.name !== "RANK" && window.name !== "DENSE_RANK") {
|
|
3928
|
-
const argumentDomain = window.name === "AVG" && window.argumentAlias !== void 0 ? result.columnDomains[result.columns.indexOf(window.argumentAlias)] : void 0;
|
|
3929
|
-
applyAggregateWindow(rows, indexes, window, samePartition, sameOrderKeys, argumentDomain?.kind === "numeric" ? argumentDomain.scale : void 0);
|
|
3930
|
-
continue;
|
|
3931
|
-
}
|
|
3932
|
-
let rowNumber = 0;
|
|
3933
|
-
let rank = 0;
|
|
3934
|
-
let denseRank = 0;
|
|
3935
|
-
for (const [position, index] of indexes.entries()) {
|
|
3936
|
-
const previous = position > 0 ? indexes[position - 1] : void 0;
|
|
3937
|
-
if (previous === void 0 || !samePartition(previous, index)) {
|
|
3938
|
-
rowNumber = 1;
|
|
3939
|
-
rank = 1;
|
|
3940
|
-
denseRank = 1;
|
|
3941
|
-
} else {
|
|
3942
|
-
rowNumber += 1;
|
|
3943
|
-
if (!sameOrderKeys(previous, index)) {
|
|
3944
|
-
rank = rowNumber;
|
|
3945
|
-
denseRank += 1;
|
|
3946
|
-
}
|
|
3947
|
-
}
|
|
3948
|
-
const row = rows[index];
|
|
3949
|
-
if (row === void 0)
|
|
3950
|
-
continue;
|
|
3951
|
-
row[window.alias] = window.name === "ROW_NUMBER" ? rowNumber : window.name === "RANK" ? rank : denseRank;
|
|
3952
|
-
}
|
|
3953
|
-
}
|
|
3954
|
-
return {
|
|
3955
|
-
columns: [...result.columns, ...windows.map((window) => window.alias)],
|
|
3956
|
-
columnDomains: [...result.columnDomains, ...windows.map(() => null)],
|
|
3957
|
-
rows
|
|
3958
|
-
};
|
|
3959
|
-
}
|
|
3960
3672
|
function resolveDerivedRowTables(plan, tables, memory) {
|
|
3961
3673
|
const sources = [plan.base, ...plan.joins];
|
|
3962
3674
|
const needsDual = sources.some((source) => source.derived === void 0 && source.table === DUAL_TABLE);
|
|
@@ -4541,6 +4253,9 @@ function extractDatePart(field, value) {
|
|
|
4541
4253
|
}
|
|
4542
4254
|
if (value === null || value === void 0)
|
|
4543
4255
|
return null;
|
|
4256
|
+
const domainPart = temporalDomainPart(normalized, value);
|
|
4257
|
+
if (domainPart !== void 0)
|
|
4258
|
+
return domainPart;
|
|
4544
4259
|
let milliseconds;
|
|
4545
4260
|
if (value instanceof Date)
|
|
4546
4261
|
milliseconds = dateMilliseconds(value);
|
|
@@ -4563,7 +4278,7 @@ function extractDatePart(field, value) {
|
|
|
4563
4278
|
case "minute":
|
|
4564
4279
|
return Math.floor(timeOfDay / 6e4) % 60;
|
|
4565
4280
|
case "second":
|
|
4566
|
-
return
|
|
4281
|
+
return timeOfDay % 6e4 / 1e3;
|
|
4567
4282
|
case "milliseconds":
|
|
4568
4283
|
return timeOfDay % 6e4;
|
|
4569
4284
|
case "microseconds":
|
|
@@ -4863,7 +4578,7 @@ function isAggregateCall(expression) {
|
|
|
4863
4578
|
return expression.kind === "call" && aggregateNames.has(expression.name);
|
|
4864
4579
|
}
|
|
4865
4580
|
function groupedExpression(expression, grouped) {
|
|
4866
|
-
if (grouped.has(
|
|
4581
|
+
if (grouped.has(encodeQueryIdentity(expression)))
|
|
4867
4582
|
return true;
|
|
4868
4583
|
if (expression.kind === "column" || containsFtsExpression(expression))
|
|
4869
4584
|
return false;
|
|
@@ -4876,7 +4591,7 @@ function validateGrouping(plan) {
|
|
|
4876
4591
|
const grouped = plan.groupBy.length > 0 || plan.select.some((item) => hasAggregate(item.expression));
|
|
4877
4592
|
if (!grouped)
|
|
4878
4593
|
return;
|
|
4879
|
-
const groupExpressions = new Set(plan.groupBy.map((expression) =>
|
|
4594
|
+
const groupExpressions = new Set(plan.groupBy.map((expression) => encodeQueryIdentity(expression)));
|
|
4880
4595
|
for (const item of plan.select) {
|
|
4881
4596
|
if (hasAggregate(item.expression))
|
|
4882
4597
|
continue;
|
|
@@ -4961,17 +4676,11 @@ function asQueryValue(value) {
|
|
|
4961
4676
|
return null;
|
|
4962
4677
|
throw new TypeError("Query produced an unsupported value");
|
|
4963
4678
|
}
|
|
4964
|
-
const alreadyExternalResults = /* @__PURE__ */ new WeakSet();
|
|
4965
4679
|
function markExternalizationState(result, outputNeedsExternalization) {
|
|
4966
4680
|
if (outputNeedsExternalization === false)
|
|
4967
4681
|
alreadyExternalResults.add(result);
|
|
4968
4682
|
return result;
|
|
4969
4683
|
}
|
|
4970
|
-
function copyQueryResultExternalization(source, copy) {
|
|
4971
|
-
if (alreadyExternalResults.has(source))
|
|
4972
|
-
alreadyExternalResults.add(copy);
|
|
4973
|
-
return copy;
|
|
4974
|
-
}
|
|
4975
4684
|
function externalizeQueryResult(result) {
|
|
4976
4685
|
if (alreadyExternalResults.has(result))
|
|
4977
4686
|
return result;
|
|
@@ -6577,7 +6286,7 @@ class Parser {
|
|
|
6577
6286
|
const outerOrderBy = [];
|
|
6578
6287
|
parts.orderBy.forEach((order, index) => {
|
|
6579
6288
|
const expression = order.expression;
|
|
6580
|
-
const output = expression.kind === "column" && !expression.reference.includes(".") ? parts.select.find((item) => item.alias === expression.reference) : parts.select.find((item) => item.expression.kind !== "wildcard" &&
|
|
6289
|
+
const output = expression.kind === "column" && !expression.reference.includes(".") ? parts.select.find((item) => item.alias === expression.reference) : parts.select.find((item) => item.expression.kind !== "wildcard" && encodeQueryIdentity(item.expression) === encodeQueryIdentity(expression));
|
|
6581
6290
|
let alias = output?.alias;
|
|
6582
6291
|
if (alias === void 0) {
|
|
6583
6292
|
alias = `\0distinct_on_order_${String(index)}`;
|
|
@@ -7021,6 +6730,47 @@ class Parser {
|
|
|
7021
6730
|
}
|
|
7022
6731
|
if (this.#peek().text === "(") {
|
|
7023
6732
|
const upper = table.toUpperCase();
|
|
6733
|
+
if (upper === "UNNEST") {
|
|
6734
|
+
this.#expectPunctuation("(");
|
|
6735
|
+
const array = this.#expression();
|
|
6736
|
+
this.#expectPunctuation(")");
|
|
6737
|
+
if (array.kind !== "call" || array.name !== "ARRAY")
|
|
6738
|
+
throw new TypeError("UNNEST currently requires an ARRAY constructor");
|
|
6739
|
+
if (array.arguments.some((argument) => expressionColumns(argument).length > 0 || hasAggregate(argument) || containsWindow(argument)))
|
|
6740
|
+
throw new TypeError("UNNEST ARRAY members cannot refer to table rows");
|
|
6741
|
+
let ordinality = false;
|
|
6742
|
+
if (this.#isKeyword("WITH")) {
|
|
6743
|
+
this.#keyword("WITH");
|
|
6744
|
+
this.#keyword("ORDINALITY");
|
|
6745
|
+
ordinality = true;
|
|
6746
|
+
}
|
|
6747
|
+
const alias2 = this.#sourceAlias() ?? "unnest";
|
|
6748
|
+
const blocks = (array.arguments.length === 0 ? [{ kind: "literal", value: null }] : array.arguments).map((expression, index) => ({
|
|
6749
|
+
sql: "(unnest row)",
|
|
6750
|
+
base: { table: DUAL_TABLE, alias: DUAL_TABLE },
|
|
6751
|
+
joins: [],
|
|
6752
|
+
select: [
|
|
6753
|
+
{ expression, alias: alias2 },
|
|
6754
|
+
...ordinality ? [
|
|
6755
|
+
{
|
|
6756
|
+
expression: { kind: "literal", value: index + 1 },
|
|
6757
|
+
alias: "ordinality"
|
|
6758
|
+
}
|
|
6759
|
+
] : []
|
|
6760
|
+
],
|
|
6761
|
+
predicates: [],
|
|
6762
|
+
groupBy: [],
|
|
6763
|
+
having: [],
|
|
6764
|
+
orderBy: [],
|
|
6765
|
+
...array.arguments.length === 0 ? { limit: 0 } : {}
|
|
6766
|
+
}));
|
|
6767
|
+
const derived = blocks.length === 1 ? blocks[0] : compoundSelectBlock("(unnest)", blocks, blocks.slice(1).map(() => "union all"), { orderBy: [] }, this.nextDerivedSequence);
|
|
6768
|
+
if (derived === void 0)
|
|
6769
|
+
throw new TypeError("UNNEST requires an ARRAY constructor");
|
|
6770
|
+
if (this.#punctuation("("))
|
|
6771
|
+
this.#applyColumnAliases(derived);
|
|
6772
|
+
return this.#derivedSource(derived, alias2);
|
|
6773
|
+
}
|
|
7024
6774
|
if (upper === "JSON_TABLE") {
|
|
7025
6775
|
this.#expectPunctuation("(");
|
|
7026
6776
|
const document = this.#expression();
|
|
@@ -7431,8 +7181,8 @@ class Parser {
|
|
|
7431
7181
|
if (this.#isKeyword("ESCAPE")) {
|
|
7432
7182
|
this.#keyword("ESCAPE");
|
|
7433
7183
|
const token2 = this.#take("string");
|
|
7434
|
-
if (Array.from(token2.text).length
|
|
7435
|
-
throw new TypeError("LIKE ESCAPE takes
|
|
7184
|
+
if (Array.from(token2.text).length > 1) {
|
|
7185
|
+
throw new TypeError("LIKE ESCAPE takes at most one character");
|
|
7436
7186
|
}
|
|
7437
7187
|
escape = token2.text;
|
|
7438
7188
|
}
|
|
@@ -7508,7 +7258,11 @@ class Parser {
|
|
|
7508
7258
|
}
|
|
7509
7259
|
const operator = this.#peek().text;
|
|
7510
7260
|
if (operator === "[") {
|
|
7511
|
-
|
|
7261
|
+
this.#index += 1;
|
|
7262
|
+
const index = this.#expression();
|
|
7263
|
+
this.#expectPunctuation("]");
|
|
7264
|
+
left = { kind: "call", name: "MINNOW_ARRAY_AT", arguments: [left, index] };
|
|
7265
|
+
continue;
|
|
7512
7266
|
}
|
|
7513
7267
|
const regexOperator = operator === "~" || operator === "~*" || operator === "!~" || operator === "!~*";
|
|
7514
7268
|
const precedence = operator === "::" ? 30 : operator === "^" ? 25 : operator === "*" || operator === "/" || operator === "%" ? 20 : operator === "+" || operator === "-" ? 10 : operator === "||" || operator === "->" || operator === "->>" || regexOperator ? 5 : -1;
|
|
@@ -8013,7 +7767,7 @@ class Parser {
|
|
|
8013
7767
|
return this.#booleanAggregate(upper);
|
|
8014
7768
|
}
|
|
8015
7769
|
const name = upper === "ANY_VALUE" ? "MIN" : functionSpellings.get(upper) ?? upper;
|
|
8016
|
-
if (name === "MINNOW_TUPLE_KEY" || name === "MINNOW_COLLATE" || name === "MINNOW_SINGLE_VALUE" || name === "MINNOW_JSON_GET" || name === "MINNOW_JSON_GET_TEXT" || name === "MINNOW_REGEX_MATCH") {
|
|
7770
|
+
if (name === "MINNOW_TUPLE_KEY" || name === "MINNOW_COLLATE" || name === "MINNOW_ARRAY_AT" || name === "MINNOW_ARRAY_FROM_JSON" || name === "MINNOW_ARRAY_ELEMENT" || name === "MINNOW_SINGLE_VALUE" || name === "MINNOW_JSON_GET" || name === "MINNOW_JSON_GET_TEXT" || name === "MINNOW_REGEX_MATCH") {
|
|
8017
7771
|
throw new TypeError(`Unsupported function: ${identifier}`);
|
|
8018
7772
|
}
|
|
8019
7773
|
if (!aggregateNames.has(name) && !scalarFunctionNames.has(name))
|
|
@@ -8176,13 +7930,17 @@ class Parser {
|
|
|
8176
7930
|
...frame === void 0 ? {} : { frame }
|
|
8177
7931
|
};
|
|
8178
7932
|
}
|
|
8179
|
-
|
|
7933
|
+
if (upper === "ARRAY_AGG" && args[0] !== void 0) {
|
|
7934
|
+
args[0] = { kind: "call", name: "MINNOW_ARRAY_ELEMENT", arguments: [args[0]] };
|
|
7935
|
+
}
|
|
7936
|
+
const call = {
|
|
8180
7937
|
kind: "call",
|
|
8181
7938
|
name,
|
|
8182
7939
|
arguments: args,
|
|
8183
7940
|
...distinct ? { distinct: true } : {},
|
|
8184
7941
|
...aggregateOrderBy === void 0 ? {} : { aggregateOrderBy }
|
|
8185
7942
|
};
|
|
7943
|
+
return upper === "ARRAY_AGG" ? { kind: "call", name: "MINNOW_ARRAY_FROM_JSON", arguments: [call] } : call;
|
|
8186
7944
|
}
|
|
8187
7945
|
let reference = identifier;
|
|
8188
7946
|
if (this.#punctuation(".")) {
|
|
@@ -8346,6 +8104,8 @@ class Parser {
|
|
|
8346
8104
|
if (unit === "groups" && orderBy.length === 0) {
|
|
8347
8105
|
throw new TypeError("GROUPS frames require ORDER BY inside OVER (...)");
|
|
8348
8106
|
}
|
|
8107
|
+
if (unit === "range" && (start.offset !== void 0 || end.offset !== void 0) && orderBy.length !== 1)
|
|
8108
|
+
throw new TypeError("Offset RANGE frames require exactly one ORDER BY expression");
|
|
8349
8109
|
let exclude;
|
|
8350
8110
|
if (this.#isKeyword("EXCLUDE")) {
|
|
8351
8111
|
this.#keyword("EXCLUDE");
|
|
@@ -8391,11 +8151,8 @@ class Parser {
|
|
|
8391
8151
|
return { kind: "current-row" };
|
|
8392
8152
|
}
|
|
8393
8153
|
const offset = Number(this.#take("number").text);
|
|
8394
|
-
if (!Number.
|
|
8395
|
-
throw new TypeError("Window frame offsets must be non-negative integers");
|
|
8396
|
-
}
|
|
8397
|
-
if (unit === "range") {
|
|
8398
|
-
throw new TypeError("RANGE frames take only UNBOUNDED and CURRENT ROW bounds; use ROWS");
|
|
8154
|
+
if (!Number.isFinite(offset) || offset < 0 || unit !== "range" && !Number.isInteger(offset)) {
|
|
8155
|
+
throw new TypeError("Window frame offsets must be non-negative integers, or numeric RANGE offsets");
|
|
8399
8156
|
}
|
|
8400
8157
|
if (this.#isKeyword("PRECEDING")) {
|
|
8401
8158
|
this.#keyword("PRECEDING");
|
|
@@ -8468,7 +8225,7 @@ function desugarGroupingSets(parts, nextSequence) {
|
|
|
8468
8225
|
}
|
|
8469
8226
|
}
|
|
8470
8227
|
}
|
|
8471
|
-
const signatureOf = (expression) =>
|
|
8228
|
+
const signatureOf = (expression) => encodeQueryIdentity(expression);
|
|
8472
8229
|
const universe = new Set(sets.flat().map(signatureOf));
|
|
8473
8230
|
const members = sets.map((set) => {
|
|
8474
8231
|
const setSignatures = new Set(set.map(signatureOf));
|
|
@@ -8707,6 +8464,108 @@ function unifyPlanGroupedReferences(plan, columnsOf) {
|
|
|
8707
8464
|
return owner === void 0 ? void 0 : `${owner}.${reference}`;
|
|
8708
8465
|
});
|
|
8709
8466
|
}
|
|
8467
|
+
function desugarComposedFullJoin(parts, join, nextSequence) {
|
|
8468
|
+
const marker = `(full marker ${String(nextSequence())})`;
|
|
8469
|
+
const plain = {
|
|
8470
|
+
sql: parts.sql,
|
|
8471
|
+
distinct: false,
|
|
8472
|
+
predicates: [],
|
|
8473
|
+
groupBy: [],
|
|
8474
|
+
having: [],
|
|
8475
|
+
orderBy: []
|
|
8476
|
+
};
|
|
8477
|
+
const marked = derivedTableSource(assembleSelectBlock({
|
|
8478
|
+
...plain,
|
|
8479
|
+
base: parts.base,
|
|
8480
|
+
joins: [],
|
|
8481
|
+
select: [
|
|
8482
|
+
{ expression: { kind: "wildcard", table: parts.base.alias }, alias: "*" },
|
|
8483
|
+
{ expression: { kind: "literal", value: 1 }, alias: marker }
|
|
8484
|
+
]
|
|
8485
|
+
}, nextSequence), parts.base.alias, nextSequence);
|
|
8486
|
+
const columns = /* @__PURE__ */ new Map();
|
|
8487
|
+
const gather = (expression) => {
|
|
8488
|
+
if (expression.kind === "column" && !columns.has(expression.reference))
|
|
8489
|
+
columns.set(expression.reference, `(full column ${String(columns.size)})`);
|
|
8490
|
+
for (const child of childExpressions(expression))
|
|
8491
|
+
gather(child);
|
|
8492
|
+
};
|
|
8493
|
+
for (const item of parts.select)
|
|
8494
|
+
gather(item.expression);
|
|
8495
|
+
for (const expression of parts.groupBy)
|
|
8496
|
+
gather(expression);
|
|
8497
|
+
for (const set of parts.groupingSets ?? [])
|
|
8498
|
+
for (const expression of set)
|
|
8499
|
+
gather(expression);
|
|
8500
|
+
for (const predicate of [...parts.predicates, ...parts.having]) {
|
|
8501
|
+
gather(predicate.left);
|
|
8502
|
+
gather(predicate.right);
|
|
8503
|
+
}
|
|
8504
|
+
const outputs = new Set(parts.select.map((item) => item.alias));
|
|
8505
|
+
for (const order of parts.orderBy)
|
|
8506
|
+
if (order.expression.kind !== "column" || !outputs.has(order.expression.reference))
|
|
8507
|
+
gather(order.expression);
|
|
8508
|
+
const select = [...columns].map(([reference, alias]) => ({
|
|
8509
|
+
expression: { kind: "column", reference },
|
|
8510
|
+
alias
|
|
8511
|
+
}));
|
|
8512
|
+
if (select.length === 0)
|
|
8513
|
+
select.push({ expression: { kind: "literal", value: 1 }, alias: "(full row)" });
|
|
8514
|
+
const { full, kind, left, right, on, ...rightSource } = join;
|
|
8515
|
+
void full;
|
|
8516
|
+
void kind;
|
|
8517
|
+
const matched = assembleSelectBlock({
|
|
8518
|
+
...plain,
|
|
8519
|
+
base: marked,
|
|
8520
|
+
joins: [{ ...rightSource, kind: "left", left, right, ...on === void 0 ? {} : { on } }],
|
|
8521
|
+
select
|
|
8522
|
+
}, nextSequence);
|
|
8523
|
+
const unmatched = assembleSelectBlock({
|
|
8524
|
+
...plain,
|
|
8525
|
+
base: rightSource,
|
|
8526
|
+
joins: [{ ...marked, kind: "left", left, right, ...on === void 0 ? {} : { on } }],
|
|
8527
|
+
select,
|
|
8528
|
+
predicates: [
|
|
8529
|
+
{
|
|
8530
|
+
left: { kind: "column", reference: `${marked.alias}.${marker}` },
|
|
8531
|
+
operator: "IS NULL",
|
|
8532
|
+
right: { kind: "literal", value: null }
|
|
8533
|
+
}
|
|
8534
|
+
]
|
|
8535
|
+
}, nextSequence);
|
|
8536
|
+
const combined = compoundSelectBlock(parts.sql, [matched, unmatched], ["union all"], { orderBy: [] }, nextSequence);
|
|
8537
|
+
const source = derivedTableSource(combined, `(full result ${String(nextSequence())})`, nextSequence);
|
|
8538
|
+
const rewrite = (expression) => {
|
|
8539
|
+
if (expression.kind === "column") {
|
|
8540
|
+
const column = columns.get(expression.reference);
|
|
8541
|
+
if (column !== void 0)
|
|
8542
|
+
return { kind: "column", reference: `${source.alias}.${column}` };
|
|
8543
|
+
}
|
|
8544
|
+
return mapChildExpressions(expression, rewrite);
|
|
8545
|
+
};
|
|
8546
|
+
return assembleSelectBlock({
|
|
8547
|
+
...parts,
|
|
8548
|
+
base: source,
|
|
8549
|
+
joins: [],
|
|
8550
|
+
select: parts.select.map((item) => ({ ...item, expression: rewrite(item.expression) })),
|
|
8551
|
+
predicates: parts.predicates.map((predicate) => ({
|
|
8552
|
+
...predicate,
|
|
8553
|
+
left: rewrite(predicate.left),
|
|
8554
|
+
right: rewrite(predicate.right)
|
|
8555
|
+
})),
|
|
8556
|
+
groupBy: parts.groupBy.map(rewrite),
|
|
8557
|
+
having: parts.having.map((predicate) => ({
|
|
8558
|
+
...predicate,
|
|
8559
|
+
left: rewrite(predicate.left),
|
|
8560
|
+
right: rewrite(predicate.right)
|
|
8561
|
+
})),
|
|
8562
|
+
orderBy: parts.orderBy.map((order) => ({
|
|
8563
|
+
...order,
|
|
8564
|
+
expression: order.expression.kind === "column" && outputs.has(order.expression.reference) ? order.expression : rewrite(order.expression)
|
|
8565
|
+
})),
|
|
8566
|
+
...parts.groupingSets === void 0 ? {} : { groupingSets: parts.groupingSets.map((set) => set.map(rewrite)) }
|
|
8567
|
+
}, nextSequence);
|
|
8568
|
+
}
|
|
8710
8569
|
function desugarFullJoin(parts, nextSequence) {
|
|
8711
8570
|
const join = parts.joins[0];
|
|
8712
8571
|
if (parts.joins.length !== 1 || join?.full !== true) {
|
|
@@ -8716,10 +8575,10 @@ function desugarFullJoin(parts, nextSequence) {
|
|
|
8716
8575
|
throw new TypeError("FULL JOIN cannot be combined with SELECT *");
|
|
8717
8576
|
}
|
|
8718
8577
|
if (parts.groupBy.length > 0 || parts.having.length > 0 || parts.distinct || parts.select.some((item) => hasAggregate(item.expression) || containsWindow(item.expression))) {
|
|
8719
|
-
|
|
8578
|
+
return desugarComposedFullJoin(parts, join, nextSequence);
|
|
8720
8579
|
}
|
|
8721
8580
|
if (join.on !== void 0) {
|
|
8722
|
-
|
|
8581
|
+
return desugarComposedFullJoin(parts, join, nextSequence);
|
|
8723
8582
|
}
|
|
8724
8583
|
const outputAlias = (reference) => {
|
|
8725
8584
|
const exact = parts.select.find((item) => item.alias === reference || item.expression.kind === "column" && item.expression.reference === reference);
|
|
@@ -8775,9 +8634,6 @@ function desugarFullJoin(parts, nextSequence) {
|
|
|
8775
8634
|
}
|
|
8776
8635
|
function assembleSelectBlock(parts, nextSequence) {
|
|
8777
8636
|
if (parts.select.some((item) => item.expression.kind === "wildcard")) {
|
|
8778
|
-
if (parts.joins.some((join) => join.full === true)) {
|
|
8779
|
-
throw new TypeError("FULL JOIN cannot be combined with SELECT *");
|
|
8780
|
-
}
|
|
8781
8637
|
return {
|
|
8782
8638
|
sql: parts.sql,
|
|
8783
8639
|
base: parts.base,
|
|
@@ -9408,19 +9264,16 @@ function assembleOrderByExpressionBlock(parts, nextSequence) {
|
|
|
9408
9264
|
for (const order of parts.orderBy) {
|
|
9409
9265
|
if (!orderNeedsHiddenColumn(order.expression, parts))
|
|
9410
9266
|
continue;
|
|
9411
|
-
if (containsWindow(order.expression)) {
|
|
9412
|
-
throw new TypeError("Window functions are only allowed in the select list");
|
|
9413
|
-
}
|
|
9414
9267
|
if (order.expression.kind === "literal") {
|
|
9415
9268
|
throw new TypeError("ORDER BY position is outside the select list");
|
|
9416
9269
|
}
|
|
9417
9270
|
}
|
|
9418
|
-
const selectSignatures = new Map(parts.select.map((item) => [
|
|
9271
|
+
const selectSignatures = new Map(parts.select.map((item) => [encodeQueryIdentity(item.expression), item.alias]));
|
|
9419
9272
|
const hiddenItems = [];
|
|
9420
9273
|
const rewrittenOrder = parts.orderBy.map((order) => {
|
|
9421
9274
|
if (!orderNeedsHiddenColumn(order.expression, parts))
|
|
9422
9275
|
return order;
|
|
9423
|
-
const existingAlias = selectSignatures.get(
|
|
9276
|
+
const existingAlias = selectSignatures.get(encodeQueryIdentity(order.expression));
|
|
9424
9277
|
if (existingAlias !== void 0) {
|
|
9425
9278
|
return {
|
|
9426
9279
|
...order,
|
|
@@ -9596,16 +9449,24 @@ function validateOffset(offset) {
|
|
|
9596
9449
|
}
|
|
9597
9450
|
function desugarWindows(sql, base, joins, select, predicates, groupBy, having, tail, nextSequence) {
|
|
9598
9451
|
const grouped = groupBy.length > 0 || select.some((item) => hasAggregate(item.expression));
|
|
9599
|
-
const groupExpressions = new Set(groupBy.map((expression) =>
|
|
9600
|
-
const readableWhenGrouped = (expression) => hasAggregate(expression) || expressionColumns(expression).length === 0 || groupExpressions.has(
|
|
9452
|
+
const groupExpressions = new Set(groupBy.map((expression) => encodeQueryIdentity(expression)));
|
|
9453
|
+
const readableWhenGrouped = (expression) => hasAggregate(expression) || expressionColumns(expression).length === 0 || groupExpressions.has(encodeQueryIdentity(expression));
|
|
9601
9454
|
const internalAliases = select.map((item, index) => item.alias.includes(".") ? `(window visible ${String(index + 1)})` : item.alias);
|
|
9602
9455
|
const innerSelect = select.flatMap((item, index) => containsWindow(item.expression) ? [] : [{ ...item, alias: internalAliases[index] ?? item.alias }]);
|
|
9603
9456
|
const windows = [];
|
|
9604
9457
|
let hidden = 0;
|
|
9458
|
+
const hiddenExpressions = /* @__PURE__ */ new Map();
|
|
9459
|
+
const repeatable = (expression) => !(expression.kind === "call" && volatileScalarFunctionNames.has(expression.name)) && childExpressions(expression).every(repeatable);
|
|
9605
9460
|
const hide = (expression) => {
|
|
9461
|
+
const key = repeatable(expression) ? encodeQueryIdentity(expression) : void 0;
|
|
9462
|
+
const existing = key === void 0 ? void 0 : hiddenExpressions.get(key);
|
|
9463
|
+
if (existing !== void 0)
|
|
9464
|
+
return existing;
|
|
9606
9465
|
hidden += 1;
|
|
9607
9466
|
const alias = `(window ${String(hidden)})`;
|
|
9608
9467
|
innerSelect.push({ expression, alias });
|
|
9468
|
+
if (key !== void 0)
|
|
9469
|
+
hiddenExpressions.set(key, alias);
|
|
9609
9470
|
return alias;
|
|
9610
9471
|
};
|
|
9611
9472
|
const registerWindow = (expression, alias) => {
|
|
@@ -10019,7 +9880,7 @@ export {
|
|
|
10019
9880
|
annotateAvgArgumentScales,
|
|
10020
9881
|
annotateIntegerDivision,
|
|
10021
9882
|
annotatePlanIntegerDivision,
|
|
10022
|
-
applyWindowFunctions,
|
|
9883
|
+
applyWindowFunctions2 as applyWindowFunctions,
|
|
10023
9884
|
assembleSelectBlock,
|
|
10024
9885
|
bindPendingSelectShapes,
|
|
10025
9886
|
bindPlanParameters,
|
|
@@ -10035,7 +9896,7 @@ export {
|
|
|
10035
9896
|
compileQuery,
|
|
10036
9897
|
compileStatement,
|
|
10037
9898
|
compoundSelectBlock,
|
|
10038
|
-
copyQueryResultExternalization,
|
|
9899
|
+
copyQueryResultExternalization2 as copyQueryResultExternalization,
|
|
10039
9900
|
createPreparedColumnarQuery,
|
|
10040
9901
|
createPreparedQuery,
|
|
10041
9902
|
createRecursiveCteState,
|
|
@@ -10049,6 +9910,7 @@ export {
|
|
|
10049
9910
|
evaluateRowExpression,
|
|
10050
9911
|
executeQuery,
|
|
10051
9912
|
executeRowQuery,
|
|
9913
|
+
executeRowQueryInternal,
|
|
10052
9914
|
expandFtsColumns,
|
|
10053
9915
|
expandNaturalJoins,
|
|
10054
9916
|
expandRowReferences,
|
|
@@ -10074,6 +9936,7 @@ export {
|
|
|
10074
9936
|
likeMatches,
|
|
10075
9937
|
mapBlockExpressions,
|
|
10076
9938
|
mapChildExpressions,
|
|
9939
|
+
markQueryResultExternal,
|
|
10077
9940
|
nullOrder,
|
|
10078
9941
|
orderOutputName,
|
|
10079
9942
|
parseQuantified,
|