@rex0220/kintone-sql-tools 3.44.0 → 3.46.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 +433 -47
- package/dist-engine/index.cjs +11 -11
- package/dist-engine/index.mjs +11 -11
- package/dist-engine/ksql-engine.umd.js +11 -11
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +20 -20
- package/dist-engine/meta/esm.json +20 -20
- package/dist-engine/meta/umd.json +20 -20
- package/dist-mcp/ksql-mcp.js +456 -54
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -577,6 +577,9 @@ function compareDecimal(left, right) {
|
|
|
577
577
|
|
|
578
578
|
// src/types/ast.ts
|
|
579
579
|
var NO_FROM_CTE_NAME = "__NO_FROM__";
|
|
580
|
+
function isRankingWindow(column) {
|
|
581
|
+
return column.windowKind !== "AGGREGATE";
|
|
582
|
+
}
|
|
580
583
|
function makeNumberLiteral(raw) {
|
|
581
584
|
return { type: "NUMBER", value: Number(raw), raw };
|
|
582
585
|
}
|
|
@@ -749,7 +752,7 @@ function caseLabel(expr) {
|
|
|
749
752
|
}
|
|
750
753
|
function stringFuncArgLabel(arg) {
|
|
751
754
|
if (arg.type === "AGG_REF") return aggregateSyntheticName(arg.func, arg.distinct, arg.arg);
|
|
752
|
-
if (arg.type === "AGG_ARITH") return aggregateOperandLabel(arg);
|
|
755
|
+
if (arg.type === "AGG_ARITH" || arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") return aggregateOperandLabel(arg);
|
|
753
756
|
return scalarValueLabel(arg);
|
|
754
757
|
}
|
|
755
758
|
function stringFuncLabel(expr) {
|
|
@@ -787,6 +790,8 @@ function aggregateSyntheticName(func, distinct, arg) {
|
|
|
787
790
|
function aggregateOperandLabel(node) {
|
|
788
791
|
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
789
792
|
if (node.type === "AGG_REF") return aggregateSyntheticName(node.func, node.distinct, node.arg);
|
|
793
|
+
if (node.type === "AGG_GROUP_KEY") return node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field;
|
|
794
|
+
if (node.type === "VARIABLE") return `@${node.name}`;
|
|
790
795
|
return `${aggregateOperandLabel(node.left)}${node.op}${aggregateOperandLabel(node.right)}`;
|
|
791
796
|
}
|
|
792
797
|
|
|
@@ -1065,6 +1070,8 @@ var Parser = class {
|
|
|
1065
1070
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
1066
1071
|
/** パース中に出現した一時テーブル参照(#name)のトークン。単文 API での拒否に使う */
|
|
1067
1072
|
this.tempTableRefs = [];
|
|
1073
|
+
/** GROUP BY を読む前に作る B124 候補 leaf の診断位置。AST 公開型へ位置情報を足さない。 */
|
|
1074
|
+
this.aggregateGroupKeyTokens = /* @__PURE__ */ new WeakMap();
|
|
1068
1075
|
this.allowSelectArithVariable = false;
|
|
1069
1076
|
}
|
|
1070
1077
|
// ----------------------------------------------------------
|
|
@@ -1318,6 +1325,11 @@ var Parser = class {
|
|
|
1318
1325
|
}
|
|
1319
1326
|
throw new ParseError(msg, tok);
|
|
1320
1327
|
}
|
|
1328
|
+
consumeSoftKeyword(word) {
|
|
1329
|
+
if (!this.isSoftKeyword(word)) return false;
|
|
1330
|
+
this.advance();
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1321
1333
|
parseTempTableName() {
|
|
1322
1334
|
const tok = this.peek();
|
|
1323
1335
|
if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
|
|
@@ -1871,6 +1883,7 @@ var Parser = class {
|
|
|
1871
1883
|
if (grouping && orderMode === "KINTONE_NATIVE") {
|
|
1872
1884
|
throw new ParseError("B65: KORDER BY cannot be combined with grouping sets in Phase1.", this.peek());
|
|
1873
1885
|
}
|
|
1886
|
+
this.validateAggregateGroupKeyRefs(columns, having, groupBy, grouping);
|
|
1874
1887
|
return {
|
|
1875
1888
|
type: "SELECT",
|
|
1876
1889
|
distinct,
|
|
@@ -1957,6 +1970,18 @@ var Parser = class {
|
|
|
1957
1970
|
const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1958
1971
|
return this.withAliasDisplay({ type: "GROUPING_COL", ref, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
|
|
1959
1972
|
}
|
|
1973
|
+
if (this.tryAggregateFunc() === null && this.hasNestedAggregateWindowInSelectColumn()) {
|
|
1974
|
+
throw new ParseError(
|
|
1975
|
+
"\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306E\u7D50\u679C\u3092\u5F0F\u306B\u542B\u3081\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002CTE \u3067\u4E00\u5EA6\u5B9F\u4F53\u5316\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
1976
|
+
this.peek()
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
if (this.isNonAggregateArithmeticStartWithAggregate()) {
|
|
1980
|
+
throw new ParseError(
|
|
1981
|
+
`\u96C6\u8A08\u7B97\u8853\u5F0F\u306F\u96C6\u8A08\u95A2\u6570\u304B\u3089\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08${this.peek().value}\uFF09\u3002`,
|
|
1982
|
+
this.peek()
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1960
1985
|
if (this.tryAggregateFunc() === null && this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
1961
1986
|
const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
1962
1987
|
const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -2001,6 +2026,9 @@ var Parser = class {
|
|
|
2001
2026
|
const aggFunc = this.tryAggregateFunc();
|
|
2002
2027
|
if (aggFunc !== null) {
|
|
2003
2028
|
const ref = this.parseAggregateRef(aggFunc);
|
|
2029
|
+
if (this.isSoftKeyword("OVER")) {
|
|
2030
|
+
return this.parseAggregateWindowColumn(ref);
|
|
2031
|
+
}
|
|
2004
2032
|
if (this.isArithOp(this.peek().kind)) {
|
|
2005
2033
|
const expr = this.continueAggArith(ref);
|
|
2006
2034
|
const parsedAlias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -2052,6 +2080,28 @@ var Parser = class {
|
|
|
2052
2080
|
tryWindowFunc() {
|
|
2053
2081
|
return PARSER_WINDOW_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
|
|
2054
2082
|
}
|
|
2083
|
+
hasNestedAggregateWindowInSelectColumn() {
|
|
2084
|
+
let depth = 0;
|
|
2085
|
+
for (let index = this.pos; index < this.tokens.length; index++) {
|
|
2086
|
+
const token = this.tokens[index];
|
|
2087
|
+
if (depth === 0 && (token.kind === "," /* COMMA */ || token.kind === "FROM" /* FROM */ || token.kind === ";" /* SEMICOLON */ || token.kind === "EOF" /* EOF */)) return false;
|
|
2088
|
+
if (PARSER_AGGREGATE_FUNCTION_TOKEN_MAP[token.kind] !== void 0 && this.tokens[index + 1]?.kind === "(" /* LPAREN */) {
|
|
2089
|
+
let aggregateDepth = 0;
|
|
2090
|
+
for (let cursor = index + 1; cursor < this.tokens.length; cursor++) {
|
|
2091
|
+
const candidate = this.tokens[cursor];
|
|
2092
|
+
if (candidate.kind === "(" /* LPAREN */) aggregateDepth++;
|
|
2093
|
+
else if (candidate.kind === ")" /* RPAREN */ && --aggregateDepth === 0) {
|
|
2094
|
+
const next = this.tokens[cursor + 1];
|
|
2095
|
+
if (next?.kind === "IDENT" /* IDENT */ && next.value.toUpperCase() === "OVER") return true;
|
|
2096
|
+
break;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
if (token.kind === "(" /* LPAREN */) depth++;
|
|
2101
|
+
else if (token.kind === ")" /* RPAREN */) depth--;
|
|
2102
|
+
}
|
|
2103
|
+
return false;
|
|
2104
|
+
}
|
|
2055
2105
|
parseWindowColumn(func) {
|
|
2056
2106
|
this.advance();
|
|
2057
2107
|
this.expect("(" /* LPAREN */);
|
|
@@ -2078,6 +2128,66 @@ var Parser = class {
|
|
|
2078
2128
|
const parsedAlias = this.parseAliasName();
|
|
2079
2129
|
return this.withAliasDisplay({ type: "WINDOW_COL", func, partitionBy, orderBy, alias: parsedAlias.alias }, parsedAlias);
|
|
2080
2130
|
}
|
|
2131
|
+
parseAggregateWindowColumn(ref) {
|
|
2132
|
+
const supported = /* @__PURE__ */ new Set(["SUM", "COUNT", "AVG", "MIN", "MAX"]);
|
|
2133
|
+
if (!supported.has(ref.func)) {
|
|
2134
|
+
throw new ParseError(
|
|
2135
|
+
`${ref.func} \u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u96C6\u8A08\u306F\u672A\u5BFE\u5FDC\u3067\u3059\u3002\u5BFE\u5FDC\u306F SUM / COUNT / AVG / MIN / MAX \u3067\u3059`,
|
|
2136
|
+
this.peek()
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
if (ref.distinct) {
|
|
2140
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u96C6\u8A08\u3067\u306F\u5F15\u6570\u306E DISTINCT \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
2141
|
+
}
|
|
2142
|
+
this.advance();
|
|
2143
|
+
this.expect("(" /* LPAREN */);
|
|
2144
|
+
const partitionBy = [];
|
|
2145
|
+
if (this.isSoftKeyword("PARTITION")) {
|
|
2146
|
+
this.advance();
|
|
2147
|
+
this.expect("BY" /* BY */, "PARTITION \u306E\u5F8C\u306B\u306F BY \u304C\u5FC5\u8981\u3067\u3059");
|
|
2148
|
+
do {
|
|
2149
|
+
const field = this.parseQualifiedIdent();
|
|
2150
|
+
partitionBy.push({ type: "FIELD", tableAlias: field.tableAlias, field: field.field });
|
|
2151
|
+
} while (this.consume("," /* COMMA */));
|
|
2152
|
+
}
|
|
2153
|
+
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy(false)) : [];
|
|
2154
|
+
let frame = orderBy.length > 0 ? { unit: "RANGE", source: "DEFAULT" } : null;
|
|
2155
|
+
if (this.isSoftKeyword("ROWS") || this.isSoftKeyword("RANGE")) {
|
|
2156
|
+
if (orderBy.length === 0) {
|
|
2157
|
+
throw new ParseError("\u30D5\u30EC\u30FC\u30E0\u53E5\u306B\u306F OVER (ORDER BY ...) \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2158
|
+
}
|
|
2159
|
+
const unit = this.advance().value.toUpperCase();
|
|
2160
|
+
const valid = this.consume("BETWEEN" /* BETWEEN */) && this.consumeSoftKeyword("UNBOUNDED") && this.consumeSoftKeyword("PRECEDING") && this.consume("AND" /* AND */) && this.consumeSoftKeyword("CURRENT") && this.consumeSoftKeyword("ROW");
|
|
2161
|
+
if (!valid) {
|
|
2162
|
+
throw new ParseError(
|
|
2163
|
+
"\u5BFE\u5FDC\u3059\u308B\u30D5\u30EC\u30FC\u30E0\u306F BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW \u3060\u3051\u3067\u3059",
|
|
2164
|
+
this.peek()
|
|
2165
|
+
);
|
|
2166
|
+
}
|
|
2167
|
+
frame = { unit, source: "EXPLICIT" };
|
|
2168
|
+
}
|
|
2169
|
+
this.expect(")" /* RPAREN */);
|
|
2170
|
+
if (this.isArithOp(this.peek().kind)) {
|
|
2171
|
+
throw new ParseError(
|
|
2172
|
+
"\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306E\u7D50\u679C\u3092\u5F0F\u306B\u542B\u3081\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002CTE \u3067\u4E00\u5EA6\u5B9F\u4F53\u5316\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
2173
|
+
this.peek()
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
2176
|
+
if (!this.consume("AS" /* AS */)) {
|
|
2177
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2178
|
+
}
|
|
2179
|
+
const parsedAlias = this.parseAliasName();
|
|
2180
|
+
return this.withAliasDisplay({
|
|
2181
|
+
type: "WINDOW_COL",
|
|
2182
|
+
windowKind: "AGGREGATE",
|
|
2183
|
+
aggFunc: ref.func,
|
|
2184
|
+
arg: ref.arg,
|
|
2185
|
+
frame,
|
|
2186
|
+
partitionBy,
|
|
2187
|
+
orderBy,
|
|
2188
|
+
alias: parsedAlias.alias
|
|
2189
|
+
}, parsedAlias);
|
|
2190
|
+
}
|
|
2081
2191
|
selectColumnHasAggregate(column) {
|
|
2082
2192
|
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
2083
2193
|
if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
@@ -2095,6 +2205,7 @@ var Parser = class {
|
|
|
2095
2205
|
}
|
|
2096
2206
|
stringFuncArgHasAggregate(arg) {
|
|
2097
2207
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
2208
|
+
if (arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") return false;
|
|
2098
2209
|
return this.scalarValueHasAggregate(arg);
|
|
2099
2210
|
}
|
|
2100
2211
|
scalarValueHasAggregate(expr) {
|
|
@@ -2137,7 +2248,7 @@ var Parser = class {
|
|
|
2137
2248
|
parseAggArithMulDiv() {
|
|
2138
2249
|
return this.continueAggArithMulDiv(this.parseAggPrimary());
|
|
2139
2250
|
}
|
|
2140
|
-
/** 集計算術式の一次式: 集計関数 /
|
|
2251
|
+
/** 集計算術式の一次式: 集計関数 / 数値 / 変数 / GROUP BY キー候補 / 括弧 */
|
|
2141
2252
|
parseAggPrimary() {
|
|
2142
2253
|
if (this.consume("(" /* LPAREN */)) {
|
|
2143
2254
|
const inner = this.continueAggArith(this.parseAggPrimary());
|
|
@@ -2154,12 +2265,99 @@ var Parser = class {
|
|
|
2154
2265
|
const tok = this.advance();
|
|
2155
2266
|
return makeNumberLiteral(tok.value);
|
|
2156
2267
|
}
|
|
2268
|
+
if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
|
|
2269
|
+
const tok = this.advance();
|
|
2270
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
2271
|
+
}
|
|
2157
2272
|
const aggFunc = this.tryAggregateFunc();
|
|
2158
2273
|
if (aggFunc !== null) {
|
|
2159
|
-
|
|
2274
|
+
const ref = this.parseAggregateRef(aggFunc);
|
|
2275
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2276
|
+
return ref;
|
|
2277
|
+
}
|
|
2278
|
+
if (this.peek().kind === "IDENT" /* IDENT */ || this.peek().kind === "BIDENT" /* BIDENT */) {
|
|
2279
|
+
const tok = this.peek();
|
|
2280
|
+
const parsed = this.parseQualifiedIdent();
|
|
2281
|
+
const ref = {
|
|
2282
|
+
type: "AGG_GROUP_KEY",
|
|
2283
|
+
field: parsed.field,
|
|
2284
|
+
...parsed.tableAlias ? { tableAlias: parsed.tableAlias } : {}
|
|
2285
|
+
};
|
|
2286
|
+
this.aggregateGroupKeyTokens.set(ref, tok);
|
|
2287
|
+
return ref;
|
|
2160
2288
|
}
|
|
2161
2289
|
throw new ParseError("\u96C6\u8A08\u7B97\u8853\u5F0F\u306B\u306F\u96C6\u8A08\u95A2\u6570\u307E\u305F\u306F\u6570\u5024\u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2162
2290
|
}
|
|
2291
|
+
/** B124 Phase 1 はトップレベルの非集計オペランド開始形を明示拒否する。 */
|
|
2292
|
+
isNonAggregateArithmeticStartWithAggregate() {
|
|
2293
|
+
const first = this.peek();
|
|
2294
|
+
if (this.tryAggregateFunc() !== null || first.kind === "CASE" /* CASE */ || first.kind === "IF" /* IF */) return false;
|
|
2295
|
+
if (this.isGroupingFunctionStart()) return false;
|
|
2296
|
+
if (this.tryStringFuncName() !== null) return false;
|
|
2297
|
+
if (!["IDENT" /* IDENT */, "BIDENT" /* BIDENT */, "VARIABLE" /* VARIABLE */, "(" /* LPAREN */].includes(first.kind)) return false;
|
|
2298
|
+
let depth = 0;
|
|
2299
|
+
let sawArithmetic = false;
|
|
2300
|
+
for (let index = this.pos; index < this.tokens.length; index++) {
|
|
2301
|
+
const token = this.tokens[index];
|
|
2302
|
+
if (depth === 0 && index > this.pos && (token.kind === "," /* COMMA */ || token.kind === "AS" /* AS */ || token.kind === "FROM" /* FROM */ || token.kind === ";" /* SEMICOLON */ || token.kind === "EOF" /* EOF */ || token.kind === "=" /* EQ */ || token.kind === "!=" /* NEQ */ || token.kind === "<>" /* LT_GT */ || token.kind === ">" /* GT */ || token.kind === "<" /* LT */ || token.kind === ">=" /* GTE */ || token.kind === "<=" /* LTE */ || token.kind === "AND" /* AND */ || token.kind === "OR" /* OR */)) break;
|
|
2303
|
+
if (this.isArithOp(token.kind)) sawArithmetic = true;
|
|
2304
|
+
if (PARSER_AGGREGATE_FUNCTION_TOKEN_MAP[token.kind] !== void 0 && this.tokens[index + 1]?.kind === "(" /* LPAREN */) return sawArithmetic;
|
|
2305
|
+
if (token.kind === "(" /* LPAREN */) depth++;
|
|
2306
|
+
else if (token.kind === ")" /* RPAREN */) {
|
|
2307
|
+
depth--;
|
|
2308
|
+
if (depth < 0) break;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
return false;
|
|
2312
|
+
}
|
|
2313
|
+
/** SELECT ローカルの B124 leaf だけを ordinary GROUP BY の表記と照合する。 */
|
|
2314
|
+
validateAggregateGroupKeyRefs(columns, having, groupBy, grouping) {
|
|
2315
|
+
const refs = [];
|
|
2316
|
+
const visit = (node) => {
|
|
2317
|
+
if (Array.isArray(node)) {
|
|
2318
|
+
node.forEach(visit);
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
if (node === null || typeof node !== "object") return;
|
|
2322
|
+
const value = node;
|
|
2323
|
+
if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
|
|
2324
|
+
if (value["type"] === "AGG_GROUP_KEY") {
|
|
2325
|
+
refs.push(node);
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
Object.values(value).forEach(visit);
|
|
2329
|
+
};
|
|
2330
|
+
visit(columns);
|
|
2331
|
+
visit(having);
|
|
2332
|
+
if (refs.length === 0) return;
|
|
2333
|
+
const first = refs[0];
|
|
2334
|
+
const firstToken = this.aggregateGroupKeyTokens.get(first) ?? this.peek();
|
|
2335
|
+
if (grouping !== void 0) {
|
|
2336
|
+
throw new ParseError(
|
|
2337
|
+
"ROLLUP / CUBE / GROUPING SETS \u3067\u306F\u96C6\u8A08\u7B97\u8853\u5F0F\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u66F8\u3051\u307E\u305B\u3093\uFF08\u5C0F\u8A08\u30FB\u7DCF\u8A08\u884C\u3067\u5024\u304C\u5B9A\u307E\u3089\u306A\u3044\u305F\u3081\u3067\u3059\uFF09\u3002",
|
|
2338
|
+
firstToken
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
if (groupBy.length === 0) {
|
|
2342
|
+
throw new ParseError(
|
|
2343
|
+
`\u96C6\u8A08\u7B97\u8853\u5F0F\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u66F8\u304F\u306B\u306F GROUP BY \u304C\u5FC5\u8981\u3067\u3059\uFF08${this.aggregateGroupKeyDisplay(first)}\uFF09\u3002`,
|
|
2344
|
+
firstToken
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
const ordinaryNames = new Set(groupBy.filter((key) => key.type === "FIELD_NAME").map((key) => key.name));
|
|
2348
|
+
for (const ref of refs) {
|
|
2349
|
+
const display = this.aggregateGroupKeyDisplay(ref);
|
|
2350
|
+
if (!ordinaryNames.has(display)) {
|
|
2351
|
+
throw new ParseError(
|
|
2352
|
+
`\u96C6\u8A08\u7B97\u8853\u5F0F\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u306F GROUP BY \u306B\u66F8\u3044\u305F\u8868\u8A18\u3068\u4E00\u81F4\u3059\u308B\u5217\u3060\u3051\u3067\u3059\uFF08${display}\uFF09\u3002\u30B0\u30EB\u30FC\u30D7\u5185\u3067\u5024\u304C\u5B9A\u307E\u3089\u306A\u3044\u305F\u3081\u3067\u3059\u3002`,
|
|
2353
|
+
this.aggregateGroupKeyTokens.get(ref) ?? firstToken
|
|
2354
|
+
);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
aggregateGroupKeyDisplay(ref) {
|
|
2359
|
+
return ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
2360
|
+
}
|
|
2163
2361
|
// ──────────────────────────────────────────────────
|
|
2164
2362
|
// 汎用スカラー値式パーサー(B38)
|
|
2165
2363
|
// ──────────────────────────────────────────────────
|
|
@@ -2405,7 +2603,9 @@ var Parser = class {
|
|
|
2405
2603
|
}
|
|
2406
2604
|
const aggregateFunc = this.tryAggregateFunc();
|
|
2407
2605
|
if (aggregateFunc !== null && allowAggregateResult) {
|
|
2408
|
-
|
|
2606
|
+
const ref = this.parseAggregateRef(aggregateFunc);
|
|
2607
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2608
|
+
return this.continueAggArith(ref);
|
|
2409
2609
|
}
|
|
2410
2610
|
if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
2411
2611
|
return this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
@@ -2905,6 +3105,12 @@ var Parser = class {
|
|
|
2905
3105
|
// - 集計関数(HAVING のみ): COUNT(*) / SUM(f) ...
|
|
2906
3106
|
// - 通常フィールド参照: [alias.]field
|
|
2907
3107
|
parseFieldValue() {
|
|
3108
|
+
if (this.groupingFieldContext === "HAVING" && this.isNonAggregateArithmeticStartWithAggregate()) {
|
|
3109
|
+
throw new ParseError(
|
|
3110
|
+
`\u96C6\u8A08\u7B97\u8853\u5F0F\u306F\u96C6\u8A08\u95A2\u6570\u304B\u3089\u59CB\u307E\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08${this.peek().value}\uFF09\u3002`,
|
|
3111
|
+
this.peek()
|
|
3112
|
+
);
|
|
3113
|
+
}
|
|
2908
3114
|
if (this.isUnsupportedGroupingIdStart()) {
|
|
2909
3115
|
throw new ParseError("B65: GROUPING_ID is not supported in Phase1.", this.peek());
|
|
2910
3116
|
}
|
|
@@ -2930,6 +3136,7 @@ var Parser = class {
|
|
|
2930
3136
|
throw new ParseError("\u96C6\u8A08\u95A2\u6570\u306E\u5F15\u6570\u5185\u306B\u96C6\u8A08\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
2931
3137
|
}
|
|
2932
3138
|
const ref = this.parseAggregateRef(aggFunc);
|
|
3139
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2933
3140
|
if (this.isArithOp(this.peek().kind)) {
|
|
2934
3141
|
return {
|
|
2935
3142
|
type: "AGG_FIELD",
|
|
@@ -3388,6 +3595,16 @@ var Parser = class {
|
|
|
3388
3595
|
* フィールド名/alias: 名前 / total
|
|
3389
3596
|
*/
|
|
3390
3597
|
parseOrderByKey(allowGrouping = true) {
|
|
3598
|
+
const aggregateStart = this.tryAggregateFunc();
|
|
3599
|
+
if (aggregateStart !== null) {
|
|
3600
|
+
const start = this.pos;
|
|
3601
|
+
const ref = this.parseAggregateRef(aggregateStart);
|
|
3602
|
+
if (this.isSoftKeyword("OVER")) {
|
|
3603
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F SELECT \u5217\u306B\u306E\u307F\u8A18\u8FF0\u3067\u304D\u307E\u3059", this.peek());
|
|
3604
|
+
}
|
|
3605
|
+
this.pos = start;
|
|
3606
|
+
void ref;
|
|
3607
|
+
}
|
|
3391
3608
|
if (this.isUnsupportedGroupingIdStart()) {
|
|
3392
3609
|
throw new ParseError("B65: GROUPING_ID is not supported in Phase1.", this.peek());
|
|
3393
3610
|
}
|
|
@@ -3911,6 +4128,11 @@ var Parser = class {
|
|
|
3911
4128
|
isSoftKeyword(value) {
|
|
3912
4129
|
return this.peek().kind === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === value;
|
|
3913
4130
|
}
|
|
4131
|
+
rejectAggregateWindowOutsideSelect() {
|
|
4132
|
+
if (this.isSoftKeyword("OVER")) {
|
|
4133
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F SELECT \u5217\u306B\u306E\u307F\u8A18\u8FF0\u3067\u304D\u307E\u3059", this.peek());
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
3914
4136
|
validateUpdateFromAssignments(assignments, sourceAlias, tok) {
|
|
3915
4137
|
for (const assignment of assignments) {
|
|
3916
4138
|
if (assignment.value.type === "STRING_FUNC") {
|
|
@@ -4426,7 +4648,11 @@ function selectCompleteInputReasons(stmt) {
|
|
|
4426
4648
|
if (stmt.distinct) reasons.add("DISTINCT");
|
|
4427
4649
|
if (stmt.orderBy.length > 0) reasons.add("LOCAL_ORDER");
|
|
4428
4650
|
for (const column of stmt.columns) {
|
|
4429
|
-
if (column.type === "WINDOW_COL" && column.
|
|
4651
|
+
if (column.type === "WINDOW_COL" && column.windowKind === "AGGREGATE") {
|
|
4652
|
+
reasons.add("AGGREGATE_WINDOW");
|
|
4653
|
+
} else if (column.type === "WINDOW_COL" && column.orderBy.length > 0) {
|
|
4654
|
+
reasons.add("WINDOW_ORDER");
|
|
4655
|
+
}
|
|
4430
4656
|
if (column.type === "SCALAR_SUBQUERY_COL") addReasons(reasons, selectCompleteInputReasons(column.query));
|
|
4431
4657
|
if (column.type === "CASE_COL") {
|
|
4432
4658
|
for (const branch of column.expr.branches) addReasons(reasons, whereCompleteInputReasons(branch.condition));
|
|
@@ -5688,7 +5914,7 @@ function collectStringFuncFields(expr, out) {
|
|
|
5688
5914
|
}
|
|
5689
5915
|
}
|
|
5690
5916
|
function collectStringFuncArgFields(arg, out) {
|
|
5691
|
-
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
5917
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH" || arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") {
|
|
5692
5918
|
collectAggOperandFields(arg, out);
|
|
5693
5919
|
return;
|
|
5694
5920
|
}
|
|
@@ -5734,6 +5960,9 @@ function collectAggOperandFields(node, out) {
|
|
|
5734
5960
|
collectAggOperandFields(node.left, out);
|
|
5735
5961
|
collectAggOperandFields(node.right, out);
|
|
5736
5962
|
}
|
|
5963
|
+
if (node.type === "AGG_GROUP_KEY") {
|
|
5964
|
+
out.push(normalizeSimpleFieldRef(node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field));
|
|
5965
|
+
}
|
|
5737
5966
|
}
|
|
5738
5967
|
function collectAggregateArgFields(node, out) {
|
|
5739
5968
|
if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
|
|
@@ -5742,6 +5971,7 @@ function collectAggregateArgFields(node, out) {
|
|
|
5742
5971
|
function hasAggregateInStringFuncExpr(expr) {
|
|
5743
5972
|
return expr.args.some((arg) => {
|
|
5744
5973
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
5974
|
+
if (arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") return false;
|
|
5745
5975
|
return scalarValueHasAggregate(arg);
|
|
5746
5976
|
});
|
|
5747
5977
|
}
|
|
@@ -5929,9 +6159,12 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
|
5929
6159
|
walkAgg(node.left, phase);
|
|
5930
6160
|
walkAgg(node.right, phase);
|
|
5931
6161
|
}
|
|
6162
|
+
if (node.type === "AGG_GROUP_KEY") {
|
|
6163
|
+
addFieldRef(node.field, node.tableAlias ?? null, phase);
|
|
6164
|
+
}
|
|
5932
6165
|
};
|
|
5933
6166
|
const walkStringArg = (arg, phase = "select") => {
|
|
5934
|
-
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
6167
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH" || arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") {
|
|
5935
6168
|
walkAgg(arg, phase);
|
|
5936
6169
|
return;
|
|
5937
6170
|
}
|
|
@@ -6104,6 +6337,9 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
|
6104
6337
|
case "SCALAR_SUBQUERY_COL":
|
|
6105
6338
|
break;
|
|
6106
6339
|
case "WINDOW_COL":
|
|
6340
|
+
if (col.windowKind === "AGGREGATE" && col.arg.type !== "WILDCARD") {
|
|
6341
|
+
walkAggregateArg(col.arg, "select");
|
|
6342
|
+
}
|
|
6107
6343
|
for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
|
|
6108
6344
|
for (const item of col.orderBy) walkOrderByKey(item.key, "select");
|
|
6109
6345
|
break;
|
|
@@ -8029,7 +8265,7 @@ function formatWithComma(num, digits) {
|
|
|
8029
8265
|
return decStr ? `${intFmt}.${decStr}` : intFmt;
|
|
8030
8266
|
}
|
|
8031
8267
|
function evalStringFuncArg(arg, row, resolveFieldType, resolveFieldSemantics2) {
|
|
8032
|
-
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
8268
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH" || arg.type === "AGG_GROUP_KEY") {
|
|
8033
8269
|
return String(evalMaterializedAggregateOperand(arg, row));
|
|
8034
8270
|
}
|
|
8035
8271
|
if (arg.type === "NUMBER") return numberLiteralText(arg);
|
|
@@ -8040,6 +8276,13 @@ function evalMaterializedAggregateOperand(node, row) {
|
|
|
8040
8276
|
if (node.type === "AGG_REF") {
|
|
8041
8277
|
return row[aggregateSyntheticName(node.func, node.distinct, node.arg)] ?? "";
|
|
8042
8278
|
}
|
|
8279
|
+
if (node.type === "AGG_GROUP_KEY") {
|
|
8280
|
+
const field = node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field;
|
|
8281
|
+
return Number(resolveFieldRef(row, field));
|
|
8282
|
+
}
|
|
8283
|
+
if (node.type === "VARIABLE") {
|
|
8284
|
+
throw new Error(`InternalError: unresolved aggregate arithmetic variable @${node.name}.`);
|
|
8285
|
+
}
|
|
8043
8286
|
const left = Number(evalMaterializedAggregateOperand(node.left, row));
|
|
8044
8287
|
const right = Number(evalMaterializedAggregateOperand(node.right, row));
|
|
8045
8288
|
switch (node.op) {
|
|
@@ -8541,7 +8784,7 @@ function collectStringFuncFields2(expr, out) {
|
|
|
8541
8784
|
for (const arg of expr.args) collectStringFuncArgFields2(arg, out);
|
|
8542
8785
|
}
|
|
8543
8786
|
function collectStringFuncArgFields2(arg, out) {
|
|
8544
|
-
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
8787
|
+
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH" || arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") {
|
|
8545
8788
|
collectAggOperandFields2(arg, out);
|
|
8546
8789
|
return;
|
|
8547
8790
|
}
|
|
@@ -8572,6 +8815,7 @@ function collectAggOperandFields2(node, out) {
|
|
|
8572
8815
|
collectAggOperandFields2(node.left, out);
|
|
8573
8816
|
collectAggOperandFields2(node.right, out);
|
|
8574
8817
|
}
|
|
8818
|
+
if (node.type === "AGG_GROUP_KEY") out.add(node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field);
|
|
8575
8819
|
}
|
|
8576
8820
|
function collectAggregateArgFields2(node, out) {
|
|
8577
8821
|
if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode2(node, out);
|
|
@@ -11076,7 +11320,7 @@ function valueNeedsFieldMetadata(value) {
|
|
|
11076
11320
|
return Object.values(item).some(valueNeedsFieldMetadata);
|
|
11077
11321
|
}
|
|
11078
11322
|
function selectNeedsOwnMetadata(statement) {
|
|
11079
|
-
return whereNeedsFieldMetadata(statement.where) || normalizeGroupingSpec(statement).type === "GROUPING_SETS" || statement.orderBy.length > 0 || statement.columns.some(
|
|
11323
|
+
return whereNeedsFieldMetadata(statement.where) || statement.groupBy.length > 0 || normalizeGroupingSpec(statement).type === "GROUPING_SETS" || statement.orderBy.length > 0 || statement.columns.some(
|
|
11080
11324
|
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
11081
11325
|
);
|
|
11082
11326
|
}
|
|
@@ -13199,26 +13443,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
13199
13443
|
if (arg.type === "WILDCARD") {
|
|
13200
13444
|
return func === "COUNT" ? rows.length : 0;
|
|
13201
13445
|
}
|
|
13202
|
-
const strValues =
|
|
13203
|
-
for (const row of rows) {
|
|
13204
|
-
let strVal;
|
|
13205
|
-
if (arg.type === "FIELD_REF") {
|
|
13206
|
-
const raw = row[arg.field];
|
|
13207
|
-
if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
|
|
13208
|
-
strVal = raw;
|
|
13209
|
-
} else if (arg.type === "ARITH" || arg.type === "NUMBER") {
|
|
13210
|
-
const n = evalArithExpr(arg, row);
|
|
13211
|
-
if (isNaN(n)) continue;
|
|
13212
|
-
strVal = String(n);
|
|
13213
|
-
} else {
|
|
13214
|
-
const value = evalScalarValueExprNullable(arg, row);
|
|
13215
|
-
if (value === null) continue;
|
|
13216
|
-
if (value === "" && func !== "MIN" && func !== "MAX") continue;
|
|
13217
|
-
if (typeof value === "number" && Number.isNaN(value)) continue;
|
|
13218
|
-
strVal = String(value);
|
|
13219
|
-
}
|
|
13220
|
-
strValues.push(strVal);
|
|
13221
|
-
}
|
|
13446
|
+
const strValues = aggregateRowValues(func, arg, rows).filter((value) => value !== null);
|
|
13222
13447
|
const statistical = func === "STDDEV_POP" || func === "STDDEV_SAMP" || func === "VAR_POP" || func === "VAR_SAMP" || func === "MEDIAN";
|
|
13223
13448
|
const numericValues = statistical ? strValues.map((value) => {
|
|
13224
13449
|
const numeric = Number(value);
|
|
@@ -13296,6 +13521,27 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
13296
13521
|
}
|
|
13297
13522
|
}
|
|
13298
13523
|
}
|
|
13524
|
+
function aggregateRowValues(func, arg, rows) {
|
|
13525
|
+
return rows.map((row) => {
|
|
13526
|
+
let strVal;
|
|
13527
|
+
if (arg.type === "FIELD_REF") {
|
|
13528
|
+
const raw = row[arg.field];
|
|
13529
|
+
if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") return null;
|
|
13530
|
+
strVal = raw;
|
|
13531
|
+
} else if (arg.type === "ARITH" || arg.type === "NUMBER") {
|
|
13532
|
+
const n = evalArithExpr(arg, row);
|
|
13533
|
+
if (isNaN(n)) return null;
|
|
13534
|
+
strVal = String(n);
|
|
13535
|
+
} else {
|
|
13536
|
+
const value = evalScalarValueExprNullable(arg, row);
|
|
13537
|
+
if (value === null) return null;
|
|
13538
|
+
if (value === "" && func !== "MIN" && func !== "MAX") return null;
|
|
13539
|
+
if (typeof value === "number" && Number.isNaN(value)) return null;
|
|
13540
|
+
strVal = String(value);
|
|
13541
|
+
}
|
|
13542
|
+
return strVal;
|
|
13543
|
+
});
|
|
13544
|
+
}
|
|
13299
13545
|
function toAggregateFieldRef(field) {
|
|
13300
13546
|
const dot = field.indexOf(".");
|
|
13301
13547
|
return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
|
|
@@ -13303,6 +13549,13 @@ function toAggregateFieldRef(field) {
|
|
|
13303
13549
|
function evalAggArithExpr(node, rows, resolveAggSortKind) {
|
|
13304
13550
|
if (node.type === "NUMBER") return node.value;
|
|
13305
13551
|
if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, node.separator, rows, resolveAggSortKind));
|
|
13552
|
+
if (node.type === "AGG_GROUP_KEY") {
|
|
13553
|
+
const field = node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field;
|
|
13554
|
+
return Number(resolveFieldRef(rows[0] ?? {}, field));
|
|
13555
|
+
}
|
|
13556
|
+
if (node.type === "VARIABLE") {
|
|
13557
|
+
throw new Error(`InternalError: unresolved aggregate arithmetic variable @${node.name}.`);
|
|
13558
|
+
}
|
|
13306
13559
|
const l = evalAggArithExpr(node.left, rows, resolveAggSortKind);
|
|
13307
13560
|
const r = evalAggArithExpr(node.right, rows, resolveAggSortKind);
|
|
13308
13561
|
switch (node.op) {
|
|
@@ -13526,7 +13779,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
|
|
|
13526
13779
|
}
|
|
13527
13780
|
return (name, row) => evaluators.get(name)?.(row);
|
|
13528
13781
|
}
|
|
13529
|
-
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
13782
|
+
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2, resolveAggSortKind) {
|
|
13530
13783
|
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
13531
13784
|
if (rows.length === 0 || windows.length === 0) return rows;
|
|
13532
13785
|
for (const window of windows) {
|
|
@@ -13540,6 +13793,10 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
|
13540
13793
|
for (const partition of partitions.values()) {
|
|
13541
13794
|
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
|
|
13542
13795
|
const sorted = sortedResult.rows;
|
|
13796
|
+
if (!isRankingWindow(window)) {
|
|
13797
|
+
applyAggregateWindow(window, sortedResult, resolveAggSortKind);
|
|
13798
|
+
continue;
|
|
13799
|
+
}
|
|
13543
13800
|
let rank = 1;
|
|
13544
13801
|
let denseRank = 1;
|
|
13545
13802
|
for (let index = 0; index < sorted.length; index++) {
|
|
@@ -13554,6 +13811,53 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
|
13554
13811
|
}
|
|
13555
13812
|
return rows;
|
|
13556
13813
|
}
|
|
13814
|
+
function applyAggregateWindow(window, sortedResult, resolveAggSortKind) {
|
|
13815
|
+
const sorted = sortedResult.rows;
|
|
13816
|
+
const values = window.arg.type === "WILDCARD" ? null : aggregateRowValues(window.aggFunc, window.arg, sorted.map((item) => item.row));
|
|
13817
|
+
const comparison = window.arg.type === "WILDCARD" ? void 0 : resolveAggregateArgSemantics(window.arg, resolveAggSortKind);
|
|
13818
|
+
const semantics = typeof comparison === "string" ? syntheticSemantics(comparison) : comparison ?? syntheticSemantics("string");
|
|
13819
|
+
const output = [];
|
|
13820
|
+
let count = 0;
|
|
13821
|
+
let sum = 0;
|
|
13822
|
+
let best;
|
|
13823
|
+
for (let index = 0; index < sorted.length; index++) {
|
|
13824
|
+
const value = values?.[index] ?? null;
|
|
13825
|
+
if (window.arg.type === "WILDCARD") {
|
|
13826
|
+
count++;
|
|
13827
|
+
} else if (value !== null) {
|
|
13828
|
+
if (window.aggFunc === "COUNT") {
|
|
13829
|
+
count++;
|
|
13830
|
+
} else if (window.aggFunc === "SUM" || window.aggFunc === "AVG") {
|
|
13831
|
+
sum += Number(value);
|
|
13832
|
+
count++;
|
|
13833
|
+
} else if (best === void 0) {
|
|
13834
|
+
best = value;
|
|
13835
|
+
} else {
|
|
13836
|
+
const cmp = compareCanonicalValues(value, best, semantics);
|
|
13837
|
+
if (window.aggFunc === "MAX" && cmp > 0 || window.aggFunc === "MIN" && cmp < 0) {
|
|
13838
|
+
best = value;
|
|
13839
|
+
}
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13842
|
+
const result = window.aggFunc === "COUNT" ? count : window.aggFunc === "SUM" ? sum : window.aggFunc === "AVG" ? count === 0 ? 0 : sum / count : best ?? 0;
|
|
13843
|
+
output.push(String(result));
|
|
13844
|
+
}
|
|
13845
|
+
if (window.frame === null) {
|
|
13846
|
+
const finalValue = output[output.length - 1];
|
|
13847
|
+
for (const item of sorted) item.row[window.alias] = finalValue;
|
|
13848
|
+
return;
|
|
13849
|
+
}
|
|
13850
|
+
if (window.frame.unit === "RANGE") {
|
|
13851
|
+
for (let start = 0; start < sorted.length; ) {
|
|
13852
|
+
let end = start;
|
|
13853
|
+
while (end + 1 < sorted.length && sortedResult.compare(sorted[end], sorted[end + 1]) === 0) end++;
|
|
13854
|
+
for (let index = start; index <= end; index++) sorted[index].row[window.alias] = output[end];
|
|
13855
|
+
start = end + 1;
|
|
13856
|
+
}
|
|
13857
|
+
return;
|
|
13858
|
+
}
|
|
13859
|
+
for (let index = 0; index < sorted.length; index++) sorted[index].row[window.alias] = output[index];
|
|
13860
|
+
}
|
|
13557
13861
|
function resolveWindowField(row, ref) {
|
|
13558
13862
|
const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
13559
13863
|
return resolveFieldRef(row, name);
|
|
@@ -13890,7 +14194,8 @@ function arithColDefaultKey(expr) {
|
|
|
13890
14194
|
}
|
|
13891
14195
|
function stringFuncDefaultKey(expr) {
|
|
13892
14196
|
const argStrs = expr.args.map((a) => {
|
|
13893
|
-
if (a.type === "AGG_REF" || a.type === "AGG_ARITH") return aggArithDefaultKey(a);
|
|
14197
|
+
if (a.type === "AGG_REF" || a.type === "AGG_ARITH" || a.type === "AGG_GROUP_KEY") return aggArithDefaultKey(a);
|
|
14198
|
+
if (a.type === "VARIABLE") return `@${a.name}`;
|
|
13894
14199
|
return scalarValueDefaultKey(a);
|
|
13895
14200
|
});
|
|
13896
14201
|
return `${expr.func}(${argStrs.join(",")})`;
|
|
@@ -13917,6 +14222,7 @@ function scalarValueDefaultKey(expr) {
|
|
|
13917
14222
|
}
|
|
13918
14223
|
function hasAggregateInStringFuncArg(arg) {
|
|
13919
14224
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
14225
|
+
if (arg.type === "AGG_GROUP_KEY" || arg.type === "VARIABLE") return false;
|
|
13920
14226
|
return scalarValueHasAggregate2(arg);
|
|
13921
14227
|
}
|
|
13922
14228
|
function scalarValueHasAggregate2(expr) {
|
|
@@ -13946,6 +14252,13 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
|
|
|
13946
14252
|
const value = evalAggArithExpr(arg, rows, resolveAggSortKind);
|
|
13947
14253
|
return { type: "NUMBER", value, raw: String(value) };
|
|
13948
14254
|
}
|
|
14255
|
+
if (arg.type === "AGG_GROUP_KEY") {
|
|
14256
|
+
const field = arg.tableAlias ? `${arg.tableAlias}.${arg.field}` : arg.field;
|
|
14257
|
+
return { type: "NUMBER", value: Number(resolveFieldRef(rows[0] ?? {}, field)), raw: resolveFieldRef(rows[0] ?? {}, field) };
|
|
14258
|
+
}
|
|
14259
|
+
if (arg.type === "VARIABLE") {
|
|
14260
|
+
throw new Error(`InternalError: unresolved aggregate arithmetic variable @${arg.name}.`);
|
|
14261
|
+
}
|
|
13949
14262
|
if (arg.type === "STRING_FUNC") {
|
|
13950
14263
|
return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
|
|
13951
14264
|
}
|
|
@@ -14020,12 +14333,19 @@ function mergeKnownColumns(left, right, rows) {
|
|
|
14020
14333
|
...Object.keys(rows[0] ?? {})
|
|
14021
14334
|
])];
|
|
14022
14335
|
}
|
|
14023
|
-
function deriveOutputOrderSemantics(columns) {
|
|
14336
|
+
function deriveOutputOrderSemantics(columns, resolveAggSortKind) {
|
|
14024
14337
|
const result = /* @__PURE__ */ new Map();
|
|
14025
14338
|
for (const column of columns) {
|
|
14026
14339
|
if (!("alias" in column) || !column.alias) continue;
|
|
14027
|
-
if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
14340
|
+
if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
14028
14341
|
result.set(column.alias, syntheticSemantics("number"));
|
|
14342
|
+
} else if (column.type === "WINDOW_COL") {
|
|
14343
|
+
if (isRankingWindow(column) || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
14344
|
+
result.set(column.alias, syntheticSemantics("number"));
|
|
14345
|
+
} else if (column.arg.type !== "WILDCARD") {
|
|
14346
|
+
const semantics = resolveAggregateArgSemantics(column.arg, resolveAggSortKind) ?? "string";
|
|
14347
|
+
result.set(column.alias, typeof semantics === "string" ? syntheticSemantics(semantics) : semantics);
|
|
14348
|
+
}
|
|
14029
14349
|
} else if (column.type === "AGGREGATE") {
|
|
14030
14350
|
if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG" || column.func === "STDDEV_POP" || column.func === "STDDEV_SAMP" || column.func === "VAR_POP" || column.func === "VAR_SAMP" || column.func === "MEDIAN") {
|
|
14031
14351
|
result.set(column.alias, syntheticSemantics("number"));
|
|
@@ -14060,7 +14380,7 @@ function runFullScan(input) {
|
|
|
14060
14380
|
resolvedGroupingSpec,
|
|
14061
14381
|
plainGroupByPlan
|
|
14062
14382
|
} = input;
|
|
14063
|
-
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
|
|
14383
|
+
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns, aggregateSortKindResolver);
|
|
14064
14384
|
for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
|
|
14065
14385
|
let rows = [];
|
|
14066
14386
|
const mainAlias = stmt.from.alias;
|
|
@@ -14116,7 +14436,14 @@ function runFullScan(input) {
|
|
|
14116
14436
|
}
|
|
14117
14437
|
const resolveHavingSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, aggregateSortKindResolver) : havingFieldSemanticsResolver?.(field);
|
|
14118
14438
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, resolveHavingSemantics);
|
|
14119
|
-
rows = applyWindow(
|
|
14439
|
+
rows = applyWindow(
|
|
14440
|
+
rows,
|
|
14441
|
+
stmt.columns,
|
|
14442
|
+
optionOrders,
|
|
14443
|
+
sortKinds,
|
|
14444
|
+
effectiveOrderSemantics,
|
|
14445
|
+
aggregateSortKindResolver
|
|
14446
|
+
);
|
|
14120
14447
|
if (stmt.distinct) {
|
|
14121
14448
|
rows = applyDistinct(
|
|
14122
14449
|
rows,
|
|
@@ -16601,8 +16928,8 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
16601
16928
|
tempTables
|
|
16602
16929
|
);
|
|
16603
16930
|
const first = resolvedStmt2.expr.query.columns[0];
|
|
16604
|
-
let numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG" || first.func === "STDDEV_POP" || first.func === "STDDEV_SAMP" || first.func === "VAR_POP" || first.func === "VAR_SAMP" || first.func === "MEDIAN");
|
|
16605
|
-
if (first?.type === "AGGREGATE" && first.func === "MODE") {
|
|
16931
|
+
let numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" && (first.windowKind !== "AGGREGATE" || first.aggFunc === "COUNT" || first.aggFunc === "SUM" || first.aggFunc === "AVG") || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG" || first.func === "STDDEV_POP" || first.func === "STDDEV_SAMP" || first.func === "VAR_POP" || first.func === "VAR_SAMP" || first.func === "MEDIAN");
|
|
16932
|
+
if (first?.type === "AGGREGATE" && first.func === "MODE" || first?.type === "WINDOW_COL" && first.windowKind === "AGGREGATE" && (first.aggFunc === "MIN" || first.aggFunc === "MAX")) {
|
|
16606
16933
|
const meta = (await inferSelectColumnMeta(
|
|
16607
16934
|
resolvedStmt2.expr.query,
|
|
16608
16935
|
["__scalar__"],
|
|
@@ -16924,7 +17251,15 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
|
|
|
16924
17251
|
`ArgumentError: variable @${obj["name"]} is not numeric and cannot be used in arithmetic.`
|
|
16925
17252
|
);
|
|
16926
17253
|
}
|
|
16927
|
-
return numericArithmeticOperand && value.type === "string" && value.placeholder === true ? {
|
|
17254
|
+
return numericArithmeticOperand && value.type === "string" && value.placeholder === true ? {
|
|
17255
|
+
type: "NUMBER",
|
|
17256
|
+
value: 0,
|
|
17257
|
+
raw: numericArithmeticOperand === "AGG_ARITH" ? `@${obj["name"]}` : value.value
|
|
17258
|
+
} : value.type === "number" ? {
|
|
17259
|
+
type: "NUMBER",
|
|
17260
|
+
value: value.value,
|
|
17261
|
+
raw: numericArithmeticOperand === "AGG_ARITH" ? `@${obj["name"]}` : value.raw ?? String(value.value)
|
|
17262
|
+
} : { type: "STRING", value: value.value };
|
|
16928
17263
|
}
|
|
16929
17264
|
if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && typeof obj["alias"] === "string") {
|
|
16930
17265
|
const value = variables.get(obj["name"]);
|
|
@@ -16943,7 +17278,7 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
|
|
|
16943
17278
|
resolveBatchVariableReferencesInternal(
|
|
16944
17279
|
value,
|
|
16945
17280
|
variables,
|
|
16946
|
-
|
|
17281
|
+
key === "left" || key === "right" ? obj["type"] === "AGG_ARITH" ? "AGG_ARITH" : obj["type"] === "ARITH" || obj["type"] === "SCALAR_ARITH" ? "ARITH" : false : false
|
|
16947
17282
|
)
|
|
16948
17283
|
])
|
|
16949
17284
|
);
|
|
@@ -17228,8 +17563,21 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
|
|
|
17228
17563
|
if (!("alias" in column) || !column.alias) continue;
|
|
17229
17564
|
let semantics;
|
|
17230
17565
|
if (column.type === "FIELD") semantics = rowResolver(aggregateFieldRef(column.field));
|
|
17231
|
-
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
17566
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
17232
17567
|
semantics = syntheticSemantics("number");
|
|
17568
|
+
} else if (column.type === "WINDOW_COL") {
|
|
17569
|
+
if (column.windowKind !== "AGGREGATE" || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
17570
|
+
semantics = syntheticSemantics("number");
|
|
17571
|
+
} else if (column.arg.type !== "WILDCARD") {
|
|
17572
|
+
semantics = inferAggregateArgMeta(column.arg, (ref) => {
|
|
17573
|
+
const resolved = rowResolver(ref);
|
|
17574
|
+
return resolved ? {
|
|
17575
|
+
sortKind: resolved.compareMode === "number" || resolved.compareMode === "recordNumber" ? "number" : "string",
|
|
17576
|
+
fieldType: resolved.fieldType,
|
|
17577
|
+
semantics: resolved
|
|
17578
|
+
} : void 0;
|
|
17579
|
+
}).semantics;
|
|
17580
|
+
}
|
|
17233
17581
|
} else if (column.type === "AGGREGATE") {
|
|
17234
17582
|
if (column.func === "MIN" || column.func === "MAX" || column.func === "MODE") {
|
|
17235
17583
|
if (column.arg.type !== "WILDCARD") {
|
|
@@ -17591,6 +17939,7 @@ async function validateSelectGroupingPlanning(stmt, client, cacheContext, materi
|
|
|
17591
17939
|
function completeInputErrorPrefix(reasons) {
|
|
17592
17940
|
const reasonList = [...reasons].join(", ");
|
|
17593
17941
|
const aggregateSubjects = [
|
|
17942
|
+
["AGGREGATE_WINDOW", "\u96C6\u8A08\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17594
17943
|
["GROUPING_SETS", "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17595
17944
|
["STATISTICAL_AGGREGATE", "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17596
17945
|
["AGGREGATE", "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
@@ -17646,6 +17995,8 @@ function arithHasFieldRef(node) {
|
|
|
17646
17995
|
return false;
|
|
17647
17996
|
}
|
|
17648
17997
|
function stringFuncArgHasFieldRef(arg) {
|
|
17998
|
+
if (arg.type === "AGG_GROUP_KEY") return true;
|
|
17999
|
+
if (arg.type === "VARIABLE") return false;
|
|
17649
18000
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
17650
18001
|
return scalarValueHasFieldRef(arg);
|
|
17651
18002
|
}
|
|
@@ -18203,7 +18554,11 @@ function collectAggregateArgFieldRefs(arg, out) {
|
|
|
18203
18554
|
}
|
|
18204
18555
|
if (arg.type === "STRING_FUNC") {
|
|
18205
18556
|
for (const child of arg.args) {
|
|
18206
|
-
if (child.type
|
|
18557
|
+
if (child.type === "AGG_GROUP_KEY") {
|
|
18558
|
+
out.push({ type: "FIELD", tableAlias: child.tableAlias ?? null, field: child.field });
|
|
18559
|
+
} else if (child.type !== "AGG_REF" && child.type !== "AGG_ARITH" && child.type !== "VARIABLE") {
|
|
18560
|
+
collectAggregateArgFieldRefs(child, out);
|
|
18561
|
+
}
|
|
18207
18562
|
}
|
|
18208
18563
|
return;
|
|
18209
18564
|
}
|
|
@@ -18223,11 +18578,16 @@ function collectAggregateOperandRefs(node, out) {
|
|
|
18223
18578
|
collectAggregateOperandRefs(node.left, out);
|
|
18224
18579
|
collectAggregateOperandRefs(node.right, out);
|
|
18225
18580
|
}
|
|
18581
|
+
if (node.type === "AGG_GROUP_KEY") out.push({ type: "FIELD", tableAlias: node.tableAlias ?? null, field: node.field });
|
|
18226
18582
|
}
|
|
18227
18583
|
function collectStringFuncAggregateRefs(expr, out) {
|
|
18228
18584
|
for (const arg of expr.args) {
|
|
18229
18585
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
18230
18586
|
collectAggregateOperandRefs(arg, out);
|
|
18587
|
+
} else if (arg.type === "AGG_GROUP_KEY") {
|
|
18588
|
+
out.push({ type: "FIELD", tableAlias: arg.tableAlias ?? null, field: arg.field });
|
|
18589
|
+
} else if (arg.type === "VARIABLE") {
|
|
18590
|
+
continue;
|
|
18231
18591
|
} else {
|
|
18232
18592
|
collectScalarAggregateRefs(arg, out);
|
|
18233
18593
|
}
|
|
@@ -18504,12 +18864,18 @@ function inferAggregateArgMeta(arg, resolveField2) {
|
|
|
18504
18864
|
if (arg.elseResult) results.push(caseResultColumnMeta(arg.elseResult, resolveField2));
|
|
18505
18865
|
return mergeExpressionColumnMeta(results);
|
|
18506
18866
|
}
|
|
18867
|
+
function inferWindowColumnMeta(column, resolveField2) {
|
|
18868
|
+
if (column.windowKind !== "AGGREGATE" || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
18869
|
+
return syntheticColumnMeta("number");
|
|
18870
|
+
}
|
|
18871
|
+
return column.arg.type === "WILDCARD" ? unknownStringColumnMeta() : inferAggregateArgMeta(column.arg, resolveField2);
|
|
18872
|
+
}
|
|
18507
18873
|
function withDisplayName(meta, displayName) {
|
|
18508
18874
|
return { ...meta ?? {}, displayName };
|
|
18509
18875
|
}
|
|
18510
18876
|
function selectNeedsSourceColumnMeta(stmt) {
|
|
18511
18877
|
return stmt.columns.some(
|
|
18512
|
-
(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")
|
|
18878
|
+
(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") || column.type === "WINDOW_COL" && column.windowKind === "AGGREGATE" && (column.aggFunc === "MIN" || column.aggFunc === "MAX")
|
|
18513
18879
|
);
|
|
18514
18880
|
}
|
|
18515
18881
|
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables, forLibraryCapture = false) {
|
|
@@ -18615,7 +18981,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
18615
18981
|
} else if (column.type === "STRFUNC_COL") {
|
|
18616
18982
|
meta = stringFunctionColumnMeta(column.expr);
|
|
18617
18983
|
} else if (column.type === "WINDOW_COL") {
|
|
18618
|
-
meta =
|
|
18984
|
+
meta = inferWindowColumnMeta(column, resolveField2);
|
|
18619
18985
|
} else if (column.type === "CASE_COL") {
|
|
18620
18986
|
const results = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
|
|
18621
18987
|
if (column.expr.elseResult) results.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
|
|
@@ -19542,8 +19908,10 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
|
|
|
19542
19908
|
if (!("alias" in column) || !column.alias) continue;
|
|
19543
19909
|
let meta;
|
|
19544
19910
|
if (column.type === "FIELD") meta = resolveField2(aggregateFieldRef(column.field));
|
|
19545
|
-
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
19911
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
19546
19912
|
meta = syntheticColumnMeta("number");
|
|
19913
|
+
} else if (column.type === "WINDOW_COL") {
|
|
19914
|
+
meta = inferWindowColumnMeta(column, resolveField2);
|
|
19547
19915
|
} else if (column.type === "GROUPING_COL") {
|
|
19548
19916
|
meta = syntheticColumnMeta("number");
|
|
19549
19917
|
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta = syntheticColumnMeta("string");
|
|
@@ -23581,6 +23949,20 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23581
23949
|
}
|
|
23582
23950
|
}
|
|
23583
23951
|
}
|
|
23952
|
+
for (const column of stmt.columns) {
|
|
23953
|
+
if (column.type !== "WINDOW_COL" || column.windowKind !== "AGGREGATE") continue;
|
|
23954
|
+
const clauses = [];
|
|
23955
|
+
if (column.partitionBy.length > 0) {
|
|
23956
|
+
clauses.push(`PARTITION BY ${column.partitionBy.map(
|
|
23957
|
+
(ref) => ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field
|
|
23958
|
+
).join(", ")}`);
|
|
23959
|
+
}
|
|
23960
|
+
if (column.orderBy.length > 0) {
|
|
23961
|
+
clauses.push(`ORDER BY ${column.orderBy.map(formatOrderByItem).join(", ")}`);
|
|
23962
|
+
}
|
|
23963
|
+
lines.push(` window ${column.alias}: ${column.aggFunc} OVER (${clauses.join(" ")})`);
|
|
23964
|
+
lines.push(column.frame === null ? " frame: PARTITION ENTIRE" : ` frame: ${column.frame.unit} UNBOUNDED PRECEDING AND CURRENT ROW${column.frame.source === "DEFAULT" ? " (\u65E2\u5B9A)" : ""}`);
|
|
23965
|
+
}
|
|
23584
23966
|
if (totalCountPlan) {
|
|
23585
23967
|
const baseQuery = stmt.where === null ? "" : whereToKintone(stmt.where);
|
|
23586
23968
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|
|
@@ -24187,7 +24569,8 @@ function collectArithNodeRefs(node, out) {
|
|
|
24187
24569
|
}
|
|
24188
24570
|
if (node.type === "STRING_FUNC") {
|
|
24189
24571
|
for (const arg of node.args) {
|
|
24190
|
-
if (arg.type
|
|
24572
|
+
if (arg.type === "AGG_GROUP_KEY") out.add(arg.tableAlias ? `${arg.tableAlias}.${arg.field}` : arg.field);
|
|
24573
|
+
else if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH" && arg.type !== "VARIABLE") collectScalarNodeRefs(arg, out);
|
|
24191
24574
|
}
|
|
24192
24575
|
}
|
|
24193
24576
|
}
|
|
@@ -24249,7 +24632,10 @@ function collectScalarNodeRefs(node, out) {
|
|
|
24249
24632
|
return;
|
|
24250
24633
|
}
|
|
24251
24634
|
if (node.type === "STRING_FUNC") {
|
|
24252
|
-
for (const arg of node.args)
|
|
24635
|
+
for (const arg of node.args) {
|
|
24636
|
+
if (arg.type === "AGG_GROUP_KEY") out.add(arg.tableAlias ? `${arg.tableAlias}.${arg.field}` : arg.field);
|
|
24637
|
+
else if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH" && arg.type !== "VARIABLE") collectScalarNodeRefs(arg, out);
|
|
24638
|
+
}
|
|
24253
24639
|
return;
|
|
24254
24640
|
}
|
|
24255
24641
|
if (node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP") {
|