@rex0220/kintone-sql-tools 3.17.0 → 3.18.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 +551 -370
- package/dist-mcp/ksql-mcp.js +561 -380
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -584,6 +584,87 @@ function numberLiteralText(node) {
|
|
|
584
584
|
return toPlainDecimal(source) ?? source;
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
+
// src/core/grouping.ts
|
|
588
|
+
var B65_MAX_GROUPING_SETS = 64;
|
|
589
|
+
var B65_MAX_GROUPING_ITEMS = 16;
|
|
590
|
+
var B65_MAX_GENERATED_ROWS = 5e4;
|
|
591
|
+
function expandCubeGroupingSets(items) {
|
|
592
|
+
let expandedSetCount = 1;
|
|
593
|
+
for (const _item of items) {
|
|
594
|
+
if (expandedSetCount > Math.floor(B65_MAX_GROUPING_SETS / 2)) {
|
|
595
|
+
const rejectedSetCount = expandedSetCount * 2;
|
|
596
|
+
throw new Error(
|
|
597
|
+
`ArgumentError: B65 expanded grouping set count ${rejectedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
expandedSetCount *= 2;
|
|
601
|
+
}
|
|
602
|
+
let sets = [{ items: [] }];
|
|
603
|
+
for (const item of items) {
|
|
604
|
+
sets = sets.flatMap((set) => [
|
|
605
|
+
{ items: [...set.items, item] },
|
|
606
|
+
{ items: [...set.items] }
|
|
607
|
+
]);
|
|
608
|
+
}
|
|
609
|
+
return sets;
|
|
610
|
+
}
|
|
611
|
+
function groupingFieldSyntaxKey(item) {
|
|
612
|
+
return `${item.tableAlias ?? ""}\0${item.field}`;
|
|
613
|
+
}
|
|
614
|
+
function normalizeGroupingSpec(stmt) {
|
|
615
|
+
if (stmt.grouping !== void 0 && stmt.groupBy.length > 0) {
|
|
616
|
+
throw new Error("internal error: SELECT cannot contain both groupBy and grouping.");
|
|
617
|
+
}
|
|
618
|
+
if (stmt.grouping === void 0) {
|
|
619
|
+
return stmt.groupBy.length === 0 ? { type: "NONE" } : { type: "PLAIN", allItems: stmt.groupBy, sets: [stmt.groupBy] };
|
|
620
|
+
}
|
|
621
|
+
const seen = /* @__PURE__ */ new Set();
|
|
622
|
+
const allItems = [];
|
|
623
|
+
for (const set of stmt.grouping.sets) {
|
|
624
|
+
for (const item of set.items) {
|
|
625
|
+
const key = groupingFieldSyntaxKey(item);
|
|
626
|
+
if (seen.has(key)) continue;
|
|
627
|
+
seen.add(key);
|
|
628
|
+
allItems.push(item);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
const sets = stmt.grouping.sets.map((set) => ({ items: [...set.items] }));
|
|
632
|
+
return {
|
|
633
|
+
type: "GROUPING_SETS",
|
|
634
|
+
source: stmt.grouping.source,
|
|
635
|
+
allItems,
|
|
636
|
+
sets
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function hasGroupingClause(stmt) {
|
|
640
|
+
return normalizeGroupingSpec(stmt).type !== "NONE";
|
|
641
|
+
}
|
|
642
|
+
function resolveGroupingSpec(stmt, resolve2) {
|
|
643
|
+
const normalized = normalizeGroupingSpec(stmt);
|
|
644
|
+
if (normalized.type !== "GROUPING_SETS") return null;
|
|
645
|
+
const byCanonicalId = /* @__PURE__ */ new Map();
|
|
646
|
+
const resolveItem = (field) => {
|
|
647
|
+
const resolved = resolve2(field);
|
|
648
|
+
const existing = byCanonicalId.get(resolved.canonicalId);
|
|
649
|
+
if (existing) return existing;
|
|
650
|
+
const item = { ...resolved, field };
|
|
651
|
+
byCanonicalId.set(item.canonicalId, item);
|
|
652
|
+
return item;
|
|
653
|
+
};
|
|
654
|
+
const allItems = normalized.allItems.map(resolveItem).filter(
|
|
655
|
+
(item, index, items) => items.findIndex((candidate) => candidate.canonicalId === item.canonicalId) === index
|
|
656
|
+
);
|
|
657
|
+
const sets = normalized.sets.map((set) => ({
|
|
658
|
+
items: set.items.map(resolveItem)
|
|
659
|
+
}));
|
|
660
|
+
return {
|
|
661
|
+
type: "GROUPING_SETS",
|
|
662
|
+
source: normalized.source,
|
|
663
|
+
allItems,
|
|
664
|
+
sets
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
587
668
|
// src/core/aggregateExpression.ts
|
|
588
669
|
function quote(value) {
|
|
589
670
|
return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -906,8 +987,8 @@ var Parser = class {
|
|
|
906
987
|
this.scalarAllowsCase = true;
|
|
907
988
|
this.pos = 0;
|
|
908
989
|
this.insideAggregateArg = 0;
|
|
909
|
-
/** GROUPING(field) is
|
|
910
|
-
this.
|
|
990
|
+
/** GROUPING(field) is limited to the explicitly selected query context. */
|
|
991
|
+
this.groupingFieldContext = "FORBIDDEN";
|
|
911
992
|
/** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
|
|
912
993
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
913
994
|
/** パース中に出現した一時テーブル参照(#name)のトークン。単文 API での拒否に使う */
|
|
@@ -1652,7 +1733,7 @@ var Parser = class {
|
|
|
1652
1733
|
} else if (this.isRollupStart()) {
|
|
1653
1734
|
grouping = this.parseRollupClause();
|
|
1654
1735
|
} else if (this.isCubeStart()) {
|
|
1655
|
-
|
|
1736
|
+
grouping = this.parseCubeClause();
|
|
1656
1737
|
} else {
|
|
1657
1738
|
groupBy = this.parseGroupByKeys();
|
|
1658
1739
|
}
|
|
@@ -1660,7 +1741,7 @@ var Parser = class {
|
|
|
1660
1741
|
throw new ParseError("B65: ordinary GROUP BY items cannot be mixed with grouping elements.", this.peek());
|
|
1661
1742
|
}
|
|
1662
1743
|
if (this.consume("HAVING" /* HAVING */)) {
|
|
1663
|
-
having = this.parseWhereExpr();
|
|
1744
|
+
having = this.parseWhereExpr("HAVING");
|
|
1664
1745
|
}
|
|
1665
1746
|
}
|
|
1666
1747
|
let orderMode = "CANONICAL";
|
|
@@ -2188,12 +2269,7 @@ var Parser = class {
|
|
|
2188
2269
|
}
|
|
2189
2270
|
parseCaseCondition(allowGroupingCondition) {
|
|
2190
2271
|
if (!allowGroupingCondition) return this.parseWhereExpr();
|
|
2191
|
-
this.
|
|
2192
|
-
try {
|
|
2193
|
-
return this.parseWhereExpr();
|
|
2194
|
-
} finally {
|
|
2195
|
-
this.groupingFieldAllowedDepth--;
|
|
2196
|
-
}
|
|
2272
|
+
return this.parseWhereExpr("SELECT_CASE");
|
|
2197
2273
|
}
|
|
2198
2274
|
/** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
|
|
2199
2275
|
parseCaseResult() {
|
|
@@ -2510,8 +2586,14 @@ var Parser = class {
|
|
|
2510
2586
|
// ----------------------------------------------------------
|
|
2511
2587
|
// WHERE 式(再帰下降・優先順位付き)
|
|
2512
2588
|
// ----------------------------------------------------------
|
|
2513
|
-
parseWhereExpr() {
|
|
2514
|
-
|
|
2589
|
+
parseWhereExpr(groupingFieldContext = this.groupingFieldContext) {
|
|
2590
|
+
const previousContext = this.groupingFieldContext;
|
|
2591
|
+
this.groupingFieldContext = groupingFieldContext;
|
|
2592
|
+
try {
|
|
2593
|
+
return this.parseOrExpr();
|
|
2594
|
+
} finally {
|
|
2595
|
+
this.groupingFieldContext = previousContext;
|
|
2596
|
+
}
|
|
2515
2597
|
}
|
|
2516
2598
|
// OR(最低優先度)
|
|
2517
2599
|
parseOrExpr() {
|
|
@@ -2680,9 +2762,9 @@ var Parser = class {
|
|
|
2680
2762
|
throw new ParseError("B65: GROUPING_ID is not supported in Phase1.", this.peek());
|
|
2681
2763
|
}
|
|
2682
2764
|
if (this.isGroupingFunctionStart()) {
|
|
2683
|
-
if (this.
|
|
2765
|
+
if (this.groupingFieldContext === "FORBIDDEN" || this.insideAggregateArg > 0) {
|
|
2684
2766
|
throw new ParseError(
|
|
2685
|
-
"B65: GROUPING() is only allowed in SELECT, SELECT CASE conditions, and direct ORDER BY.",
|
|
2767
|
+
"B65: GROUPING() is only allowed in SELECT, SELECT CASE conditions, HAVING, and direct ORDER BY.",
|
|
2686
2768
|
this.peek()
|
|
2687
2769
|
);
|
|
2688
2770
|
}
|
|
@@ -2942,6 +3024,25 @@ var Parser = class {
|
|
|
2942
3024
|
sets
|
|
2943
3025
|
};
|
|
2944
3026
|
}
|
|
3027
|
+
parseCubeClause() {
|
|
3028
|
+
this.advance();
|
|
3029
|
+
this.expect("(" /* LPAREN */);
|
|
3030
|
+
if (this.peek().kind === ")" /* RPAREN */) {
|
|
3031
|
+
throw new ParseError("B65: CUBE requires at least one field.", this.peek());
|
|
3032
|
+
}
|
|
3033
|
+
const items = [];
|
|
3034
|
+
do {
|
|
3035
|
+
items.push(this.parseGroupingFieldItem());
|
|
3036
|
+
} while (this.consume("," /* COMMA */));
|
|
3037
|
+
this.expect(")" /* RPAREN */);
|
|
3038
|
+
const sets = expandCubeGroupingSets(items);
|
|
3039
|
+
return {
|
|
3040
|
+
type: "GROUPING_SETS",
|
|
3041
|
+
source: "CUBE",
|
|
3042
|
+
allItems: this.groupingAllItems(sets),
|
|
3043
|
+
sets
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
2945
3046
|
parseGroupingRef() {
|
|
2946
3047
|
const start = this.advance();
|
|
2947
3048
|
this.expect("(" /* LPAREN */);
|
|
@@ -3930,67 +4031,6 @@ function extractTableRef(name, tok) {
|
|
|
3930
4031
|
return { appId: Number(m[1]), subtableCode: m[2] ?? null };
|
|
3931
4032
|
}
|
|
3932
4033
|
|
|
3933
|
-
// src/core/grouping.ts
|
|
3934
|
-
var B65_MAX_GROUPING_SETS = 64;
|
|
3935
|
-
var B65_MAX_GROUPING_ITEMS = 16;
|
|
3936
|
-
var B65_MAX_GENERATED_ROWS = 5e4;
|
|
3937
|
-
function groupingFieldSyntaxKey(item) {
|
|
3938
|
-
return `${item.tableAlias ?? ""}\0${item.field}`;
|
|
3939
|
-
}
|
|
3940
|
-
function normalizeGroupingSpec(stmt) {
|
|
3941
|
-
if (stmt.grouping !== void 0 && stmt.groupBy.length > 0) {
|
|
3942
|
-
throw new Error("internal error: SELECT cannot contain both groupBy and grouping.");
|
|
3943
|
-
}
|
|
3944
|
-
if (stmt.grouping === void 0) {
|
|
3945
|
-
return stmt.groupBy.length === 0 ? { type: "NONE" } : { type: "PLAIN", allItems: stmt.groupBy, sets: [stmt.groupBy] };
|
|
3946
|
-
}
|
|
3947
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3948
|
-
const allItems = [];
|
|
3949
|
-
for (const set of stmt.grouping.sets) {
|
|
3950
|
-
for (const item of set.items) {
|
|
3951
|
-
const key = groupingFieldSyntaxKey(item);
|
|
3952
|
-
if (seen.has(key)) continue;
|
|
3953
|
-
seen.add(key);
|
|
3954
|
-
allItems.push(item);
|
|
3955
|
-
}
|
|
3956
|
-
}
|
|
3957
|
-
const sets = stmt.grouping.sets.map((set) => ({ items: [...set.items] }));
|
|
3958
|
-
return {
|
|
3959
|
-
type: "GROUPING_SETS",
|
|
3960
|
-
source: stmt.grouping.source,
|
|
3961
|
-
allItems,
|
|
3962
|
-
sets
|
|
3963
|
-
};
|
|
3964
|
-
}
|
|
3965
|
-
function hasGroupingClause(stmt) {
|
|
3966
|
-
return normalizeGroupingSpec(stmt).type !== "NONE";
|
|
3967
|
-
}
|
|
3968
|
-
function resolveGroupingSpec(stmt, resolve2) {
|
|
3969
|
-
const normalized = normalizeGroupingSpec(stmt);
|
|
3970
|
-
if (normalized.type !== "GROUPING_SETS") return null;
|
|
3971
|
-
const byCanonicalId = /* @__PURE__ */ new Map();
|
|
3972
|
-
const resolveItem = (field) => {
|
|
3973
|
-
const resolved = resolve2(field);
|
|
3974
|
-
const existing = byCanonicalId.get(resolved.canonicalId);
|
|
3975
|
-
if (existing) return existing;
|
|
3976
|
-
const item = { ...resolved, field };
|
|
3977
|
-
byCanonicalId.set(item.canonicalId, item);
|
|
3978
|
-
return item;
|
|
3979
|
-
};
|
|
3980
|
-
const allItems = normalized.allItems.map(resolveItem).filter(
|
|
3981
|
-
(item, index, items) => items.findIndex((candidate) => candidate.canonicalId === item.canonicalId) === index
|
|
3982
|
-
);
|
|
3983
|
-
const sets = normalized.sets.map((set) => ({
|
|
3984
|
-
items: set.items.map(resolveItem)
|
|
3985
|
-
}));
|
|
3986
|
-
return {
|
|
3987
|
-
type: "GROUPING_SETS",
|
|
3988
|
-
source: normalized.source,
|
|
3989
|
-
allItems,
|
|
3990
|
-
sets
|
|
3991
|
-
};
|
|
3992
|
-
}
|
|
3993
|
-
|
|
3994
4034
|
// src/core/dmlGuard.ts
|
|
3995
4035
|
function getStatementType(stmt) {
|
|
3996
4036
|
if (!stmt || typeof stmt !== "object") return "UNKNOWN";
|
|
@@ -5926,6 +5966,272 @@ function isSelectObject(value) {
|
|
|
5926
5966
|
return value !== null && typeof value === "object" && value.type === "SELECT";
|
|
5927
5967
|
}
|
|
5928
5968
|
|
|
5969
|
+
// src/engine/groupingRowMeta.ts
|
|
5970
|
+
var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
|
|
5971
|
+
var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
|
|
5972
|
+
function attachGroupingRowMeta(row, includedCanonicalIds) {
|
|
5973
|
+
Object.defineProperty(row, groupingRowMetaKey, {
|
|
5974
|
+
value: { includedCanonicalIds },
|
|
5975
|
+
enumerable: false,
|
|
5976
|
+
configurable: false,
|
|
5977
|
+
writable: false
|
|
5978
|
+
});
|
|
5979
|
+
return row;
|
|
5980
|
+
}
|
|
5981
|
+
function getGroupingRowMeta(row) {
|
|
5982
|
+
return row[groupingRowMetaKey];
|
|
5983
|
+
}
|
|
5984
|
+
function readGroupingMembership(row) {
|
|
5985
|
+
return getGroupingRowMeta(row)?.includedCanonicalIds;
|
|
5986
|
+
}
|
|
5987
|
+
function bindGroupingRefCanonicalId(ref, canonicalId) {
|
|
5988
|
+
groupingRefCanonicalIds.set(ref, canonicalId);
|
|
5989
|
+
}
|
|
5990
|
+
function evalGroupingRef(ref, row) {
|
|
5991
|
+
const membership = readGroupingMembership(row);
|
|
5992
|
+
if (!membership) {
|
|
5993
|
+
throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
|
|
5994
|
+
}
|
|
5995
|
+
const canonicalId = groupingRefCanonicalIds.get(ref);
|
|
5996
|
+
if (!canonicalId) {
|
|
5997
|
+
throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
|
|
5998
|
+
}
|
|
5999
|
+
return membership.has(canonicalId) ? "0" : "1";
|
|
6000
|
+
}
|
|
6001
|
+
|
|
6002
|
+
// src/core/groupingValidation.ts
|
|
6003
|
+
var enforceGroupingPlanningCandidateLimits = (facts) => {
|
|
6004
|
+
if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
|
|
6005
|
+
throw new Error(
|
|
6006
|
+
`ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
|
|
6010
|
+
throw new Error(
|
|
6011
|
+
`ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
|
|
6012
|
+
);
|
|
6013
|
+
}
|
|
6014
|
+
};
|
|
6015
|
+
function displayField(field) {
|
|
6016
|
+
return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
6017
|
+
}
|
|
6018
|
+
function refFromName(name) {
|
|
6019
|
+
const dot = name.indexOf(".");
|
|
6020
|
+
return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
|
|
6021
|
+
}
|
|
6022
|
+
function collectGroupingRefs(node, out) {
|
|
6023
|
+
if (node === null || typeof node !== "object") return;
|
|
6024
|
+
if (Array.isArray(node)) {
|
|
6025
|
+
node.forEach((item) => collectGroupingRefs(item, out));
|
|
6026
|
+
return;
|
|
6027
|
+
}
|
|
6028
|
+
const value = node;
|
|
6029
|
+
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
|
|
6030
|
+
if (value["type"] === "GROUPING_REF") {
|
|
6031
|
+
out.push(value);
|
|
6032
|
+
return;
|
|
6033
|
+
}
|
|
6034
|
+
Object.values(value).forEach((item) => collectGroupingRefs(item, out));
|
|
6035
|
+
}
|
|
6036
|
+
function collectAggregateArgumentGroupingRefs(node, out) {
|
|
6037
|
+
if (node === null || typeof node !== "object") return;
|
|
6038
|
+
if (Array.isArray(node)) {
|
|
6039
|
+
node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
|
|
6040
|
+
return;
|
|
6041
|
+
}
|
|
6042
|
+
const value = node;
|
|
6043
|
+
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
|
|
6044
|
+
if (value["type"] === "AGGREGATE" || value["type"] === "AGG_REF") {
|
|
6045
|
+
collectGroupingRefs(value["arg"], out);
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
6048
|
+
Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
|
|
6049
|
+
}
|
|
6050
|
+
function collectNonAggregateFieldRefs(node, out) {
|
|
6051
|
+
if (node === null || typeof node !== "object") return;
|
|
6052
|
+
if (Array.isArray(node)) {
|
|
6053
|
+
node.forEach((item) => collectNonAggregateFieldRefs(item, out));
|
|
6054
|
+
return;
|
|
6055
|
+
}
|
|
6056
|
+
const value = node;
|
|
6057
|
+
const type = value["type"];
|
|
6058
|
+
if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
|
|
6059
|
+
if (type === "FIELD" && typeof value["field"] === "string") {
|
|
6060
|
+
out.push({
|
|
6061
|
+
type: "FIELD",
|
|
6062
|
+
tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
|
|
6063
|
+
field: value["field"]
|
|
6064
|
+
});
|
|
6065
|
+
return;
|
|
6066
|
+
}
|
|
6067
|
+
if (type === "FIELD_REF" && typeof value["field"] === "string") {
|
|
6068
|
+
out.push(refFromName(value["field"]));
|
|
6069
|
+
return;
|
|
6070
|
+
}
|
|
6071
|
+
Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
|
|
6072
|
+
}
|
|
6073
|
+
function containsAggregate(node) {
|
|
6074
|
+
if (node === null || typeof node !== "object") return false;
|
|
6075
|
+
if (Array.isArray(node)) return node.some(containsAggregate);
|
|
6076
|
+
const value = node;
|
|
6077
|
+
if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
|
|
6078
|
+
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
|
|
6079
|
+
return Object.values(value).some(containsAggregate);
|
|
6080
|
+
}
|
|
6081
|
+
function isAggregateMaterializedAlias(column) {
|
|
6082
|
+
if (!("alias" in column) || column.alias === null) return false;
|
|
6083
|
+
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
6084
|
+
if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL") {
|
|
6085
|
+
return containsAggregate(column);
|
|
6086
|
+
}
|
|
6087
|
+
return false;
|
|
6088
|
+
}
|
|
6089
|
+
function outputAliases(columns) {
|
|
6090
|
+
return new Set(columns.flatMap(
|
|
6091
|
+
(column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
|
|
6092
|
+
));
|
|
6093
|
+
}
|
|
6094
|
+
function isAggregateSyntheticReference(ref) {
|
|
6095
|
+
return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
|
|
6096
|
+
}
|
|
6097
|
+
function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
|
|
6098
|
+
const resolved = resolve2(ref.field);
|
|
6099
|
+
if (!resolved.physical) {
|
|
6100
|
+
throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
|
|
6101
|
+
}
|
|
6102
|
+
if (!canonicalItems.has(resolved.canonicalId)) {
|
|
6103
|
+
throw new Error(
|
|
6104
|
+
`ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
|
|
6105
|
+
);
|
|
6106
|
+
}
|
|
6107
|
+
bindGroupingRefCanonicalId(ref, resolved.canonicalId);
|
|
6108
|
+
}
|
|
6109
|
+
function validateDependency(ref, resolve2, canonicalItems, context) {
|
|
6110
|
+
const resolved = resolve2(ref);
|
|
6111
|
+
if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
|
|
6112
|
+
throw new Error(
|
|
6113
|
+
`ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
|
|
6114
|
+
);
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
function keyDependencies(key) {
|
|
6118
|
+
if (key.type === "GROUPING_KEY") return [];
|
|
6119
|
+
if (key.type === "FIELD_NAME") return [refFromName(key.name)];
|
|
6120
|
+
const refs = [];
|
|
6121
|
+
collectNonAggregateFieldRefs(key, refs);
|
|
6122
|
+
return refs;
|
|
6123
|
+
}
|
|
6124
|
+
function validateGroupingStatic(stmt) {
|
|
6125
|
+
const normalized = normalizeGroupingSpec(stmt);
|
|
6126
|
+
const groupingRefs = [];
|
|
6127
|
+
for (const column of stmt.columns) {
|
|
6128
|
+
if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
|
|
6129
|
+
}
|
|
6130
|
+
collectGroupingRefs(stmt.having, groupingRefs);
|
|
6131
|
+
collectGroupingRefs(stmt.orderBy, groupingRefs);
|
|
6132
|
+
const forbiddenGroupingRefs = [];
|
|
6133
|
+
collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
|
|
6134
|
+
collectGroupingRefs(stmt.joins, forbiddenGroupingRefs);
|
|
6135
|
+
collectAggregateArgumentGroupingRefs(stmt.columns, forbiddenGroupingRefs);
|
|
6136
|
+
collectAggregateArgumentGroupingRefs(stmt.having, forbiddenGroupingRefs);
|
|
6137
|
+
for (const column of stmt.columns) {
|
|
6138
|
+
if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
|
|
6139
|
+
}
|
|
6140
|
+
if (forbiddenGroupingRefs.length > 0) {
|
|
6141
|
+
throw new Error(
|
|
6142
|
+
"ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
|
|
6143
|
+
);
|
|
6144
|
+
}
|
|
6145
|
+
if (normalized.type !== "GROUPING_SETS") {
|
|
6146
|
+
if (groupingRefs.length > 0) {
|
|
6147
|
+
throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
|
|
6148
|
+
}
|
|
6149
|
+
return;
|
|
6150
|
+
}
|
|
6151
|
+
if (stmt.orderMode === "KINTONE_NATIVE") {
|
|
6152
|
+
throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
|
|
6153
|
+
}
|
|
6154
|
+
if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
|
|
6155
|
+
throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
|
|
6156
|
+
}
|
|
6157
|
+
if (stmt.columns.some(
|
|
6158
|
+
(column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
|
|
6159
|
+
)) {
|
|
6160
|
+
throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
|
|
6164
|
+
validateGroupingStatic(stmt);
|
|
6165
|
+
const normalized = normalizeGroupingSpec(stmt);
|
|
6166
|
+
const groupingRefs = [];
|
|
6167
|
+
for (const column of stmt.columns) {
|
|
6168
|
+
if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
|
|
6169
|
+
}
|
|
6170
|
+
collectGroupingRefs(stmt.having, groupingRefs);
|
|
6171
|
+
collectGroupingRefs(stmt.orderBy, groupingRefs);
|
|
6172
|
+
if (normalized.type !== "GROUPING_SETS") {
|
|
6173
|
+
return null;
|
|
6174
|
+
}
|
|
6175
|
+
const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
|
|
6176
|
+
const canonicalItems = /* @__PURE__ */ new Set();
|
|
6177
|
+
const resolvedItems = [];
|
|
6178
|
+
for (const item of resolvedSpec.allItems) {
|
|
6179
|
+
const resolved = item;
|
|
6180
|
+
if (!resolved.physical) {
|
|
6181
|
+
throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
|
|
6182
|
+
}
|
|
6183
|
+
if (!canonicalItems.has(resolved.canonicalId)) {
|
|
6184
|
+
canonicalItems.add(resolved.canonicalId);
|
|
6185
|
+
resolvedItems.push(resolved);
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
6188
|
+
planningGuardHook({
|
|
6189
|
+
expandedSetCount: normalized.sets.length,
|
|
6190
|
+
canonicalItemCount: canonicalItems.size
|
|
6191
|
+
});
|
|
6192
|
+
for (const ref of groupingRefs) {
|
|
6193
|
+
validateGroupingRefMembership(ref, resolve2, canonicalItems);
|
|
6194
|
+
}
|
|
6195
|
+
const aliases = outputAliases(stmt.columns);
|
|
6196
|
+
for (const column of stmt.columns) {
|
|
6197
|
+
if (column.type === "GROUPING_COL" || column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL" || column.type === "LITERAL_COL" || column.type === "VARIABLE_COL" || column.type === "SCALAR_SUBQUERY_COL") continue;
|
|
6198
|
+
const refs = [];
|
|
6199
|
+
if (column.type === "FIELD") refs.push(refFromName(column.field));
|
|
6200
|
+
else collectNonAggregateFieldRefs(column, refs);
|
|
6201
|
+
for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
|
|
6202
|
+
}
|
|
6203
|
+
if (stmt.having) {
|
|
6204
|
+
const refs = [];
|
|
6205
|
+
collectNonAggregateFieldRefs(stmt.having, refs);
|
|
6206
|
+
for (const ref of refs) {
|
|
6207
|
+
if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
|
|
6208
|
+
validateDependency(ref, resolve2, canonicalItems, "HAVING");
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
for (const order of stmt.orderBy) {
|
|
6212
|
+
for (const ref of keyDependencies(order.key)) {
|
|
6213
|
+
if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
|
|
6214
|
+
validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
const collisionKeys = /* @__PURE__ */ new Set();
|
|
6218
|
+
for (const item of resolvedItems) {
|
|
6219
|
+
collisionKeys.add(item.directKey);
|
|
6220
|
+
if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
|
|
6221
|
+
}
|
|
6222
|
+
for (const column of stmt.columns) {
|
|
6223
|
+
if (!isAggregateMaterializedAlias(column)) continue;
|
|
6224
|
+
const alias = "alias" in column ? column.alias : null;
|
|
6225
|
+
if (alias === null) continue;
|
|
6226
|
+
if (collisionKeys.has(alias)) {
|
|
6227
|
+
throw new Error(
|
|
6228
|
+
`ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
|
|
6229
|
+
);
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6232
|
+
return resolvedSpec;
|
|
6233
|
+
}
|
|
6234
|
+
|
|
5929
6235
|
// src/core/batch.ts
|
|
5930
6236
|
var MAX_TEMP_TABLES = 16;
|
|
5931
6237
|
var MAX_BATCH_VARIABLES = 64;
|
|
@@ -5967,11 +6273,32 @@ function collectVariableRefs(node, refs) {
|
|
|
5967
6273
|
for (const v of Object.values(obj)) collectVariableRefs(v, refs);
|
|
5968
6274
|
}
|
|
5969
6275
|
}
|
|
6276
|
+
function validateGroupingStaticQueries(node) {
|
|
6277
|
+
if (Array.isArray(node)) {
|
|
6278
|
+
for (const value of node) validateGroupingStaticQueries(value);
|
|
6279
|
+
return;
|
|
6280
|
+
}
|
|
6281
|
+
if (node !== null && typeof node === "object") {
|
|
6282
|
+
const obj = node;
|
|
6283
|
+
if (obj["type"] === "SELECT") {
|
|
6284
|
+
validateGroupingStatic(node);
|
|
6285
|
+
}
|
|
6286
|
+
for (const value of Object.values(obj)) validateGroupingStaticQueries(value);
|
|
6287
|
+
}
|
|
6288
|
+
}
|
|
5970
6289
|
function analyzeBatch(statements) {
|
|
5971
6290
|
if (statements.length === 0) {
|
|
5972
6291
|
throw new BatchAnalysisError("ArgumentError: SQL is empty.", 0);
|
|
5973
6292
|
}
|
|
5974
6293
|
statements.forEach((stmt, index) => {
|
|
6294
|
+
try {
|
|
6295
|
+
validateGroupingStaticQueries(stmt);
|
|
6296
|
+
} catch (error) {
|
|
6297
|
+
if (error instanceof Error) {
|
|
6298
|
+
throw new BatchAnalysisError(error.message, index);
|
|
6299
|
+
}
|
|
6300
|
+
throw error;
|
|
6301
|
+
}
|
|
5975
6302
|
try {
|
|
5976
6303
|
assertApplyScope("phase15b", stmt);
|
|
5977
6304
|
validateKlikeStatement(stmt);
|
|
@@ -6975,39 +7302,6 @@ function resolveFieldRef(row, field) {
|
|
|
6975
7302
|
return "";
|
|
6976
7303
|
}
|
|
6977
7304
|
|
|
6978
|
-
// src/engine/groupingRowMeta.ts
|
|
6979
|
-
var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
|
|
6980
|
-
var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
|
|
6981
|
-
function attachGroupingRowMeta(row, includedCanonicalIds) {
|
|
6982
|
-
Object.defineProperty(row, groupingRowMetaKey, {
|
|
6983
|
-
value: { includedCanonicalIds },
|
|
6984
|
-
enumerable: false,
|
|
6985
|
-
configurable: false,
|
|
6986
|
-
writable: false
|
|
6987
|
-
});
|
|
6988
|
-
return row;
|
|
6989
|
-
}
|
|
6990
|
-
function getGroupingRowMeta(row) {
|
|
6991
|
-
return row[groupingRowMetaKey];
|
|
6992
|
-
}
|
|
6993
|
-
function readGroupingMembership(row) {
|
|
6994
|
-
return getGroupingRowMeta(row)?.includedCanonicalIds;
|
|
6995
|
-
}
|
|
6996
|
-
function bindGroupingRefCanonicalId(ref, canonicalId) {
|
|
6997
|
-
groupingRefCanonicalIds.set(ref, canonicalId);
|
|
6998
|
-
}
|
|
6999
|
-
function evalGroupingRef(ref, row) {
|
|
7000
|
-
const membership = readGroupingMembership(row);
|
|
7001
|
-
if (!membership) {
|
|
7002
|
-
throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
|
|
7003
|
-
}
|
|
7004
|
-
const canonicalId = groupingRefCanonicalIds.get(ref);
|
|
7005
|
-
if (!canonicalId) {
|
|
7006
|
-
throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
|
|
7007
|
-
}
|
|
7008
|
-
return membership.has(canonicalId) ? "0" : "1";
|
|
7009
|
-
}
|
|
7010
|
-
|
|
7011
7305
|
// src/engine/evalWhere.ts
|
|
7012
7306
|
function evalWhere(expr, row, resolveFieldType, appliedKlikes, resolveFieldSemantics2) {
|
|
7013
7307
|
switch (expr.type) {
|
|
@@ -9949,212 +10243,6 @@ function explainNeedsAppMetadata(statement) {
|
|
|
9949
10243
|
return visit(statement);
|
|
9950
10244
|
}
|
|
9951
10245
|
|
|
9952
|
-
// src/core/groupingValidation.ts
|
|
9953
|
-
var enforceGroupingPlanningCandidateLimits = (facts) => {
|
|
9954
|
-
if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
|
|
9955
|
-
throw new Error(
|
|
9956
|
-
`ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
|
|
9957
|
-
);
|
|
9958
|
-
}
|
|
9959
|
-
if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
|
|
9960
|
-
throw new Error(
|
|
9961
|
-
`ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
|
|
9962
|
-
);
|
|
9963
|
-
}
|
|
9964
|
-
};
|
|
9965
|
-
function displayField(field) {
|
|
9966
|
-
return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
9967
|
-
}
|
|
9968
|
-
function refFromName(name) {
|
|
9969
|
-
const dot = name.indexOf(".");
|
|
9970
|
-
return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
|
|
9971
|
-
}
|
|
9972
|
-
function collectGroupingRefs(node, out) {
|
|
9973
|
-
if (node === null || typeof node !== "object") return;
|
|
9974
|
-
if (Array.isArray(node)) {
|
|
9975
|
-
node.forEach((item) => collectGroupingRefs(item, out));
|
|
9976
|
-
return;
|
|
9977
|
-
}
|
|
9978
|
-
const value = node;
|
|
9979
|
-
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
|
|
9980
|
-
if (value["type"] === "GROUPING_REF") {
|
|
9981
|
-
out.push(value);
|
|
9982
|
-
return;
|
|
9983
|
-
}
|
|
9984
|
-
Object.values(value).forEach((item) => collectGroupingRefs(item, out));
|
|
9985
|
-
}
|
|
9986
|
-
function collectNonAggregateFieldRefs(node, out) {
|
|
9987
|
-
if (node === null || typeof node !== "object") return;
|
|
9988
|
-
if (Array.isArray(node)) {
|
|
9989
|
-
node.forEach((item) => collectNonAggregateFieldRefs(item, out));
|
|
9990
|
-
return;
|
|
9991
|
-
}
|
|
9992
|
-
const value = node;
|
|
9993
|
-
const type = value["type"];
|
|
9994
|
-
if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
|
|
9995
|
-
if (type === "FIELD" && typeof value["field"] === "string") {
|
|
9996
|
-
out.push({
|
|
9997
|
-
type: "FIELD",
|
|
9998
|
-
tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
|
|
9999
|
-
field: value["field"]
|
|
10000
|
-
});
|
|
10001
|
-
return;
|
|
10002
|
-
}
|
|
10003
|
-
if (type === "FIELD_REF" && typeof value["field"] === "string") {
|
|
10004
|
-
out.push(refFromName(value["field"]));
|
|
10005
|
-
return;
|
|
10006
|
-
}
|
|
10007
|
-
Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
|
|
10008
|
-
}
|
|
10009
|
-
function containsAggregate(node) {
|
|
10010
|
-
if (node === null || typeof node !== "object") return false;
|
|
10011
|
-
if (Array.isArray(node)) return node.some(containsAggregate);
|
|
10012
|
-
const value = node;
|
|
10013
|
-
if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
|
|
10014
|
-
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
|
|
10015
|
-
return Object.values(value).some(containsAggregate);
|
|
10016
|
-
}
|
|
10017
|
-
function isAggregateMaterializedAlias(column) {
|
|
10018
|
-
if (!("alias" in column) || column.alias === null) return false;
|
|
10019
|
-
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
10020
|
-
if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL") {
|
|
10021
|
-
return containsAggregate(column);
|
|
10022
|
-
}
|
|
10023
|
-
return false;
|
|
10024
|
-
}
|
|
10025
|
-
function outputAliases(columns) {
|
|
10026
|
-
return new Set(columns.flatMap(
|
|
10027
|
-
(column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
|
|
10028
|
-
));
|
|
10029
|
-
}
|
|
10030
|
-
function isAggregateSyntheticReference(ref) {
|
|
10031
|
-
return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
|
|
10032
|
-
}
|
|
10033
|
-
function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
|
|
10034
|
-
const resolved = resolve2(ref.field);
|
|
10035
|
-
if (!resolved.physical) {
|
|
10036
|
-
throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
|
|
10037
|
-
}
|
|
10038
|
-
if (!canonicalItems.has(resolved.canonicalId)) {
|
|
10039
|
-
throw new Error(
|
|
10040
|
-
`ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
|
|
10041
|
-
);
|
|
10042
|
-
}
|
|
10043
|
-
bindGroupingRefCanonicalId(ref, resolved.canonicalId);
|
|
10044
|
-
}
|
|
10045
|
-
function validateDependency(ref, resolve2, canonicalItems, context) {
|
|
10046
|
-
const resolved = resolve2(ref);
|
|
10047
|
-
if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
|
|
10048
|
-
throw new Error(
|
|
10049
|
-
`ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
|
|
10050
|
-
);
|
|
10051
|
-
}
|
|
10052
|
-
}
|
|
10053
|
-
function keyDependencies(key) {
|
|
10054
|
-
if (key.type === "GROUPING_KEY") return [];
|
|
10055
|
-
if (key.type === "FIELD_NAME") return [refFromName(key.name)];
|
|
10056
|
-
const refs = [];
|
|
10057
|
-
collectNonAggregateFieldRefs(key, refs);
|
|
10058
|
-
return refs;
|
|
10059
|
-
}
|
|
10060
|
-
function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
|
|
10061
|
-
const normalized = normalizeGroupingSpec(stmt);
|
|
10062
|
-
const groupingRefs = [];
|
|
10063
|
-
for (const column of stmt.columns) {
|
|
10064
|
-
if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
|
|
10065
|
-
}
|
|
10066
|
-
collectGroupingRefs(stmt.orderBy, groupingRefs);
|
|
10067
|
-
const forbiddenGroupingRefs = [];
|
|
10068
|
-
collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
|
|
10069
|
-
collectGroupingRefs(stmt.having, forbiddenGroupingRefs);
|
|
10070
|
-
for (const column of stmt.columns) {
|
|
10071
|
-
if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
|
|
10072
|
-
}
|
|
10073
|
-
if (forbiddenGroupingRefs.length > 0) {
|
|
10074
|
-
throw new Error(
|
|
10075
|
-
"ArgumentError: B65 GROUPING() is not allowed in WHERE, HAVING, JOIN, window, aggregate arguments, or DML expressions in Phase1."
|
|
10076
|
-
);
|
|
10077
|
-
}
|
|
10078
|
-
if (normalized.type !== "GROUPING_SETS") {
|
|
10079
|
-
if (groupingRefs.length > 0) {
|
|
10080
|
-
throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
|
|
10081
|
-
}
|
|
10082
|
-
return null;
|
|
10083
|
-
}
|
|
10084
|
-
if (stmt.distinct) {
|
|
10085
|
-
throw new Error("ArgumentError: B65 SELECT DISTINCT is not supported in Phase1.");
|
|
10086
|
-
}
|
|
10087
|
-
if (stmt.orderMode === "KINTONE_NATIVE") {
|
|
10088
|
-
throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
|
|
10089
|
-
}
|
|
10090
|
-
if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
|
|
10091
|
-
throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
|
|
10092
|
-
}
|
|
10093
|
-
if (stmt.columns.some(
|
|
10094
|
-
(column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
|
|
10095
|
-
)) {
|
|
10096
|
-
throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
|
|
10097
|
-
}
|
|
10098
|
-
const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
|
|
10099
|
-
const canonicalItems = /* @__PURE__ */ new Set();
|
|
10100
|
-
const resolvedItems = [];
|
|
10101
|
-
for (const item of resolvedSpec.allItems) {
|
|
10102
|
-
const resolved = item;
|
|
10103
|
-
if (!resolved.physical) {
|
|
10104
|
-
throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
|
|
10105
|
-
}
|
|
10106
|
-
if (!canonicalItems.has(resolved.canonicalId)) {
|
|
10107
|
-
canonicalItems.add(resolved.canonicalId);
|
|
10108
|
-
resolvedItems.push(resolved);
|
|
10109
|
-
}
|
|
10110
|
-
}
|
|
10111
|
-
planningGuardHook({
|
|
10112
|
-
expandedSetCount: normalized.sets.length,
|
|
10113
|
-
canonicalItemCount: canonicalItems.size
|
|
10114
|
-
});
|
|
10115
|
-
for (const ref of groupingRefs) {
|
|
10116
|
-
validateGroupingRefMembership(ref, resolve2, canonicalItems);
|
|
10117
|
-
}
|
|
10118
|
-
const aliases = outputAliases(stmt.columns);
|
|
10119
|
-
for (const column of stmt.columns) {
|
|
10120
|
-
if (column.type === "GROUPING_COL" || column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL" || column.type === "LITERAL_COL" || column.type === "VARIABLE_COL" || column.type === "SCALAR_SUBQUERY_COL") continue;
|
|
10121
|
-
const refs = [];
|
|
10122
|
-
if (column.type === "FIELD") refs.push(refFromName(column.field));
|
|
10123
|
-
else collectNonAggregateFieldRefs(column, refs);
|
|
10124
|
-
for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
|
|
10125
|
-
}
|
|
10126
|
-
if (stmt.having) {
|
|
10127
|
-
const refs = [];
|
|
10128
|
-
collectNonAggregateFieldRefs(stmt.having, refs);
|
|
10129
|
-
for (const ref of refs) {
|
|
10130
|
-
if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
|
|
10131
|
-
validateDependency(ref, resolve2, canonicalItems, "HAVING");
|
|
10132
|
-
}
|
|
10133
|
-
}
|
|
10134
|
-
for (const order of stmt.orderBy) {
|
|
10135
|
-
for (const ref of keyDependencies(order.key)) {
|
|
10136
|
-
if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
|
|
10137
|
-
validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
|
|
10138
|
-
}
|
|
10139
|
-
}
|
|
10140
|
-
const collisionKeys = /* @__PURE__ */ new Set();
|
|
10141
|
-
for (const item of resolvedItems) {
|
|
10142
|
-
collisionKeys.add(item.directKey);
|
|
10143
|
-
if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
|
|
10144
|
-
}
|
|
10145
|
-
for (const column of stmt.columns) {
|
|
10146
|
-
if (!isAggregateMaterializedAlias(column)) continue;
|
|
10147
|
-
const alias = "alias" in column ? column.alias : null;
|
|
10148
|
-
if (alias === null) continue;
|
|
10149
|
-
if (collisionKeys.has(alias)) {
|
|
10150
|
-
throw new Error(
|
|
10151
|
-
`ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
|
|
10152
|
-
);
|
|
10153
|
-
}
|
|
10154
|
-
}
|
|
10155
|
-
return resolvedSpec;
|
|
10156
|
-
}
|
|
10157
|
-
|
|
10158
10246
|
// src/api/fetchAll.ts
|
|
10159
10247
|
async function fetchAll(fetcher, app, query, fields, options = {}) {
|
|
10160
10248
|
const pageSize = options.pageSize ?? PAGE_SIZE_DEFAULT;
|
|
@@ -10932,9 +11020,13 @@ function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
|
|
|
10932
11020
|
if (having === null) return rows;
|
|
10933
11021
|
return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
|
|
10934
11022
|
}
|
|
10935
|
-
function applyDistinct(rows, columns) {
|
|
11023
|
+
function applyDistinct(rows, columns, scalarCache, resolveFieldType, resolveFieldSemantics2) {
|
|
10936
11024
|
if (rows.length === 0) return rows;
|
|
10937
|
-
const keyFor = buildDistinctKeyBuilder(rows, columns
|
|
11025
|
+
const keyFor = buildDistinctKeyBuilder(rows, columns, {
|
|
11026
|
+
scalarCache,
|
|
11027
|
+
resolveFieldType,
|
|
11028
|
+
resolveFieldSemantics: resolveFieldSemantics2
|
|
11029
|
+
});
|
|
10938
11030
|
const seen = /* @__PURE__ */ new Set();
|
|
10939
11031
|
return rows.filter((row) => {
|
|
10940
11032
|
const key = keyFor(row);
|
|
@@ -10943,14 +11035,14 @@ function applyDistinct(rows, columns) {
|
|
|
10943
11035
|
return true;
|
|
10944
11036
|
});
|
|
10945
11037
|
}
|
|
10946
|
-
function buildDistinctKeyBuilder(rows, columns) {
|
|
11038
|
+
function buildDistinctKeyBuilder(rows, columns, context) {
|
|
11039
|
+
let sortedWildcardKeys = [];
|
|
10947
11040
|
if (columns.some((c) => c.type === "WILDCARD")) {
|
|
10948
11041
|
const allKeys = /* @__PURE__ */ new Set();
|
|
10949
11042
|
for (const row of rows) {
|
|
10950
11043
|
for (const k of Object.keys(row)) allKeys.add(k);
|
|
10951
11044
|
}
|
|
10952
|
-
|
|
10953
|
-
return (row) => JSON.stringify(keys.map((k) => row[k] !== void 0 ? row[k] : null));
|
|
11045
|
+
sortedWildcardKeys = [...allKeys].sort();
|
|
10954
11046
|
}
|
|
10955
11047
|
let sortedParentKeys = [];
|
|
10956
11048
|
if (columns.some((c) => c.type === "PARENT_WILDCARD")) {
|
|
@@ -10962,25 +11054,12 @@ function buildDistinctKeyBuilder(rows, columns) {
|
|
|
10962
11054
|
}
|
|
10963
11055
|
sortedParentKeys = [...parentKeys].sort();
|
|
10964
11056
|
}
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
values.push(row[col.field] ?? "");
|
|
10970
|
-
continue;
|
|
10971
|
-
}
|
|
10972
|
-
if (col.type === "WINDOW_COL") {
|
|
10973
|
-
values.push(row[col.alias] ?? "");
|
|
10974
|
-
continue;
|
|
10975
|
-
}
|
|
10976
|
-
if (col.type === "PARENT_WILDCARD") {
|
|
10977
|
-
for (const k of sortedParentKeys) {
|
|
10978
|
-
values.push(row[k] !== void 0 ? row[k] : null);
|
|
10979
|
-
}
|
|
10980
|
-
}
|
|
10981
|
-
}
|
|
10982
|
-
return JSON.stringify(values);
|
|
11057
|
+
const distinctContext = {
|
|
11058
|
+
...context,
|
|
11059
|
+
wildcardKeys: sortedWildcardKeys,
|
|
11060
|
+
parentWildcardKeys: sortedParentKeys
|
|
10983
11061
|
};
|
|
11062
|
+
return (row) => JSON.stringify(buildDistinctTuple(columns, row, distinctContext));
|
|
10984
11063
|
}
|
|
10985
11064
|
function applyOrderBy(rows, orderBy, optionOrders, sortKinds, fieldSemantics2, aliasEvaluator) {
|
|
10986
11065
|
if (orderBy.length === 0) return rows;
|
|
@@ -11152,12 +11231,100 @@ function applyLimit(rows, limit, offset) {
|
|
|
11152
11231
|
if (limit === null) return rows.slice(start);
|
|
11153
11232
|
return rows.slice(start, start + limit);
|
|
11154
11233
|
}
|
|
11234
|
+
function evaluateSelectColumnValue(column, row, columnIndex, context = {}) {
|
|
11235
|
+
switch (column.type) {
|
|
11236
|
+
case "VARIABLE_COL":
|
|
11237
|
+
throw new Error(`internal error: unresolved SELECT variable @${column.name}`);
|
|
11238
|
+
case "WILDCARD": {
|
|
11239
|
+
const keys = context.wildcardKeys ?? Object.keys(row);
|
|
11240
|
+
return {
|
|
11241
|
+
kind: "EXPANDED",
|
|
11242
|
+
entries: keys.map((key) => [key, row[key] !== void 0 ? row[key] : null])
|
|
11243
|
+
};
|
|
11244
|
+
}
|
|
11245
|
+
case "PARENT_WILDCARD": {
|
|
11246
|
+
const keys = context.parentWildcardKeys ?? Object.keys(row).filter((key) => key.startsWith("_p.")).sort();
|
|
11247
|
+
return {
|
|
11248
|
+
kind: "EXPANDED",
|
|
11249
|
+
entries: keys.map((key) => [key, row[key] !== void 0 ? row[key] : null])
|
|
11250
|
+
};
|
|
11251
|
+
}
|
|
11252
|
+
case "FIELD":
|
|
11253
|
+
return resolveFieldRef(row, column.field);
|
|
11254
|
+
case "LITERAL_COL":
|
|
11255
|
+
return column.value;
|
|
11256
|
+
case "AGGREGATE": {
|
|
11257
|
+
const source = aggregateSyntheticName(column.func, column.distinct, column.arg);
|
|
11258
|
+
return row[column.alias ?? source] ?? row[source] ?? "0";
|
|
11259
|
+
}
|
|
11260
|
+
case "ARITH_AGG_COL": {
|
|
11261
|
+
const source = column.alias ?? aggArithDefaultKey(column.expr);
|
|
11262
|
+
return row[source] ?? "0";
|
|
11263
|
+
}
|
|
11264
|
+
case "ARITH_COL":
|
|
11265
|
+
return String(evalArithExpr(column.expr, row));
|
|
11266
|
+
case "CASE_COL":
|
|
11267
|
+
return evalCaseWhen(
|
|
11268
|
+
column.expr,
|
|
11269
|
+
row,
|
|
11270
|
+
context.resolveFieldType,
|
|
11271
|
+
context.resolveFieldSemantics
|
|
11272
|
+
);
|
|
11273
|
+
case "GROUPING_COL":
|
|
11274
|
+
return evalGroupingRef(column.ref, row);
|
|
11275
|
+
case "STRFUNC_COL": {
|
|
11276
|
+
const source = stringFuncDefaultKey(column.expr);
|
|
11277
|
+
return hasAggregateInStringFuncExpr2(column.expr) ? row[column.alias ?? source] ?? row[source] ?? evalStringFunc(
|
|
11278
|
+
column.expr,
|
|
11279
|
+
row,
|
|
11280
|
+
context.resolveFieldType,
|
|
11281
|
+
context.resolveFieldSemantics
|
|
11282
|
+
) : evalStringFunc(
|
|
11283
|
+
column.expr,
|
|
11284
|
+
row,
|
|
11285
|
+
context.resolveFieldType,
|
|
11286
|
+
context.resolveFieldSemantics
|
|
11287
|
+
);
|
|
11288
|
+
}
|
|
11289
|
+
case "SCALAR_VALUE_COL": {
|
|
11290
|
+
const source = scalarValueDefaultKey(column.expr);
|
|
11291
|
+
return scalarValueHasAggregate2(column.expr) ? row[column.alias ?? source] ?? row[source] ?? "" : String(evalScalarValueExpr(
|
|
11292
|
+
column.expr,
|
|
11293
|
+
row,
|
|
11294
|
+
context.resolveFieldType,
|
|
11295
|
+
context.resolveFieldSemantics
|
|
11296
|
+
));
|
|
11297
|
+
}
|
|
11298
|
+
case "SCALAR_SUBQUERY_COL":
|
|
11299
|
+
return context.scalarCache?.get(columnIndex) ?? "";
|
|
11300
|
+
case "WINDOW_COL":
|
|
11301
|
+
return row[column.alias] ?? "";
|
|
11302
|
+
}
|
|
11303
|
+
}
|
|
11304
|
+
function buildDistinctTuple(columns, row, context = {}) {
|
|
11305
|
+
return columns.map((column, columnIndex) => {
|
|
11306
|
+
const value = evaluateSelectColumnValue(column, row, columnIndex, context);
|
|
11307
|
+
return typeof value === "string" ? value : value.entries.map(([, entryValue]) => entryValue);
|
|
11308
|
+
});
|
|
11309
|
+
}
|
|
11155
11310
|
function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, resolveFieldSemantics2, hiddenQualifiedAliases) {
|
|
11156
11311
|
if (columns.length === 1 && columns[0].type === "WILDCARD") {
|
|
11157
|
-
const projected2 = rows.map((row) =>
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11312
|
+
const projected2 = rows.map((row) => {
|
|
11313
|
+
const visible = stripHiddenQualifiedColumns(
|
|
11314
|
+
stripParentShortcutColumns(row),
|
|
11315
|
+
hiddenQualifiedAliases
|
|
11316
|
+
);
|
|
11317
|
+
const value = evaluateSelectColumnValue(columns[0], row, 0, {
|
|
11318
|
+
wildcardKeys: Object.keys(visible)
|
|
11319
|
+
});
|
|
11320
|
+
const out = {};
|
|
11321
|
+
if (typeof value !== "string") {
|
|
11322
|
+
for (const [key, entryValue] of value.entries) {
|
|
11323
|
+
if (entryValue !== null) out[key] = entryValue;
|
|
11324
|
+
}
|
|
11325
|
+
}
|
|
11326
|
+
return out;
|
|
11327
|
+
});
|
|
11161
11328
|
const cols = projected2.length > 0 ? Object.keys(projected2[0]) : [...sourceColumns ?? []];
|
|
11162
11329
|
return { rows: projected2, columns: cols };
|
|
11163
11330
|
}
|
|
@@ -11172,95 +11339,101 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
|
|
|
11172
11339
|
}
|
|
11173
11340
|
const projected = rows.map((row, rowIdx) => {
|
|
11174
11341
|
const out = {};
|
|
11342
|
+
const evaluationContext = {
|
|
11343
|
+
scalarCache,
|
|
11344
|
+
resolveFieldType,
|
|
11345
|
+
resolveFieldSemantics: resolveFieldSemantics2,
|
|
11346
|
+
wildcardKeys: Object.keys(stripHiddenQualifiedColumns(
|
|
11347
|
+
stripParentShortcutColumns(row),
|
|
11348
|
+
hiddenQualifiedAliases
|
|
11349
|
+
)),
|
|
11350
|
+
parentWildcardKeys: Object.keys(row).filter((key) => key.startsWith("_p.")).sort()
|
|
11351
|
+
};
|
|
11175
11352
|
for (const [colIdx, col] of columns.entries()) {
|
|
11353
|
+
const value = evaluateSelectColumnValue(col, row, colIdx, evaluationContext);
|
|
11176
11354
|
switch (col.type) {
|
|
11177
11355
|
case "VARIABLE_COL":
|
|
11178
|
-
|
|
11356
|
+
break;
|
|
11179
11357
|
case "WILDCARD":
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11358
|
+
if (typeof value !== "string") {
|
|
11359
|
+
for (const [key, entryValue] of value.entries) {
|
|
11360
|
+
if (entryValue !== null) out[key] = entryValue;
|
|
11361
|
+
}
|
|
11362
|
+
}
|
|
11184
11363
|
break;
|
|
11185
11364
|
case "PARENT_WILDCARD": {
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11365
|
+
if (typeof value !== "string") {
|
|
11366
|
+
for (const [key, entryValue] of value.entries) {
|
|
11367
|
+
if (entryValue !== null) out[key] = entryValue;
|
|
11368
|
+
if (rowIdx === 0) orderedKeys.push(key);
|
|
11369
|
+
}
|
|
11190
11370
|
}
|
|
11191
11371
|
break;
|
|
11192
11372
|
}
|
|
11193
11373
|
case "FIELD": {
|
|
11194
11374
|
const key = outputKeys?.[colIdx] ?? col.alias ?? defaultFieldKeys.get(colIdx) ?? col.field;
|
|
11195
|
-
out[key] =
|
|
11375
|
+
out[key] = value;
|
|
11196
11376
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11197
11377
|
break;
|
|
11198
11378
|
}
|
|
11199
11379
|
case "LITERAL_COL": {
|
|
11200
11380
|
const key = outputKeys?.[colIdx] ?? col.alias ?? `'${col.value}'`;
|
|
11201
|
-
out[key] =
|
|
11381
|
+
out[key] = value;
|
|
11202
11382
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11203
11383
|
break;
|
|
11204
11384
|
}
|
|
11205
11385
|
case "AGGREGATE": {
|
|
11206
11386
|
const srcKey = aggregateSyntheticName(col.func, col.distinct, col.arg);
|
|
11207
11387
|
const dstKey = outputKeys?.[colIdx] ?? col.alias ?? srcKey;
|
|
11208
|
-
out[dstKey] =
|
|
11388
|
+
out[dstKey] = value;
|
|
11209
11389
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(dstKey);
|
|
11210
11390
|
break;
|
|
11211
11391
|
}
|
|
11212
11392
|
case "ARITH_AGG_COL": {
|
|
11213
11393
|
const key = outputKeys?.[colIdx] ?? col.alias ?? aggArithDefaultKey(col.expr);
|
|
11214
|
-
out[key] =
|
|
11394
|
+
out[key] = value;
|
|
11215
11395
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11216
11396
|
break;
|
|
11217
11397
|
}
|
|
11218
11398
|
case "ARITH_COL": {
|
|
11219
|
-
const val = evalArithExpr(col.expr, row);
|
|
11220
11399
|
const key = outputKeys?.[colIdx] ?? col.alias ?? arithColDefaultKey(col.expr);
|
|
11221
|
-
out[key] =
|
|
11400
|
+
out[key] = value;
|
|
11222
11401
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11223
11402
|
break;
|
|
11224
11403
|
}
|
|
11225
11404
|
case "CASE_COL": {
|
|
11226
11405
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
|
|
11227
|
-
out[key] =
|
|
11406
|
+
out[key] = value;
|
|
11228
11407
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11229
11408
|
break;
|
|
11230
11409
|
}
|
|
11231
11410
|
case "GROUPING_COL": {
|
|
11232
11411
|
const key = outputKeys?.[colIdx] ?? col.alias ?? `GROUPING(${col.ref.field.tableAlias ? `${col.ref.field.tableAlias}.` : ""}${col.ref.field.field})`;
|
|
11233
|
-
out[key] =
|
|
11412
|
+
out[key] = value;
|
|
11234
11413
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11235
11414
|
break;
|
|
11236
11415
|
}
|
|
11237
11416
|
case "STRFUNC_COL": {
|
|
11238
11417
|
const key = outputKeys?.[colIdx] ?? col.alias ?? stringFuncDefaultKey(col.expr);
|
|
11239
|
-
|
|
11240
|
-
const srcKey = stringFuncDefaultKey(col.expr);
|
|
11241
|
-
out[key] = row[col.alias ?? srcKey] ?? row[srcKey] ?? evalStringFunc(col.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
11242
|
-
} else {
|
|
11243
|
-
out[key] = evalStringFunc(col.expr, row, resolveFieldType, resolveFieldSemantics2);
|
|
11244
|
-
}
|
|
11418
|
+
out[key] = value;
|
|
11245
11419
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11246
11420
|
break;
|
|
11247
11421
|
}
|
|
11248
11422
|
case "SCALAR_VALUE_COL": {
|
|
11249
11423
|
const key = outputKeys?.[colIdx] ?? col.alias ?? scalarValueDefaultKey(col.expr);
|
|
11250
|
-
|
|
11251
|
-
out[key] = scalarValueHasAggregate2(col.expr) ? row[col.alias ?? srcKey] ?? row[srcKey] ?? "" : String(evalScalarValueExpr(col.expr, row, resolveFieldType, resolveFieldSemantics2));
|
|
11424
|
+
out[key] = value;
|
|
11252
11425
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11253
11426
|
break;
|
|
11254
11427
|
}
|
|
11255
11428
|
case "SCALAR_SUBQUERY_COL": {
|
|
11256
11429
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "(subquery)";
|
|
11257
|
-
out[key] =
|
|
11430
|
+
out[key] = value;
|
|
11258
11431
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11259
11432
|
break;
|
|
11260
11433
|
}
|
|
11261
11434
|
case "WINDOW_COL": {
|
|
11262
11435
|
const key = outputKeys?.[colIdx] ?? col.alias;
|
|
11263
|
-
out[key] =
|
|
11436
|
+
out[key] = value;
|
|
11264
11437
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
11265
11438
|
break;
|
|
11266
11439
|
}
|
|
@@ -11551,7 +11724,13 @@ function runFullScan(input) {
|
|
|
11551
11724
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
|
|
11552
11725
|
rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
|
|
11553
11726
|
if (stmt.distinct) {
|
|
11554
|
-
rows = applyDistinct(
|
|
11727
|
+
rows = applyDistinct(
|
|
11728
|
+
rows,
|
|
11729
|
+
stmt.columns,
|
|
11730
|
+
scalarCache,
|
|
11731
|
+
fieldTypeResolver,
|
|
11732
|
+
fieldSemanticsResolver
|
|
11733
|
+
);
|
|
11555
11734
|
}
|
|
11556
11735
|
rows = applyOrderBy(
|
|
11557
11736
|
rows,
|
|
@@ -19291,7 +19470,9 @@ function collectFullScanReasons(stmt) {
|
|
|
19291
19470
|
if (grouping.type === "PLAIN")
|
|
19292
19471
|
r.push("GROUP BY \u3042\u308A");
|
|
19293
19472
|
else if (grouping.type === "GROUPING_SETS")
|
|
19294
|
-
r.push(
|
|
19473
|
+
r.push(
|
|
19474
|
+
grouping.source === "ROLLUP" ? "ROLLUP \u3042\u308A" : grouping.source === "CUBE" ? "CUBE \u3042\u308A" : "GROUPING SETS \u3042\u308A"
|
|
19475
|
+
);
|
|
19295
19476
|
if (stmt.distinct)
|
|
19296
19477
|
r.push("DISTINCT \u3042\u308A");
|
|
19297
19478
|
if (stmt.columns.some((c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL"))
|