@rex0220/kintone-sql-tools 3.21.0 → 3.23.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-cli/ksql.js +484 -96
- package/dist-engine/index.cjs +10 -10
- package/dist-engine/index.mjs +10 -10
- package/dist-engine/ksql-engine.umd.js +10 -10
- package/dist-engine/meta/bundle-baseline.json +10 -10
- package/dist-engine/meta/cjs.json +56 -14
- package/dist-engine/meta/esm.json +56 -14
- package/dist-engine/meta/umd.json +56 -14
- package/dist-engine/publicTypes.d.ts +6 -0
- package/dist-mcp/ksql-mcp.js +490 -98
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -5186,8 +5186,8 @@ function selectToFetchAllParams(stmt, appId) {
|
|
|
5186
5186
|
// 全件取得なので全フィールドを取得する
|
|
5187
5187
|
};
|
|
5188
5188
|
}
|
|
5189
|
-
function selectToFetchAllFields(stmt, targetTable) {
|
|
5190
|
-
const plan = collectRequiredFieldsByTable(stmt);
|
|
5189
|
+
function selectToFetchAllFields(stmt, targetTable, plainGroupByPlan) {
|
|
5190
|
+
const plan = collectRequiredFieldsByTable(stmt, plainGroupByPlan);
|
|
5191
5191
|
const target = plan.get(targetTable);
|
|
5192
5192
|
if (!target) return [];
|
|
5193
5193
|
if (target.allFields) return [];
|
|
@@ -5312,7 +5312,8 @@ function caseResultHasAggregate(result) {
|
|
|
5312
5312
|
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
5313
5313
|
return scalarValueHasAggregate(result);
|
|
5314
5314
|
}
|
|
5315
|
-
function collectRequiredFieldsByTable(stmt) {
|
|
5315
|
+
function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
5316
|
+
const allTables = [stmt.from, ...stmt.joins.map((j) => j.table)];
|
|
5316
5317
|
const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
|
|
5317
5318
|
const states = /* @__PURE__ */ new Map();
|
|
5318
5319
|
for (const table of physicalTables) {
|
|
@@ -5361,7 +5362,7 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
5361
5362
|
if (!fieldName) return;
|
|
5362
5363
|
st.fields.add(fieldName);
|
|
5363
5364
|
};
|
|
5364
|
-
const addFieldName = (rawName, phase = "select") => {
|
|
5365
|
+
const addFieldName = (rawName, phase = "select", groupResolution) => {
|
|
5365
5366
|
if (!rawName || rawName === "*") return;
|
|
5366
5367
|
if (rawName === "_p.*") {
|
|
5367
5368
|
markAllSubtableTables();
|
|
@@ -5384,6 +5385,15 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
5384
5385
|
}
|
|
5385
5386
|
return;
|
|
5386
5387
|
}
|
|
5388
|
+
if (phase === "groupBy" && groupResolution !== void 0) {
|
|
5389
|
+
if (groupResolution.kind === "PHYSICAL") {
|
|
5390
|
+
const source = allTables[groupResolution.sourceIndex];
|
|
5391
|
+
if (source?.cteName === null) {
|
|
5392
|
+
addFieldToTable(source, groupResolution.fieldCode);
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5387
5397
|
if ((phase === "orderBy" || phase === "having" || phase === "groupBy") && selectAliases.has(rawName)) {
|
|
5388
5398
|
return;
|
|
5389
5399
|
}
|
|
@@ -5544,9 +5554,9 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
5544
5554
|
return;
|
|
5545
5555
|
}
|
|
5546
5556
|
};
|
|
5547
|
-
const walkGroupByKey = (k) => {
|
|
5557
|
+
const walkGroupByKey = (k, resolution) => {
|
|
5548
5558
|
if (k.type === "FIELD_NAME") {
|
|
5549
|
-
addFieldName(k.name, "groupBy");
|
|
5559
|
+
addFieldName(k.name, "groupBy", resolution);
|
|
5550
5560
|
return;
|
|
5551
5561
|
}
|
|
5552
5562
|
if (k.type === "ARITH_KEY") {
|
|
@@ -5619,7 +5629,9 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
5619
5629
|
walkWhere(stmt.where, "where");
|
|
5620
5630
|
const grouping = normalizeGroupingSpec(stmt);
|
|
5621
5631
|
if (grouping.type === "PLAIN") {
|
|
5622
|
-
|
|
5632
|
+
grouping.allItems.forEach(
|
|
5633
|
+
(item, index) => walkGroupByKey(item, plainGroupByPlan?.items[index])
|
|
5634
|
+
);
|
|
5623
5635
|
} else if (grouping.type === "GROUPING_SETS") {
|
|
5624
5636
|
for (const item of grouping.allItems) {
|
|
5625
5637
|
addFieldRef(item.field, item.tableAlias, "select");
|
|
@@ -6853,8 +6865,8 @@ function parseOptionValues(value, fieldType) {
|
|
|
6853
6865
|
}
|
|
6854
6866
|
function optionVector(value, semantics) {
|
|
6855
6867
|
const order = semantics.optionOrder ?? /* @__PURE__ */ new Map();
|
|
6856
|
-
const
|
|
6857
|
-
const vector =
|
|
6868
|
+
const unique2 = [...new Set(parseOptionValues(value, semantics.fieldType))];
|
|
6869
|
+
const vector = unique2.map((label) => {
|
|
6858
6870
|
const rank = order.get(label);
|
|
6859
6871
|
return rank === void 0 ? { knownBand: 1, rank: 0, label } : { knownBand: 0, rank, label };
|
|
6860
6872
|
});
|
|
@@ -10802,10 +10814,10 @@ function planKorder(input) {
|
|
|
10802
10814
|
if (stmt.limit !== null && !Number.isSafeInteger(scanRows)) {
|
|
10803
10815
|
reasons.push(`KORDER_SCAN_ROWS_INVALID(offset=${offset}, limit=${stmt.limit})`);
|
|
10804
10816
|
}
|
|
10805
|
-
const
|
|
10806
|
-
if (
|
|
10817
|
+
const unique2 = [...new Set(reasons)];
|
|
10818
|
+
if (unique2.length > 0) {
|
|
10807
10819
|
throw new Error(
|
|
10808
|
-
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; ${
|
|
10820
|
+
`ArgumentError: KORDER BY cannot be executed (mode=KINTONE_NATIVE; ${unique2.join(", ")}). Use ORDER BY for canonical local ordering or simplify the query.`
|
|
10809
10821
|
);
|
|
10810
10822
|
}
|
|
10811
10823
|
const native = stmt.limit <= 500 && offset <= 1e4 && stmt.limit <= input.maxRecords;
|
|
@@ -10905,6 +10917,148 @@ function buildKorderCursorQuery(stmt) {
|
|
|
10905
10917
|
return parts.join(" ");
|
|
10906
10918
|
}
|
|
10907
10919
|
|
|
10920
|
+
// src/core/systemFields.ts
|
|
10921
|
+
var APP_SYSTEM_FIELD_CODES = [
|
|
10922
|
+
"$id",
|
|
10923
|
+
"$revision",
|
|
10924
|
+
"\u30EC\u30B3\u30FC\u30C9\u756A\u53F7",
|
|
10925
|
+
"\u4F5C\u6210\u8005",
|
|
10926
|
+
"\u4F5C\u6210\u65E5\u6642",
|
|
10927
|
+
"\u66F4\u65B0\u8005",
|
|
10928
|
+
"\u66F4\u65B0\u65E5\u6642",
|
|
10929
|
+
"\u30B9\u30C6\u30FC\u30BF\u30B9",
|
|
10930
|
+
"\u4F5C\u696D\u8005"
|
|
10931
|
+
];
|
|
10932
|
+
function isSystemLikeFieldCode(code) {
|
|
10933
|
+
return code.startsWith("_") || code.startsWith("$");
|
|
10934
|
+
}
|
|
10935
|
+
|
|
10936
|
+
// src/core/optimization/plainGroupByPlan.ts
|
|
10937
|
+
var AGGREGATE_REFERENCE_PREFIX = /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/;
|
|
10938
|
+
function containsAggregateColumnNode(node) {
|
|
10939
|
+
if (node === null || typeof node !== "object") return false;
|
|
10940
|
+
if (Array.isArray(node)) return node.some(containsAggregateColumnNode);
|
|
10941
|
+
const value = node;
|
|
10942
|
+
if (value["type"] === "AGGREGATE" || value["type"] === "ARITH_AGG_COL") return true;
|
|
10943
|
+
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
|
|
10944
|
+
if (value["type"] === "FIELD" && typeof value["field"] === "string") {
|
|
10945
|
+
return AGGREGATE_REFERENCE_PREFIX.test(value["field"]);
|
|
10946
|
+
}
|
|
10947
|
+
return Object.values(value).some(containsAggregateColumnNode);
|
|
10948
|
+
}
|
|
10949
|
+
function classifyPreGroupAlias(column) {
|
|
10950
|
+
switch (column.type) {
|
|
10951
|
+
case "AGGREGATE":
|
|
10952
|
+
case "ARITH_AGG_COL":
|
|
10953
|
+
return "AGGREGATE_DEPENDENT";
|
|
10954
|
+
case "GROUPING_COL":
|
|
10955
|
+
case "WINDOW_COL":
|
|
10956
|
+
return "POST_GROUP_ONLY";
|
|
10957
|
+
case "VARIABLE_COL":
|
|
10958
|
+
throw new Error("InternalError: unresolved VARIABLE_COL reached GROUP BY alias planning.");
|
|
10959
|
+
case "WILDCARD":
|
|
10960
|
+
case "PARENT_WILDCARD":
|
|
10961
|
+
case "FIELD":
|
|
10962
|
+
case "LITERAL_COL":
|
|
10963
|
+
case "ARITH_COL":
|
|
10964
|
+
case "CASE_COL":
|
|
10965
|
+
case "STRFUNC_COL":
|
|
10966
|
+
case "SCALAR_VALUE_COL":
|
|
10967
|
+
case "SCALAR_SUBQUERY_COL":
|
|
10968
|
+
return containsAggregate(column) || containsAggregateColumnNode(column) ? "AGGREGATE_DEPENDENT" : "SAFE";
|
|
10969
|
+
}
|
|
10970
|
+
}
|
|
10971
|
+
var SUBTABLE_SYSTEM_COLUMNS = ["_pid", "_rid", "_idx"];
|
|
10972
|
+
function unique(values) {
|
|
10973
|
+
return [...new Set(values)];
|
|
10974
|
+
}
|
|
10975
|
+
function sourceColumns(input) {
|
|
10976
|
+
switch (input.kind) {
|
|
10977
|
+
case "APP":
|
|
10978
|
+
return unique([
|
|
10979
|
+
...input.fieldCodes,
|
|
10980
|
+
...APP_SYSTEM_FIELD_CODES
|
|
10981
|
+
]);
|
|
10982
|
+
case "SUBTABLE":
|
|
10983
|
+
return unique([
|
|
10984
|
+
...input.childFieldCodes,
|
|
10985
|
+
...SUBTABLE_SYSTEM_COLUMNS,
|
|
10986
|
+
...input.parentFieldCodes.map((field) => `_p.${field}`)
|
|
10987
|
+
]);
|
|
10988
|
+
case "MATERIALIZED":
|
|
10989
|
+
return unique(input.columns);
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
function resolvePlainGroupBySourceSchemas(stmt, lookup) {
|
|
10993
|
+
const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
10994
|
+
return sources.map((source, sourceIndex) => ({
|
|
10995
|
+
sourceIndex,
|
|
10996
|
+
qualifier: source.alias ?? source.cteName,
|
|
10997
|
+
columns: sourceColumns(lookup(source, sourceIndex))
|
|
10998
|
+
}));
|
|
10999
|
+
}
|
|
11000
|
+
function parseGroupName(name) {
|
|
11001
|
+
if (name.startsWith("_p.")) return { qualifier: null, fieldCode: name };
|
|
11002
|
+
const dot = name.indexOf(".");
|
|
11003
|
+
if (dot <= 0 || dot === name.length - 1) {
|
|
11004
|
+
return { qualifier: null, fieldCode: name };
|
|
11005
|
+
}
|
|
11006
|
+
return { qualifier: name.slice(0, dot), fieldCode: name.slice(dot + 1) };
|
|
11007
|
+
}
|
|
11008
|
+
function runtimeKey(source, fieldCode) {
|
|
11009
|
+
return source.qualifier === null ? fieldCode : `${source.qualifier}.${fieldCode}`;
|
|
11010
|
+
}
|
|
11011
|
+
function explicitAlias(column) {
|
|
11012
|
+
return "alias" in column && typeof column.alias === "string" ? column.alias : null;
|
|
11013
|
+
}
|
|
11014
|
+
function resolveFieldName(name, columns, schemas) {
|
|
11015
|
+
const parsed = parseGroupName(name);
|
|
11016
|
+
const candidateSources = parsed.qualifier === null ? schemas : schemas.filter((source) => source.qualifier === parsed.qualifier);
|
|
11017
|
+
const physical = candidateSources.filter((source) => source.columns.includes(parsed.fieldCode));
|
|
11018
|
+
if (physical.length > 1) {
|
|
11019
|
+
throw new Error(
|
|
11020
|
+
`ArgumentError: GROUP BY field ${name} is ambiguous across multiple sources (reason=GROUP_BY_FIELD_AMBIGUOUS).`
|
|
11021
|
+
);
|
|
11022
|
+
}
|
|
11023
|
+
if (physical.length === 1) {
|
|
11024
|
+
const source = physical[0];
|
|
11025
|
+
return {
|
|
11026
|
+
kind: "PHYSICAL",
|
|
11027
|
+
sourceIndex: source.sourceIndex,
|
|
11028
|
+
fieldCode: parsed.fieldCode,
|
|
11029
|
+
runtimeKey: runtimeKey(source, parsed.fieldCode)
|
|
11030
|
+
};
|
|
11031
|
+
}
|
|
11032
|
+
if (parsed.qualifier !== null) return { kind: "UNKNOWN", name };
|
|
11033
|
+
const aliases = columns.flatMap(
|
|
11034
|
+
(column, columnIndex) => explicitAlias(column) === name ? [{ column, columnIndex }] : []
|
|
11035
|
+
);
|
|
11036
|
+
if (aliases.length > 1) return { kind: "ALIAS_REJECT", reason: "DUPLICATE" };
|
|
11037
|
+
if (aliases.length === 1) {
|
|
11038
|
+
const candidate = aliases[0];
|
|
11039
|
+
const classification = classifyPreGroupAlias(candidate.column);
|
|
11040
|
+
if (classification === "SAFE") {
|
|
11041
|
+
return { kind: "ALIAS_SAFE", columnIndex: candidate.columnIndex };
|
|
11042
|
+
}
|
|
11043
|
+
return {
|
|
11044
|
+
kind: "ALIAS_REJECT",
|
|
11045
|
+
reason: classification === "AGGREGATE_DEPENDENT" ? "AGGREGATE" : "POST_GROUP_ONLY"
|
|
11046
|
+
};
|
|
11047
|
+
}
|
|
11048
|
+
const aggregateSyntheticMatch = columns.some(
|
|
11049
|
+
(column) => column.type === "AGGREGATE" && column.alias === null && aggregateSyntheticName(column.func, column.distinct, column.arg) === name
|
|
11050
|
+
);
|
|
11051
|
+
if (aggregateSyntheticMatch) return { kind: "ALIAS_REJECT", reason: "AGGREGATE" };
|
|
11052
|
+
return { kind: "UNKNOWN", name };
|
|
11053
|
+
}
|
|
11054
|
+
function planPlainGroupByResolution(groupBy, columns, schemas) {
|
|
11055
|
+
return {
|
|
11056
|
+
items: groupBy.map(
|
|
11057
|
+
(key) => key.type === "FIELD_NAME" ? resolveFieldName(key.name, columns, schemas) : { kind: "EXPRESSION" }
|
|
11058
|
+
)
|
|
11059
|
+
};
|
|
11060
|
+
}
|
|
11061
|
+
|
|
10908
11062
|
// src/engine/process.ts
|
|
10909
11063
|
function flatten(record, alias) {
|
|
10910
11064
|
const row = {};
|
|
@@ -10986,10 +11140,21 @@ function hasAggregateColumns(columns) {
|
|
|
10986
11140
|
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
|
|
10987
11141
|
);
|
|
10988
11142
|
}
|
|
10989
|
-
function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
|
|
11143
|
+
function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind, resolutionPlan, aliasEvaluationContext = {}) {
|
|
11144
|
+
if (resolutionPlan && resolutionPlan.items.length !== groupByKeys.length) {
|
|
11145
|
+
throw new Error("InternalError: plain GROUP BY resolution plan length does not match group keys.");
|
|
11146
|
+
}
|
|
10990
11147
|
const groups = /* @__PURE__ */ new Map();
|
|
10991
11148
|
for (const row of rows) {
|
|
10992
|
-
const key = groupByKeys.map(
|
|
11149
|
+
const key = groupByKeys.map(
|
|
11150
|
+
(groupKey, index) => evalGroupByKey(
|
|
11151
|
+
groupKey,
|
|
11152
|
+
row,
|
|
11153
|
+
resolutionPlan?.items[index],
|
|
11154
|
+
columns,
|
|
11155
|
+
aliasEvaluationContext
|
|
11156
|
+
)
|
|
11157
|
+
).join("\0");
|
|
10993
11158
|
const bucket = groups.get(key);
|
|
10994
11159
|
if (bucket) bucket.push(row);
|
|
10995
11160
|
else groups.set(key, [row]);
|
|
@@ -11097,8 +11262,32 @@ function materializeAggregateColumns(outRow, groupRows, columns, resolveAggSortK
|
|
|
11097
11262
|
}
|
|
11098
11263
|
}
|
|
11099
11264
|
}
|
|
11100
|
-
function evalGroupByKey(key, row) {
|
|
11101
|
-
if (key.type === "FIELD_NAME")
|
|
11265
|
+
function evalGroupByKey(key, row, resolution, columns, aliasEvaluationContext) {
|
|
11266
|
+
if (key.type === "FIELD_NAME") {
|
|
11267
|
+
if (!resolution) return row[key.name] ?? "";
|
|
11268
|
+
if (resolution.kind === "PHYSICAL") return row[resolution.runtimeKey] ?? "";
|
|
11269
|
+
if (resolution.kind === "ALIAS_SAFE") {
|
|
11270
|
+
const column = columns[resolution.columnIndex];
|
|
11271
|
+
if (!column) {
|
|
11272
|
+
throw new Error(
|
|
11273
|
+
`InternalError: GROUP BY alias column index ${resolution.columnIndex} is out of range.`
|
|
11274
|
+
);
|
|
11275
|
+
}
|
|
11276
|
+
const value = evaluateSelectColumnValue(
|
|
11277
|
+
column,
|
|
11278
|
+
row,
|
|
11279
|
+
resolution.columnIndex,
|
|
11280
|
+
aliasEvaluationContext
|
|
11281
|
+
);
|
|
11282
|
+
if (typeof value !== "string") {
|
|
11283
|
+
throw new Error("InternalError: GROUP BY alias resolved to an expanded SELECT column.");
|
|
11284
|
+
}
|
|
11285
|
+
return value;
|
|
11286
|
+
}
|
|
11287
|
+
throw new Error(
|
|
11288
|
+
`InternalError: unresolved plain GROUP BY item ${resolution.kind} reached evaluation.`
|
|
11289
|
+
);
|
|
11290
|
+
}
|
|
11102
11291
|
if (key.type === "FUNC_KEY") return evalStringFunc(key.expr, row);
|
|
11103
11292
|
return String(evalArithExpr(key.expr, row));
|
|
11104
11293
|
}
|
|
@@ -11536,7 +11725,7 @@ function buildDistinctTuple(columns, row, context = {}) {
|
|
|
11536
11725
|
return typeof value === "string" ? value : value.entries.map(([, entryValue]) => entryValue);
|
|
11537
11726
|
});
|
|
11538
11727
|
}
|
|
11539
|
-
function project(rows, columns, scalarCache, resolveFieldType,
|
|
11728
|
+
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, resolveFieldSemantics2, hiddenQualifiedAliases) {
|
|
11540
11729
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
11541
11730
|
const projected2 = rows.map((row) => {
|
|
11542
11731
|
const visible = stripHiddenQualifiedColumns(
|
|
@@ -11554,7 +11743,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
|
|
|
11554
11743
|
}
|
|
11555
11744
|
return out;
|
|
11556
11745
|
});
|
|
11557
|
-
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...
|
|
11746
|
+
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns2 ?? []];
|
|
11558
11747
|
return { rows: projected2, columns: cols };
|
|
11559
11748
|
}
|
|
11560
11749
|
const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
|
|
@@ -11898,10 +12087,11 @@ function runFullScan(input) {
|
|
|
11898
12087
|
havingFieldSemanticsResolver,
|
|
11899
12088
|
aggregateSortKindResolver,
|
|
11900
12089
|
appliedKlikes,
|
|
11901
|
-
sourceColumns,
|
|
12090
|
+
sourceColumns: sourceColumns2,
|
|
11902
12091
|
tableColumns,
|
|
11903
12092
|
hiddenQualifiedAliases,
|
|
11904
|
-
resolvedGroupingSpec
|
|
12093
|
+
resolvedGroupingSpec,
|
|
12094
|
+
plainGroupByPlan
|
|
11905
12095
|
} = input;
|
|
11906
12096
|
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
|
|
11907
12097
|
for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
|
|
@@ -11948,7 +12138,13 @@ function runFullScan(input) {
|
|
|
11948
12138
|
rows,
|
|
11949
12139
|
grouping.type === "PLAIN" ? grouping.allItems : [],
|
|
11950
12140
|
stmt.columns,
|
|
11951
|
-
aggregateSortKindResolver
|
|
12141
|
+
aggregateSortKindResolver,
|
|
12142
|
+
grouping.type === "PLAIN" ? plainGroupByPlan : void 0,
|
|
12143
|
+
{
|
|
12144
|
+
scalarCache,
|
|
12145
|
+
resolveFieldType: fieldTypeResolver,
|
|
12146
|
+
resolveFieldSemantics: fieldSemanticsResolver
|
|
12147
|
+
}
|
|
11952
12148
|
);
|
|
11953
12149
|
}
|
|
11954
12150
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
|
|
@@ -11976,7 +12172,7 @@ function runFullScan(input) {
|
|
|
11976
12172
|
stmt.columns,
|
|
11977
12173
|
scalarCache,
|
|
11978
12174
|
fieldTypeResolver,
|
|
11979
|
-
|
|
12175
|
+
sourceColumns2,
|
|
11980
12176
|
fieldSemanticsResolver,
|
|
11981
12177
|
hiddenQualifiedAliases
|
|
11982
12178
|
);
|
|
@@ -13927,7 +14123,12 @@ async function execute(sql, client, options = {}) {
|
|
|
13927
14123
|
cacheContext
|
|
13928
14124
|
);
|
|
13929
14125
|
metrics.elapsedMs = Date.now() - startedAt;
|
|
13930
|
-
|
|
14126
|
+
const finalResult = { ...attachSearchAbortWarning(result, collector), metrics };
|
|
14127
|
+
if (result.type === "SELECT") {
|
|
14128
|
+
const columnMeta = materializedMetaBySelectResult.get(result);
|
|
14129
|
+
if (columnMeta) materializedMetaBySelectResult.set(finalResult, columnMeta);
|
|
14130
|
+
}
|
|
14131
|
+
return finalResult;
|
|
13931
14132
|
}
|
|
13932
14133
|
function createEmptyMetrics() {
|
|
13933
14134
|
return {
|
|
@@ -14138,11 +14339,26 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
14138
14339
|
case "VALIDATE":
|
|
14139
14340
|
return executeExistingRecordValidation(stmt, client, options, cacheContext);
|
|
14140
14341
|
case "SELECT":
|
|
14141
|
-
return executeSelect(
|
|
14342
|
+
return executeSelect(
|
|
14343
|
+
stmt,
|
|
14344
|
+
client,
|
|
14345
|
+
options,
|
|
14346
|
+
cacheContext,
|
|
14347
|
+
void 0,
|
|
14348
|
+
options.captureColumnMeta === true,
|
|
14349
|
+
options.captureColumnMeta === true
|
|
14350
|
+
);
|
|
14142
14351
|
case "UNION":
|
|
14143
|
-
return executeUnion(
|
|
14352
|
+
return executeUnion(
|
|
14353
|
+
stmt,
|
|
14354
|
+
client,
|
|
14355
|
+
options,
|
|
14356
|
+
cacheContext,
|
|
14357
|
+
options.captureColumnMeta === true,
|
|
14358
|
+
options.captureColumnMeta === true
|
|
14359
|
+
);
|
|
14144
14360
|
case "WITH":
|
|
14145
|
-
return executeWith(stmt, client, options, cacheContext);
|
|
14361
|
+
return executeWith(stmt, client, options, cacheContext, void 0, options.captureColumnMeta === true);
|
|
14146
14362
|
case "INSERT":
|
|
14147
14363
|
return executeInsert(stmt, client, options, cacheContext);
|
|
14148
14364
|
case "INSERT_SELECT":
|
|
@@ -15196,16 +15412,25 @@ async function assertDmlWhereCapability(stmt, client, cacheContext) {
|
|
|
15196
15412
|
);
|
|
15197
15413
|
}
|
|
15198
15414
|
}
|
|
15199
|
-
async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false) {
|
|
15415
|
+
async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false, forLibraryCapture = false) {
|
|
15200
15416
|
let result;
|
|
15201
15417
|
await validateSelectGroupingPlanning(stmt, client, cacheContext, cteCache);
|
|
15202
15418
|
if (isNoFromSelect(stmt)) {
|
|
15203
15419
|
result = executeNoFromSelect(stmt);
|
|
15204
15420
|
if (captureColumnMeta) {
|
|
15205
|
-
materializedMetaBySelectResult.set(
|
|
15421
|
+
materializedMetaBySelectResult.set(
|
|
15422
|
+
result,
|
|
15423
|
+
await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache, forLibraryCapture)
|
|
15424
|
+
);
|
|
15206
15425
|
}
|
|
15207
15426
|
return result;
|
|
15208
15427
|
}
|
|
15428
|
+
const plainGroupByPlan = await buildRuntimePlainGroupByPlan(
|
|
15429
|
+
stmt,
|
|
15430
|
+
client,
|
|
15431
|
+
cacheContext,
|
|
15432
|
+
cteCache
|
|
15433
|
+
);
|
|
15209
15434
|
await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
|
|
15210
15435
|
const whereCapability = await resolveSelectWhereCapability(stmt, client, cacheContext, cteCache);
|
|
15211
15436
|
if (whereCapability.capability === "UNSUPPORTED") {
|
|
@@ -15250,17 +15475,93 @@ async function executeSelect(stmt, client, options, cacheContext, cteCache, capt
|
|
|
15250
15475
|
cteCache,
|
|
15251
15476
|
whereCapability.capability === "EXACT_PUSHDOWN",
|
|
15252
15477
|
orderMeta,
|
|
15253
|
-
prefilterPlan
|
|
15478
|
+
prefilterPlan,
|
|
15479
|
+
plainGroupByPlan
|
|
15254
15480
|
);
|
|
15255
15481
|
}
|
|
15256
15482
|
} catch (error) {
|
|
15257
15483
|
throwCompleteInputError(completePolicy, error);
|
|
15258
15484
|
}
|
|
15259
15485
|
if (captureColumnMeta) {
|
|
15260
|
-
materializedMetaBySelectResult.set(
|
|
15486
|
+
materializedMetaBySelectResult.set(
|
|
15487
|
+
result,
|
|
15488
|
+
await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache, forLibraryCapture)
|
|
15489
|
+
);
|
|
15261
15490
|
}
|
|
15262
15491
|
return result;
|
|
15263
15492
|
}
|
|
15493
|
+
async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, materializedTables) {
|
|
15494
|
+
if (stmt.groupBy.length === 0) return void 0;
|
|
15495
|
+
const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
15496
|
+
const inputs = await Promise.all(sources.map(async (source) => {
|
|
15497
|
+
if (source.cteName !== null) {
|
|
15498
|
+
const materialized = materializedTables?.get(source.cteName);
|
|
15499
|
+
if (!materialized) {
|
|
15500
|
+
throw new Error(`InternalError: materialized schema ${source.cteName} is not available for GROUP BY planning.`);
|
|
15501
|
+
}
|
|
15502
|
+
return { kind: "MATERIALIZED", columns: materialized.columns };
|
|
15503
|
+
}
|
|
15504
|
+
const fields = await getFieldsCached(source.appId, client, cacheContext);
|
|
15505
|
+
if (!source.subtableCode) {
|
|
15506
|
+
return {
|
|
15507
|
+
kind: "APP",
|
|
15508
|
+
fieldCodes: fields.filter((field) => !field.inSubtable).map((field) => field.code)
|
|
15509
|
+
};
|
|
15510
|
+
}
|
|
15511
|
+
const exactChildren = fields.filter(
|
|
15512
|
+
(field) => field.inSubtable && field.subtableCode === source.subtableCode
|
|
15513
|
+
);
|
|
15514
|
+
const childFields = exactChildren.length > 0 ? exactChildren : fields.filter((field) => field.inSubtable && field.subtableCode === void 0);
|
|
15515
|
+
return {
|
|
15516
|
+
kind: "SUBTABLE",
|
|
15517
|
+
childFieldCodes: childFields.map((field) => field.code),
|
|
15518
|
+
parentFieldCodes: fields.filter((field) => !field.inSubtable).map((field) => field.code)
|
|
15519
|
+
};
|
|
15520
|
+
}));
|
|
15521
|
+
const schemas = resolvePlainGroupBySourceSchemas(
|
|
15522
|
+
stmt,
|
|
15523
|
+
(_source, sourceIndex) => inputs[sourceIndex]
|
|
15524
|
+
);
|
|
15525
|
+
const groupBy = stmt.groupBy;
|
|
15526
|
+
const plan = planPlainGroupByResolution(groupBy, stmt.columns, schemas);
|
|
15527
|
+
assertRuntimePlainGroupByPlan(stmt, groupBy, plan);
|
|
15528
|
+
return plan;
|
|
15529
|
+
}
|
|
15530
|
+
function assertRuntimePlainGroupByPlan(stmt, groupBy, plan) {
|
|
15531
|
+
const physicalAppIds = [
|
|
15532
|
+
stmt.from,
|
|
15533
|
+
...stmt.joins.map((join2) => join2.table)
|
|
15534
|
+
].flatMap((source) => source.cteName === null ? [source.appId] : []);
|
|
15535
|
+
const uniquePhysicalAppIds = [...new Set(physicalAppIds)];
|
|
15536
|
+
const primaryPhysicalAppId = uniquePhysicalAppIds.length === 1 ? uniquePhysicalAppIds[0] : stmt.from.cteName === null ? stmt.from.appId : null;
|
|
15537
|
+
plan.items.forEach((item, index) => {
|
|
15538
|
+
if (item.kind === "EXPRESSION" || item.kind === "PHYSICAL" || item.kind === "ALIAS_SAFE") return;
|
|
15539
|
+
const key = groupBy[index];
|
|
15540
|
+
const name = key?.type === "FIELD_NAME" ? key.name : "(expression)";
|
|
15541
|
+
if (item.kind === "UNKNOWN") {
|
|
15542
|
+
const appSuffix = primaryPhysicalAppId === null ? "" : ` (APP${primaryPhysicalAppId})`;
|
|
15543
|
+
throw new Error(`ArgumentError: unknown field code(s): ${item.name}${appSuffix}`);
|
|
15544
|
+
}
|
|
15545
|
+
if (item.kind === "ALIAS_REJECT") {
|
|
15546
|
+
if (item.reason === "DUPLICATE") {
|
|
15547
|
+
throw new Error(
|
|
15548
|
+
`ArgumentError: GROUP BY alias ${name} is ambiguous across multiple SELECT columns (reason=GROUP_BY_ALIAS_AMBIGUOUS).`
|
|
15549
|
+
);
|
|
15550
|
+
}
|
|
15551
|
+
if (item.reason === "POST_GROUP_ONLY") {
|
|
15552
|
+
throw new Error(
|
|
15553
|
+
`ArgumentError: GROUP BY alias ${name} requires post-group evaluation (reason=GROUP_BY_ALIAS_POST_GROUP_ONLY).`
|
|
15554
|
+
);
|
|
15555
|
+
}
|
|
15556
|
+
throw new Error(
|
|
15557
|
+
`ArgumentError: GROUP BY alias ${name} depends on aggregate evaluation (reason=GROUP_BY_ALIAS_AGGREGATE).`
|
|
15558
|
+
);
|
|
15559
|
+
}
|
|
15560
|
+
throw new Error(
|
|
15561
|
+
`InternalError: deferred GROUP BY field ${item.name} reached runtime planning.`
|
|
15562
|
+
);
|
|
15563
|
+
});
|
|
15564
|
+
}
|
|
15264
15565
|
var resolvedGroupingSpecs = /* @__PURE__ */ new WeakMap();
|
|
15265
15566
|
async function validateStatementGroupingPlanning(statement, client, cacheContext) {
|
|
15266
15567
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -16025,7 +16326,7 @@ function selectNeedsSourceColumnMeta(stmt) {
|
|
|
16025
16326
|
(column) => column.type === "FIELD" || column.type === "WILDCARD" || column.type === "PARENT_WILDCARD" || column.type === "CASE_COL" || column.type === "AGGREGATE" && (column.func === "MIN" || column.func === "MAX" || column.func === "MODE")
|
|
16026
16327
|
);
|
|
16027
16328
|
}
|
|
16028
|
-
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
|
|
16329
|
+
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables, forLibraryCapture = false) {
|
|
16029
16330
|
const physicalInfos = /* @__PURE__ */ new Map();
|
|
16030
16331
|
if (selectNeedsSourceColumnMeta(stmt)) {
|
|
16031
16332
|
await Promise.all(physicalSelectTables(stmt).map(async (table) => {
|
|
@@ -16035,6 +16336,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
16035
16336
|
}));
|
|
16036
16337
|
}
|
|
16037
16338
|
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
16339
|
+
const canExposePublicSource = forLibraryCapture && materializedTables === void 0 && tables.every((table) => table.cteName === null);
|
|
16038
16340
|
const resolveField2 = (ref) => {
|
|
16039
16341
|
if (ref.tableAlias !== null) {
|
|
16040
16342
|
if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
|
|
@@ -16064,18 +16366,33 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
16064
16366
|
});
|
|
16065
16367
|
return matches.length === 1 ? matches[0] : void 0;
|
|
16066
16368
|
};
|
|
16369
|
+
const resolvePublicSourceApp = (ref) => {
|
|
16370
|
+
if (!canExposePublicSource) return void 0;
|
|
16371
|
+
const matches = tables.filter((table) => {
|
|
16372
|
+
if (ref.tableAlias !== null && effectiveTableAlias(table) !== ref.tableAlias) return false;
|
|
16373
|
+
const fieldCode = fieldCodeForTypeLookup(table, ref.field);
|
|
16374
|
+
return physicalInfos.get(table.appId)?.has(fieldCode) === true || systemColumnMeta(ref.field) !== void 0;
|
|
16375
|
+
});
|
|
16376
|
+
return matches.length === 1 ? matches[0].appId : void 0;
|
|
16377
|
+
};
|
|
16378
|
+
const withPublicSource = (meta, ref) => {
|
|
16379
|
+
const publicSourceApp = resolvePublicSourceApp(ref);
|
|
16380
|
+
return meta && publicSourceApp !== void 0 ? { ...meta, publicSourceApp } : meta;
|
|
16381
|
+
};
|
|
16067
16382
|
const inferred = /* @__PURE__ */ new Map();
|
|
16068
16383
|
const hasWildcard = stmt.columns.some((column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD");
|
|
16069
16384
|
if (stmt.columns.length === 1 && (stmt.columns[0].type === "WILDCARD" || stmt.columns[0].type === "PARENT_WILDCARD")) {
|
|
16070
16385
|
for (const output of outputColumns) {
|
|
16071
|
-
const
|
|
16386
|
+
const ref = aggregateFieldRef(output);
|
|
16387
|
+
const meta = withPublicSource(resolveField2(ref), ref);
|
|
16072
16388
|
if (meta) inferred.set(output, meta);
|
|
16073
16389
|
}
|
|
16074
16390
|
return inferred;
|
|
16075
16391
|
}
|
|
16076
16392
|
if (hasWildcard) {
|
|
16077
16393
|
for (const output of outputColumns) {
|
|
16078
|
-
const
|
|
16394
|
+
const ref = aggregateFieldRef(output);
|
|
16395
|
+
const meta = withPublicSource(resolveField2(ref), ref);
|
|
16079
16396
|
if (meta) inferred.set(output, meta);
|
|
16080
16397
|
}
|
|
16081
16398
|
}
|
|
@@ -16087,7 +16404,8 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
16087
16404
|
if (!output) return;
|
|
16088
16405
|
let meta;
|
|
16089
16406
|
if (column.type === "FIELD") {
|
|
16090
|
-
|
|
16407
|
+
const ref = aggregateFieldRef(column.field);
|
|
16408
|
+
meta = withPublicSource(resolveField2(ref), ref);
|
|
16091
16409
|
} else if (column.type === "AGGREGATE") {
|
|
16092
16410
|
if (column.func === "GROUP_CONCAT") {
|
|
16093
16411
|
meta = syntheticColumnMeta("string");
|
|
@@ -16131,8 +16449,15 @@ function mergeUnionColumnMeta(left, right) {
|
|
|
16131
16449
|
const a = leftMeta?.get(column);
|
|
16132
16450
|
const rightColumn = right.columns[index];
|
|
16133
16451
|
const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
|
|
16134
|
-
if (a && b)
|
|
16135
|
-
|
|
16452
|
+
if (a && b) {
|
|
16453
|
+
const combined = mergeExpressionColumnMeta([a, b]);
|
|
16454
|
+
const publicSourceApp = a.publicSourceApp === b.publicSourceApp ? a.publicSourceApp : void 0;
|
|
16455
|
+
const { publicSourceApp: _discarded, ...withoutPublicSource } = combined;
|
|
16456
|
+
merged.set(
|
|
16457
|
+
column,
|
|
16458
|
+
publicSourceApp === void 0 ? withoutPublicSource : { ...withoutPublicSource, publicSourceApp }
|
|
16459
|
+
);
|
|
16460
|
+
} else if (a || b) merged.set(column, unknownStringColumnMeta());
|
|
16136
16461
|
});
|
|
16137
16462
|
return merged;
|
|
16138
16463
|
}
|
|
@@ -16168,7 +16493,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
|
|
|
16168
16493
|
};
|
|
16169
16494
|
return { row, having };
|
|
16170
16495
|
}
|
|
16171
|
-
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache, allowOriginalWherePushdown = true, preloadedOrderMeta, prefilterPlan) {
|
|
16496
|
+
async function executeFullScanSelect(stmt, client, options, cacheContext, cteCache, allowOriginalWherePushdown = true, preloadedOrderMeta, prefilterPlan, plainGroupByPlan) {
|
|
16172
16497
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
16173
16498
|
const warnings = /* @__PURE__ */ new Set();
|
|
16174
16499
|
const parallel = options.fetchParallel ?? 1;
|
|
@@ -16198,6 +16523,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16198
16523
|
throw new Error("internal error: relative-date prefilter must disable original WHERE pushdown.");
|
|
16199
16524
|
}
|
|
16200
16525
|
const mainFetchCondition = prefilterPlan ? prefilterPlan.prefilterWhere : mainPushDown;
|
|
16526
|
+
const scalarCache = await resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
16201
16527
|
const constantFalse = isConstantFalseWhere(stmt.where);
|
|
16202
16528
|
const mainFetch = constantFalse ? Promise.resolve([]) : fetchTableRecordsForFullScan(
|
|
16203
16529
|
stmt,
|
|
@@ -16209,7 +16535,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16209
16535
|
options.onLimitReached ?? "error",
|
|
16210
16536
|
warnings,
|
|
16211
16537
|
mainFetchCondition,
|
|
16212
|
-
allowOriginalWherePushdown
|
|
16538
|
+
allowOriginalWherePushdown,
|
|
16539
|
+
plainGroupByPlan
|
|
16213
16540
|
);
|
|
16214
16541
|
const parallelJoins = [];
|
|
16215
16542
|
const onOptJoins = [];
|
|
@@ -16231,17 +16558,16 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16231
16558
|
false,
|
|
16232
16559
|
options.onLimitReached ?? "error",
|
|
16233
16560
|
warnings,
|
|
16234
|
-
jCond
|
|
16561
|
+
jCond,
|
|
16562
|
+
true,
|
|
16563
|
+
plainGroupByPlan
|
|
16235
16564
|
)
|
|
16236
16565
|
});
|
|
16237
16566
|
} else {
|
|
16238
16567
|
onOptJoins.push(join2);
|
|
16239
16568
|
}
|
|
16240
16569
|
}
|
|
16241
|
-
const scalarCachePromise = resolveScalarColumns(stmt.columns, client, options, cacheContext, cteCache);
|
|
16242
16570
|
const orderByMetaPromise = preloadedOrderMeta ? Promise.resolve(preloadedOrderMeta) : buildOrderByMetaForSelect(stmt, client, cacheContext, cteCache);
|
|
16243
|
-
scalarCachePromise.catch(() => {
|
|
16244
|
-
});
|
|
16245
16571
|
orderByMetaPromise.catch(() => {
|
|
16246
16572
|
});
|
|
16247
16573
|
const mainRecords = await mainFetch;
|
|
@@ -16260,7 +16586,8 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16260
16586
|
parallel,
|
|
16261
16587
|
options.onLimitReached ?? "error",
|
|
16262
16588
|
warnings,
|
|
16263
|
-
null
|
|
16589
|
+
null,
|
|
16590
|
+
plainGroupByPlan
|
|
16264
16591
|
);
|
|
16265
16592
|
const joinRecords = optimized ?? await fetchTableRecordsForFullScan(
|
|
16266
16593
|
stmt,
|
|
@@ -16271,11 +16598,12 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16271
16598
|
false,
|
|
16272
16599
|
options.onLimitReached ?? "error",
|
|
16273
16600
|
warnings,
|
|
16274
|
-
null
|
|
16601
|
+
null,
|
|
16602
|
+
true,
|
|
16603
|
+
plainGroupByPlan
|
|
16275
16604
|
);
|
|
16276
16605
|
tables.set(join2.table.alias, joinRecords);
|
|
16277
16606
|
}));
|
|
16278
|
-
const scalarCache = await scalarCachePromise;
|
|
16279
16607
|
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
16280
16608
|
const { rows, columns } = runFullScan({
|
|
16281
16609
|
tables,
|
|
@@ -16291,14 +16619,15 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
|
|
|
16291
16619
|
aggregateSortKindResolver,
|
|
16292
16620
|
appliedKlikes: prefilterPlan?.appliedKlikes ?? pushdownPlan.appliedKlikes,
|
|
16293
16621
|
...prefilterPlan ? { residualWhere: prefilterPlan.residualWhere } : {},
|
|
16294
|
-
resolvedGroupingSpec: resolvedGroupingSpecs.get(stmt)
|
|
16622
|
+
resolvedGroupingSpec: resolvedGroupingSpecs.get(stmt),
|
|
16623
|
+
plainGroupByPlan
|
|
16295
16624
|
});
|
|
16296
16625
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
16297
16626
|
}
|
|
16298
|
-
async function executeUnion(stmt, client, options, cacheContext) {
|
|
16627
|
+
async function executeUnion(stmt, client, options, cacheContext, captureColumnMeta = false, forLibraryCapture = false) {
|
|
16299
16628
|
const [leftResult, rightResult] = await Promise.all([
|
|
16300
|
-
stmt.left.type === "UNION" ? executeUnion(stmt.left, client, options, cacheContext) : executeSelect(stmt.left, client, options, cacheContext),
|
|
16301
|
-
executeSelect(stmt.right, client, options, cacheContext)
|
|
16629
|
+
stmt.left.type === "UNION" ? executeUnion(stmt.left, client, options, cacheContext, captureColumnMeta, forLibraryCapture) : executeSelect(stmt.left, client, options, cacheContext, void 0, captureColumnMeta, forLibraryCapture),
|
|
16630
|
+
executeSelect(stmt.right, client, options, cacheContext, void 0, captureColumnMeta, forLibraryCapture)
|
|
16302
16631
|
]);
|
|
16303
16632
|
const leftCols = leftResult.columns;
|
|
16304
16633
|
const rightCols = rightResult.columns;
|
|
@@ -16311,7 +16640,11 @@ async function executeUnion(stmt, client, options, cacheContext) {
|
|
|
16311
16640
|
});
|
|
16312
16641
|
const combined = [...leftResult.rows, ...remappedRight];
|
|
16313
16642
|
const rows = stmt.all ? combined : deduplicateRows(combined, leftCols);
|
|
16314
|
-
|
|
16643
|
+
const result = { type: "SELECT", rows, columns: leftCols, rowCount: rows.length };
|
|
16644
|
+
if (captureColumnMeta) {
|
|
16645
|
+
materializedMetaBySelectResult.set(result, mergeUnionColumnMeta(leftResult, rightResult));
|
|
16646
|
+
}
|
|
16647
|
+
return result;
|
|
16315
16648
|
}
|
|
16316
16649
|
function deduplicateRows(rows, columns) {
|
|
16317
16650
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -16324,7 +16657,7 @@ function deduplicateRows(rows, columns) {
|
|
|
16324
16657
|
}
|
|
16325
16658
|
async function executeWith(stmt, client, options, cacheContext, seed, captureColumnMeta = false) {
|
|
16326
16659
|
if ((seed == null || seed.size === 0) && canInlineSingleCte(stmt)) {
|
|
16327
|
-
return executeSelect(buildInlinedQuery(stmt), client, options, cacheContext, void 0, captureColumnMeta);
|
|
16660
|
+
return executeSelect(buildInlinedQuery(stmt), client, options, cacheContext, void 0, captureColumnMeta, false);
|
|
16328
16661
|
}
|
|
16329
16662
|
const cteCache = new Map(seed ?? []);
|
|
16330
16663
|
for (const cte of stmt.ctes) {
|
|
@@ -16369,7 +16702,7 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
|
|
|
16369
16702
|
}
|
|
16370
16703
|
const hasCteRef = query.from.cteName != null && query.from.cteName !== NO_FROM_CTE_NAME || query.joins.some((j) => j.table.cteName != null);
|
|
16371
16704
|
if (!hasCteRef) {
|
|
16372
|
-
return executeSelect(query, client, options, cacheContext, cteCache, captureColumnMeta);
|
|
16705
|
+
return executeSelect(query, client, options, cacheContext, cteCache, captureColumnMeta, false);
|
|
16373
16706
|
}
|
|
16374
16707
|
const result = await executeFullScanWithCte(query, client, options, cteCache, cacheContext);
|
|
16375
16708
|
if (captureColumnMeta) {
|
|
@@ -16380,6 +16713,12 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
|
|
|
16380
16713
|
async function executeFullScanWithCte(stmt, client, options, cteCache, cacheContext) {
|
|
16381
16714
|
await validateSelectGroupingPlanning(stmt, client, cacheContext, cteCache);
|
|
16382
16715
|
const resolvedGroupingSpec = resolvedGroupingSpecs.get(stmt);
|
|
16716
|
+
const plainGroupByPlan = await buildRuntimePlainGroupByPlan(
|
|
16717
|
+
stmt,
|
|
16718
|
+
client,
|
|
16719
|
+
cacheContext,
|
|
16720
|
+
cteCache
|
|
16721
|
+
);
|
|
16383
16722
|
const hiddenQualifiedAliases = /* @__PURE__ */ new Set();
|
|
16384
16723
|
const withEffectiveAlias = (table) => {
|
|
16385
16724
|
if (table.alias !== null || table.cteName === null) return table;
|
|
@@ -16451,10 +16790,14 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
16451
16790
|
const havingFieldSemanticsResolver = buildHavingFieldSemanticsResolver(stmt, fieldSemanticsResolver);
|
|
16452
16791
|
const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
|
|
16453
16792
|
validateKlikePushdownPlan(pushdownPlan);
|
|
16454
|
-
const
|
|
16793
|
+
const scalarCache = await resolveScalarColumns(
|
|
16794
|
+
stmt.columns,
|
|
16795
|
+
client,
|
|
16796
|
+
effectiveOptions,
|
|
16797
|
+
cacheContext,
|
|
16798
|
+
cteCache
|
|
16799
|
+
);
|
|
16455
16800
|
const orderByMetaPromise = Promise.resolve(orderMeta);
|
|
16456
|
-
scalarCachePromise.catch(() => {
|
|
16457
|
-
});
|
|
16458
16801
|
orderByMetaPromise.catch(() => {
|
|
16459
16802
|
});
|
|
16460
16803
|
const tables = /* @__PURE__ */ new Map();
|
|
@@ -16474,7 +16817,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
16474
16817
|
effectiveOptions.onLimitReached ?? "error",
|
|
16475
16818
|
warnings,
|
|
16476
16819
|
pushdownPlan.mainCondition,
|
|
16477
|
-
whereCapability.capability === "EXACT_PUSHDOWN"
|
|
16820
|
+
whereCapability.capability === "EXACT_PUSHDOWN",
|
|
16821
|
+
plainGroupByPlan
|
|
16478
16822
|
));
|
|
16479
16823
|
tables.set(stmt.from.alias, mainRecords);
|
|
16480
16824
|
}
|
|
@@ -16494,7 +16838,8 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
16494
16838
|
parallel,
|
|
16495
16839
|
effectiveOptions.onLimitReached ?? "error",
|
|
16496
16840
|
warnings,
|
|
16497
|
-
pushDownCond
|
|
16841
|
+
pushDownCond,
|
|
16842
|
+
plainGroupByPlan
|
|
16498
16843
|
);
|
|
16499
16844
|
const joinRecords = optimized ?? await fetchTableRecordsForFullScan(
|
|
16500
16845
|
stmt,
|
|
@@ -16505,15 +16850,16 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
16505
16850
|
false,
|
|
16506
16851
|
effectiveOptions.onLimitReached ?? "error",
|
|
16507
16852
|
warnings,
|
|
16508
|
-
pushDownCond
|
|
16853
|
+
pushDownCond,
|
|
16854
|
+
true,
|
|
16855
|
+
plainGroupByPlan
|
|
16509
16856
|
);
|
|
16510
16857
|
tables.set(join2.table.alias, joinRecords);
|
|
16511
16858
|
}
|
|
16512
16859
|
}));
|
|
16513
16860
|
await Promise.all(joinFetches);
|
|
16514
|
-
const scalarCache = await scalarCachePromise;
|
|
16515
16861
|
const { optionOrders, sortKinds, semantics } = await orderByMetaPromise;
|
|
16516
|
-
const
|
|
16862
|
+
const sourceColumns2 = stmt.joins.length === 0 && stmt.from.cteName != null ? requireMaterializedTable(stmt.from.cteName).columns : void 0;
|
|
16517
16863
|
const { rows, columns } = runFullScan({
|
|
16518
16864
|
tables,
|
|
16519
16865
|
stmt,
|
|
@@ -16527,10 +16873,11 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
|
|
|
16527
16873
|
havingFieldSemanticsResolver,
|
|
16528
16874
|
aggregateSortKindResolver,
|
|
16529
16875
|
appliedKlikes: pushdownPlan.appliedKlikes,
|
|
16530
|
-
sourceColumns,
|
|
16876
|
+
sourceColumns: sourceColumns2,
|
|
16531
16877
|
tableColumns,
|
|
16532
16878
|
hiddenQualifiedAliases,
|
|
16533
|
-
resolvedGroupingSpec
|
|
16879
|
+
resolvedGroupingSpec,
|
|
16880
|
+
plainGroupByPlan
|
|
16534
16881
|
});
|
|
16535
16882
|
return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [...warnings] };
|
|
16536
16883
|
}
|
|
@@ -16539,8 +16886,8 @@ function processRowToKintoneRecord(row) {
|
|
|
16539
16886
|
Object.entries(row).map(([k, v]) => [k, { value: v ?? "" }])
|
|
16540
16887
|
);
|
|
16541
16888
|
}
|
|
16542
|
-
async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords, parallel, isMainTable, onLimit, warnings, pushDownCond = null, allowOriginalWherePushdown = true) {
|
|
16543
|
-
const fields = selectToFetchAllFields(stmt, table);
|
|
16889
|
+
async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords, parallel, isMainTable, onLimit, warnings, pushDownCond = null, allowOriginalWherePushdown = true, plainGroupByPlan) {
|
|
16890
|
+
const fields = selectToFetchAllFields(stmt, table, plainGroupByPlan);
|
|
16544
16891
|
const onTruncate = (max) => {
|
|
16545
16892
|
warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
|
|
16546
16893
|
};
|
|
@@ -16654,7 +17001,7 @@ function splitChunks(items, size) {
|
|
|
16654
17001
|
var JOIN_IN_CHUNK_SIZE = 50;
|
|
16655
17002
|
var JOIN_IN_MAX_CHUNKS = 6;
|
|
16656
17003
|
var JOIN_IN_MAX_KEYS = JOIN_IN_CHUNK_SIZE * JOIN_IN_MAX_CHUNKS;
|
|
16657
|
-
async function tryFetchJoinRecordsBySourceKeys(stmt, join2, tables, client, maxRecords, parallel, onLimit, warnings, pushDownCond = null) {
|
|
17004
|
+
async function tryFetchJoinRecordsBySourceKeys(stmt, join2, tables, client, maxRecords, parallel, onLimit, warnings, pushDownCond = null, plainGroupByPlan) {
|
|
16658
17005
|
if (join2.type !== "INNER") return null;
|
|
16659
17006
|
if (!join2.table.alias) return null;
|
|
16660
17007
|
if (join2.table.subtableCode) return null;
|
|
@@ -16691,7 +17038,7 @@ async function tryFetchJoinRecordsBySourceKeys(stmt, join2, tables, client, maxR
|
|
|
16691
17038
|
);
|
|
16692
17039
|
return null;
|
|
16693
17040
|
}
|
|
16694
|
-
const fields = selectToFetchAllFields(stmt, join2.table);
|
|
17041
|
+
const fields = selectToFetchAllFields(stmt, join2.table, plainGroupByPlan);
|
|
16695
17042
|
const onTruncate = (max) => {
|
|
16696
17043
|
warnings.add(`\u53D6\u5F97\u4E0A\u9650\uFF08${max} \u4EF6\uFF09\u306B\u9054\u3057\u305F\u305F\u3081\u3001${max} \u4EF6\u3067\u6253\u3061\u5207\u3063\u3066\u8868\u793A\u3057\u3066\u3044\u307E\u3059\u3002`);
|
|
16697
17044
|
};
|
|
@@ -16733,9 +17080,6 @@ function setScopedCacheValue(root, cacheContext, appId, value) {
|
|
|
16733
17080
|
}
|
|
16734
17081
|
scoped.set(appId, value);
|
|
16735
17082
|
}
|
|
16736
|
-
function isSystemLikeFieldCode(code) {
|
|
16737
|
-
return code.startsWith("_") || code.startsWith("$");
|
|
16738
|
-
}
|
|
16739
17083
|
async function getFieldsCached(appId, client, cacheContext) {
|
|
16740
17084
|
const cached = getScopedCacheValue(fieldInfoCache, cacheContext, appId);
|
|
16741
17085
|
if (cached) return cached;
|
|
@@ -19931,6 +20275,7 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
19931
20275
|
};
|
|
19932
20276
|
const capabilities = /* @__PURE__ */ new Map();
|
|
19933
20277
|
const orderPlans = /* @__PURE__ */ new Map();
|
|
20278
|
+
const plainGroupByPlans = /* @__PURE__ */ new Map();
|
|
19934
20279
|
const seen = /* @__PURE__ */ new Set();
|
|
19935
20280
|
const sharedRelativeDatePlan = relativeDatePlan ?? await resolveRelativeDateExecutionPlan(query, tracedClient, cacheContext);
|
|
19936
20281
|
const relativeNodeFor = (source) => sharedRelativeDatePlan.nodes.find(
|
|
@@ -19948,6 +20293,15 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
19948
20293
|
if (typed["type"] === "SELECT") {
|
|
19949
20294
|
const select = node;
|
|
19950
20295
|
await validateSelectGroupingPlanning(select, tracedClient, cacheContext);
|
|
20296
|
+
const hasUnmaterializedSource = [select.from, ...select.joins.map((join2) => join2.table)].some((table) => table.cteName !== null);
|
|
20297
|
+
if (normalizeGroupingSpec(select).type === "PLAIN" && !hasUnmaterializedSource) {
|
|
20298
|
+
const plainPlan = await buildRuntimePlainGroupByPlan(
|
|
20299
|
+
select,
|
|
20300
|
+
tracedClient,
|
|
20301
|
+
cacheContext
|
|
20302
|
+
);
|
|
20303
|
+
if (plainPlan) plainGroupByPlans.set(select, plainPlan);
|
|
20304
|
+
}
|
|
19951
20305
|
const physicalApps = [select.from, ...select.joins.map((join2) => join2.table)].filter((table) => table.cteName === null).map((table) => table.appId);
|
|
19952
20306
|
const needsWhereSchema = whereNeedsFieldMetadata(select.where);
|
|
19953
20307
|
if (needsWhereSchema || select.orderBy.length > 0 || select.columns.some((column) => column.type === "WINDOW_COL" && column.orderBy.length > 0)) {
|
|
@@ -19968,7 +20322,6 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
19968
20322
|
}
|
|
19969
20323
|
}
|
|
19970
20324
|
}
|
|
19971
|
-
const hasUnmaterializedSource = [select.from, ...select.joins.map((join2) => join2.table)].some((table) => table.cteName !== null);
|
|
19972
20325
|
if (hasCanonicalOrder(select) && !hasUnmaterializedSource && relativeNode?.allowed !== false) {
|
|
19973
20326
|
const mode = capability.capability === "EXACT_PUSHDOWN" ? resolveSelectMode(select) : "FULL_SCAN";
|
|
19974
20327
|
orderPlans.set(select, (select.orderMode === "KINTONE_NATIVE" ? planKorder : planCanonicalOrder)({
|
|
@@ -20082,6 +20435,7 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
20082
20435
|
return {
|
|
20083
20436
|
capabilities,
|
|
20084
20437
|
orderPlans,
|
|
20438
|
+
plainGroupByPlans,
|
|
20085
20439
|
fieldApps,
|
|
20086
20440
|
processStatusApps,
|
|
20087
20441
|
numberPrecisionApps,
|
|
@@ -20405,7 +20759,8 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
|
|
|
20405
20759
|
analysis.orderPlans,
|
|
20406
20760
|
dmlMaxRows,
|
|
20407
20761
|
dmlMaxSubtableRows,
|
|
20408
|
-
maxRecords
|
|
20762
|
+
maxRecords,
|
|
20763
|
+
analysis.plainGroupByPlans
|
|
20409
20764
|
),
|
|
20410
20765
|
cursorMaxActive
|
|
20411
20766
|
)
|
|
@@ -20428,13 +20783,13 @@ function addCursorConcurrency(lines, cursorMaxActive) {
|
|
|
20428
20783
|
}
|
|
20429
20784
|
return result;
|
|
20430
20785
|
}
|
|
20431
|
-
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4) {
|
|
20432
|
-
if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans);
|
|
20433
|
-
if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans);
|
|
20786
|
+
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans) {
|
|
20787
|
+
if (query.type === "UNION") return buildUnionPlan(query, capabilities, orderPlans, plainGroupByPlans);
|
|
20788
|
+
if (query.type === "WITH") return buildWithPlan(query, capabilities, orderPlans, plainGroupByPlans);
|
|
20434
20789
|
if (query.type === "INSERT") return buildInsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
|
|
20435
|
-
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans);
|
|
20790
|
+
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
|
|
20436
20791
|
if (query.type === "UPSERT") return buildUpsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
|
|
20437
|
-
if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label, capabilities, orderPlans);
|
|
20792
|
+
if (query.type === "UPSERT_SELECT") return buildUpsertSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
|
|
20438
20793
|
if (query.type === "UPDATE") return buildUpdatePlan(
|
|
20439
20794
|
query,
|
|
20440
20795
|
label,
|
|
@@ -20520,7 +20875,7 @@ function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 1
|
|
|
20520
20875
|
` duplicateKey: preflight before lookup/write (requires load)`
|
|
20521
20876
|
];
|
|
20522
20877
|
}
|
|
20523
|
-
return buildSelectPlan(query, label, capabilities, orderPlans);
|
|
20878
|
+
return buildSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
|
|
20524
20879
|
}
|
|
20525
20880
|
function buildValidatePlan(stmt, label) {
|
|
20526
20881
|
const info = validateExplainInfo.get(stmt);
|
|
@@ -20547,9 +20902,10 @@ function buildValidatePlan(stmt, label) {
|
|
|
20547
20902
|
lines.push(" records/mutation API during EXPLAIN: none; violation count unavailable");
|
|
20548
20903
|
return lines;
|
|
20549
20904
|
}
|
|
20550
|
-
function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
20905
|
+
function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans) {
|
|
20551
20906
|
const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
20552
20907
|
const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
20908
|
+
const plainGroupByPlan = plainGroupByPlans?.get(stmt) ?? (plainGroupByPlans ? [...plainGroupByPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
20553
20909
|
const mode = orderPlan?.kind === "CANONICAL_LOCAL" ? "FULL_SCAN" : whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN" ? "FULL_SCAN" : resolveSelectMode(stmt);
|
|
20554
20910
|
const reasons = collectFullScanReasons(stmt);
|
|
20555
20911
|
if (whereCapability && whereCapability.capability !== "EXACT_PUSHDOWN") {
|
|
@@ -20574,6 +20930,29 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20574
20930
|
` grouping output rows: runtime checked (limit: ${groupingMetadata.outputRowLimit}, before HAVING/DISTINCT/LIMIT)`
|
|
20575
20931
|
);
|
|
20576
20932
|
}
|
|
20933
|
+
const normalizedGrouping = normalizeGroupingSpec(stmt);
|
|
20934
|
+
if (normalizedGrouping.type === "PLAIN") {
|
|
20935
|
+
const groupBy = normalizedGrouping.allItems;
|
|
20936
|
+
if (plainGroupByPlan) {
|
|
20937
|
+
plainGroupByPlan.items.forEach((item, index) => {
|
|
20938
|
+
const key = groupBy[index];
|
|
20939
|
+
if (key?.type !== "FIELD_NAME") return;
|
|
20940
|
+
if (item.kind === "PHYSICAL") {
|
|
20941
|
+
lines.push(
|
|
20942
|
+
` group key ${key.name}: PHYSICAL (source=${item.sourceIndex}, field=${item.fieldCode})`
|
|
20943
|
+
);
|
|
20944
|
+
}
|
|
20945
|
+
});
|
|
20946
|
+
} else if ([stmt.from, ...stmt.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)) {
|
|
20947
|
+
for (const key of groupBy) {
|
|
20948
|
+
if (key.type === "FIELD_NAME") {
|
|
20949
|
+
lines.push(
|
|
20950
|
+
` group key ${key.name}: DEFERRED (materialized schema unavailable)`
|
|
20951
|
+
);
|
|
20952
|
+
}
|
|
20953
|
+
}
|
|
20954
|
+
}
|
|
20955
|
+
}
|
|
20577
20956
|
if (orderPlan) {
|
|
20578
20957
|
lines.push(` order plan: ${orderPlan.kind}`);
|
|
20579
20958
|
if (orderPlan.reasonCodes.length > 0) lines.push(` order reason: ${orderPlan.reasonCodes.join(", ")}`);
|
|
@@ -20615,7 +20994,7 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20615
20994
|
lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
|
|
20616
20995
|
} else {
|
|
20617
20996
|
const pushdownPlan = buildKlikePushdownPlan(stmt);
|
|
20618
|
-
const mainFields = selectToFetchAllFields(stmt, stmt.from);
|
|
20997
|
+
const mainFields = selectToFetchAllFields(stmt, stmt.from, plainGroupByPlan);
|
|
20619
20998
|
const mainAliasStr = stmt.from.alias ? ` AS ${stmt.from.alias}` : "";
|
|
20620
20999
|
const mainPushDown = pushdownPlan.mainCondition;
|
|
20621
21000
|
const mainCandidate = extractMainTypedPushdownCandidate(stmt);
|
|
@@ -20628,7 +21007,7 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20628
21007
|
}
|
|
20629
21008
|
lines.push(` fields: ${mainFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : mainFields.join(", ")}`);
|
|
20630
21009
|
for (const join2 of stmt.joins) {
|
|
20631
|
-
const joinFields = selectToFetchAllFields(stmt, join2.table);
|
|
21010
|
+
const joinFields = selectToFetchAllFields(stmt, join2.table, plainGroupByPlan);
|
|
20632
21011
|
const joinAliasStr = join2.table.alias ? ` AS ${join2.table.alias}` : "";
|
|
20633
21012
|
const joinType = join2.type === "INNER" ? "JOIN" : `${join2.type} JOIN`;
|
|
20634
21013
|
const joinPushDown = join2.table.alias ? pushdownPlan.joinConditions.get(join2.table.alias) ?? null : null;
|
|
@@ -20642,10 +21021,10 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20642
21021
|
lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
|
|
20643
21022
|
}
|
|
20644
21023
|
}
|
|
20645
|
-
lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans));
|
|
21024
|
+
lines.push(...collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans));
|
|
20646
21025
|
return lines;
|
|
20647
21026
|
}
|
|
20648
|
-
function buildUnionPlan(stmt, capabilities, orderPlans) {
|
|
21027
|
+
function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
20649
21028
|
const selects = [];
|
|
20650
21029
|
const collect = (u) => {
|
|
20651
21030
|
if (u.type === "SELECT") {
|
|
@@ -20659,25 +21038,34 @@ function buildUnionPlan(stmt, capabilities, orderPlans) {
|
|
|
20659
21038
|
const lines = [];
|
|
20660
21039
|
selects.forEach((sel, i) => {
|
|
20661
21040
|
if (i > 0) lines.push("");
|
|
20662
|
-
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans));
|
|
21041
|
+
lines.push(...buildSelectPlan(sel, `[union:${i + 1}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20663
21042
|
});
|
|
20664
21043
|
return lines;
|
|
20665
21044
|
}
|
|
20666
|
-
function buildWithPlan(stmt, capabilities, orderPlans) {
|
|
21045
|
+
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
20667
21046
|
const lines = [];
|
|
20668
21047
|
for (const cte of stmt.ctes) {
|
|
20669
21048
|
if (cte.query.type === "SELECT") {
|
|
20670
|
-
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans));
|
|
21049
|
+
lines.push(...buildSelectPlan(cte.query, `[cte: ${cte.name}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20671
21050
|
lines.push("");
|
|
20672
21051
|
}
|
|
20673
21052
|
}
|
|
20674
21053
|
if (stmt.query.type === "SELECT" || stmt.query.type === "UNION") {
|
|
20675
|
-
lines.push(...buildExplainPlan(
|
|
21054
|
+
lines.push(...buildExplainPlan(
|
|
21055
|
+
stmt.query,
|
|
21056
|
+
"[main]",
|
|
21057
|
+
capabilities,
|
|
21058
|
+
orderPlans,
|
|
21059
|
+
100,
|
|
21060
|
+
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
21061
|
+
1e4,
|
|
21062
|
+
plainGroupByPlans
|
|
21063
|
+
));
|
|
20676
21064
|
}
|
|
20677
21065
|
if (canInlineSingleCte(stmt)) {
|
|
20678
21066
|
lines.push("");
|
|
20679
21067
|
const inlined = buildInlinedQuery(stmt);
|
|
20680
|
-
lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans));
|
|
21068
|
+
lines.push(...buildSelectPlan(inlined, "[effective: inlined CTE]", capabilities, orderPlans, plainGroupByPlans));
|
|
20681
21069
|
}
|
|
20682
21070
|
return lines;
|
|
20683
21071
|
}
|
|
@@ -20710,7 +21098,7 @@ function collectFullScanReasons(stmt) {
|
|
|
20710
21098
|
r.push("ORDER BY \u306B\u5F0F");
|
|
20711
21099
|
return r;
|
|
20712
21100
|
}
|
|
20713
|
-
function collectSubqueryPlans(stmt, capabilities, orderPlans) {
|
|
21101
|
+
function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
20714
21102
|
const lines = [];
|
|
20715
21103
|
let idx = 1;
|
|
20716
21104
|
const visitWhere = (w) => {
|
|
@@ -20719,16 +21107,16 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans) {
|
|
|
20719
21107
|
case "BINARY":
|
|
20720
21108
|
if (w.right.type === "SCALAR_SUBQUERY") {
|
|
20721
21109
|
lines.push("");
|
|
20722
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
21110
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20723
21111
|
}
|
|
20724
21112
|
if (w.right.type === "SUBQUERY_IN_LIST") {
|
|
20725
21113
|
lines.push("");
|
|
20726
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
21114
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20727
21115
|
}
|
|
20728
21116
|
break;
|
|
20729
21117
|
case "EXISTS":
|
|
20730
21118
|
lines.push("");
|
|
20731
|
-
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
21119
|
+
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20732
21120
|
break;
|
|
20733
21121
|
case "LOGICAL":
|
|
20734
21122
|
visitWhere(w.left);
|
|
@@ -20748,7 +21136,7 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans) {
|
|
|
20748
21136
|
for (const col of stmt.columns) {
|
|
20749
21137
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
20750
21138
|
lines.push("");
|
|
20751
|
-
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans));
|
|
21139
|
+
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans));
|
|
20752
21140
|
}
|
|
20753
21141
|
}
|
|
20754
21142
|
if (stmt.having) visitWhere(stmt.having);
|
|
@@ -20766,7 +21154,7 @@ function buildInsertPlan(stmt, label, dmlMaxRows = DEFAULT_APPLY_MAX_ROWS, dmlMa
|
|
|
20766
21154
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
20767
21155
|
return stmt.applyBlocks?.length ? [...lines, ...formatStaticApplyDiagnostic(buildStaticApplyDiagnostic(stmt, dmlMaxRows, dmlMaxSubtableRows))] : lines;
|
|
20768
21156
|
}
|
|
20769
|
-
function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
21157
|
+
function buildInsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans) {
|
|
20770
21158
|
const lines = [];
|
|
20771
21159
|
if (label) lines.push(label);
|
|
20772
21160
|
lines.push(` [INSERT SELECT]`);
|
|
@@ -20774,7 +21162,7 @@ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20774
21162
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
20775
21163
|
lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
|
|
20776
21164
|
lines.push("");
|
|
20777
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
21165
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans, plainGroupByPlans));
|
|
20778
21166
|
return lines;
|
|
20779
21167
|
}
|
|
20780
21168
|
function buildUpdatePlan(stmt, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4) {
|
|
@@ -20928,7 +21316,7 @@ function formatStaticApplyDiagnostic(diagnostic2) {
|
|
|
20928
21316
|
lines.push("records API: 0", "mutation API: 0");
|
|
20929
21317
|
return lines;
|
|
20930
21318
|
}
|
|
20931
|
-
function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
21319
|
+
function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans) {
|
|
20932
21320
|
const lines = [
|
|
20933
21321
|
...label ? [label] : [],
|
|
20934
21322
|
` [UPSERT SELECT]`,
|
|
@@ -20938,7 +21326,7 @@ function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans) {
|
|
|
20938
21326
|
` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
|
|
20939
21327
|
``
|
|
20940
21328
|
];
|
|
20941
|
-
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans));
|
|
21329
|
+
lines.push(...buildSelectPlan(stmt.select, "[source SELECT]", capabilities, orderPlans, plainGroupByPlans));
|
|
20942
21330
|
return lines;
|
|
20943
21331
|
}
|
|
20944
21332
|
function buildReorderPlan(stmt, label) {
|