@rex0220/kintone-sql-tools 3.44.0 → 3.45.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 +264 -35
- 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 +14 -14
- package/dist-engine/meta/esm.json +14 -14
- package/dist-engine/meta/umd.json +14 -14
- package/dist-mcp/ksql-mcp.js +287 -42
- 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
|
}
|
|
@@ -1318,6 +1321,11 @@ var Parser = class {
|
|
|
1318
1321
|
}
|
|
1319
1322
|
throw new ParseError(msg, tok);
|
|
1320
1323
|
}
|
|
1324
|
+
consumeSoftKeyword(word) {
|
|
1325
|
+
if (!this.isSoftKeyword(word)) return false;
|
|
1326
|
+
this.advance();
|
|
1327
|
+
return true;
|
|
1328
|
+
}
|
|
1321
1329
|
parseTempTableName() {
|
|
1322
1330
|
const tok = this.peek();
|
|
1323
1331
|
if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
|
|
@@ -1957,6 +1965,12 @@ var Parser = class {
|
|
|
1957
1965
|
const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
1958
1966
|
return this.withAliasDisplay({ type: "GROUPING_COL", ref, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
|
|
1959
1967
|
}
|
|
1968
|
+
if (this.tryAggregateFunc() === null && this.hasNestedAggregateWindowInSelectColumn()) {
|
|
1969
|
+
throw new ParseError(
|
|
1970
|
+
"\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",
|
|
1971
|
+
this.peek()
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1960
1974
|
if (this.tryAggregateFunc() === null && this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
1961
1975
|
const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
1962
1976
|
const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -2001,6 +2015,9 @@ var Parser = class {
|
|
|
2001
2015
|
const aggFunc = this.tryAggregateFunc();
|
|
2002
2016
|
if (aggFunc !== null) {
|
|
2003
2017
|
const ref = this.parseAggregateRef(aggFunc);
|
|
2018
|
+
if (this.isSoftKeyword("OVER")) {
|
|
2019
|
+
return this.parseAggregateWindowColumn(ref);
|
|
2020
|
+
}
|
|
2004
2021
|
if (this.isArithOp(this.peek().kind)) {
|
|
2005
2022
|
const expr = this.continueAggArith(ref);
|
|
2006
2023
|
const parsedAlias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
@@ -2052,6 +2069,28 @@ var Parser = class {
|
|
|
2052
2069
|
tryWindowFunc() {
|
|
2053
2070
|
return PARSER_WINDOW_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
|
|
2054
2071
|
}
|
|
2072
|
+
hasNestedAggregateWindowInSelectColumn() {
|
|
2073
|
+
let depth = 0;
|
|
2074
|
+
for (let index = this.pos; index < this.tokens.length; index++) {
|
|
2075
|
+
const token = this.tokens[index];
|
|
2076
|
+
if (depth === 0 && (token.kind === "," /* COMMA */ || token.kind === "FROM" /* FROM */ || token.kind === ";" /* SEMICOLON */ || token.kind === "EOF" /* EOF */)) return false;
|
|
2077
|
+
if (PARSER_AGGREGATE_FUNCTION_TOKEN_MAP[token.kind] !== void 0 && this.tokens[index + 1]?.kind === "(" /* LPAREN */) {
|
|
2078
|
+
let aggregateDepth = 0;
|
|
2079
|
+
for (let cursor = index + 1; cursor < this.tokens.length; cursor++) {
|
|
2080
|
+
const candidate = this.tokens[cursor];
|
|
2081
|
+
if (candidate.kind === "(" /* LPAREN */) aggregateDepth++;
|
|
2082
|
+
else if (candidate.kind === ")" /* RPAREN */ && --aggregateDepth === 0) {
|
|
2083
|
+
const next = this.tokens[cursor + 1];
|
|
2084
|
+
if (next?.kind === "IDENT" /* IDENT */ && next.value.toUpperCase() === "OVER") return true;
|
|
2085
|
+
break;
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
if (token.kind === "(" /* LPAREN */) depth++;
|
|
2090
|
+
else if (token.kind === ")" /* RPAREN */) depth--;
|
|
2091
|
+
}
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2055
2094
|
parseWindowColumn(func) {
|
|
2056
2095
|
this.advance();
|
|
2057
2096
|
this.expect("(" /* LPAREN */);
|
|
@@ -2078,6 +2117,66 @@ var Parser = class {
|
|
|
2078
2117
|
const parsedAlias = this.parseAliasName();
|
|
2079
2118
|
return this.withAliasDisplay({ type: "WINDOW_COL", func, partitionBy, orderBy, alias: parsedAlias.alias }, parsedAlias);
|
|
2080
2119
|
}
|
|
2120
|
+
parseAggregateWindowColumn(ref) {
|
|
2121
|
+
const supported = /* @__PURE__ */ new Set(["SUM", "COUNT", "AVG", "MIN", "MAX"]);
|
|
2122
|
+
if (!supported.has(ref.func)) {
|
|
2123
|
+
throw new ParseError(
|
|
2124
|
+
`${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`,
|
|
2125
|
+
this.peek()
|
|
2126
|
+
);
|
|
2127
|
+
}
|
|
2128
|
+
if (ref.distinct) {
|
|
2129
|
+
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());
|
|
2130
|
+
}
|
|
2131
|
+
this.advance();
|
|
2132
|
+
this.expect("(" /* LPAREN */);
|
|
2133
|
+
const partitionBy = [];
|
|
2134
|
+
if (this.isSoftKeyword("PARTITION")) {
|
|
2135
|
+
this.advance();
|
|
2136
|
+
this.expect("BY" /* BY */, "PARTITION \u306E\u5F8C\u306B\u306F BY \u304C\u5FC5\u8981\u3067\u3059");
|
|
2137
|
+
do {
|
|
2138
|
+
const field = this.parseQualifiedIdent();
|
|
2139
|
+
partitionBy.push({ type: "FIELD", tableAlias: field.tableAlias, field: field.field });
|
|
2140
|
+
} while (this.consume("," /* COMMA */));
|
|
2141
|
+
}
|
|
2142
|
+
const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy(false)) : [];
|
|
2143
|
+
let frame = orderBy.length > 0 ? { unit: "RANGE", source: "DEFAULT" } : null;
|
|
2144
|
+
if (this.isSoftKeyword("ROWS") || this.isSoftKeyword("RANGE")) {
|
|
2145
|
+
if (orderBy.length === 0) {
|
|
2146
|
+
throw new ParseError("\u30D5\u30EC\u30FC\u30E0\u53E5\u306B\u306F OVER (ORDER BY ...) \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2147
|
+
}
|
|
2148
|
+
const unit = this.advance().value.toUpperCase();
|
|
2149
|
+
const valid = this.consume("BETWEEN" /* BETWEEN */) && this.consumeSoftKeyword("UNBOUNDED") && this.consumeSoftKeyword("PRECEDING") && this.consume("AND" /* AND */) && this.consumeSoftKeyword("CURRENT") && this.consumeSoftKeyword("ROW");
|
|
2150
|
+
if (!valid) {
|
|
2151
|
+
throw new ParseError(
|
|
2152
|
+
"\u5BFE\u5FDC\u3059\u308B\u30D5\u30EC\u30FC\u30E0\u306F BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW \u3060\u3051\u3067\u3059",
|
|
2153
|
+
this.peek()
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
frame = { unit, source: "EXPLICIT" };
|
|
2157
|
+
}
|
|
2158
|
+
this.expect(")" /* RPAREN */);
|
|
2159
|
+
if (this.isArithOp(this.peek().kind)) {
|
|
2160
|
+
throw new ParseError(
|
|
2161
|
+
"\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",
|
|
2162
|
+
this.peek()
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
if (!this.consume("AS" /* AS */)) {
|
|
2166
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2167
|
+
}
|
|
2168
|
+
const parsedAlias = this.parseAliasName();
|
|
2169
|
+
return this.withAliasDisplay({
|
|
2170
|
+
type: "WINDOW_COL",
|
|
2171
|
+
windowKind: "AGGREGATE",
|
|
2172
|
+
aggFunc: ref.func,
|
|
2173
|
+
arg: ref.arg,
|
|
2174
|
+
frame,
|
|
2175
|
+
partitionBy,
|
|
2176
|
+
orderBy,
|
|
2177
|
+
alias: parsedAlias.alias
|
|
2178
|
+
}, parsedAlias);
|
|
2179
|
+
}
|
|
2081
2180
|
selectColumnHasAggregate(column) {
|
|
2082
2181
|
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
2083
2182
|
if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
@@ -2156,7 +2255,9 @@ var Parser = class {
|
|
|
2156
2255
|
}
|
|
2157
2256
|
const aggFunc = this.tryAggregateFunc();
|
|
2158
2257
|
if (aggFunc !== null) {
|
|
2159
|
-
|
|
2258
|
+
const ref = this.parseAggregateRef(aggFunc);
|
|
2259
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2260
|
+
return ref;
|
|
2160
2261
|
}
|
|
2161
2262
|
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
2263
|
}
|
|
@@ -2405,7 +2506,9 @@ var Parser = class {
|
|
|
2405
2506
|
}
|
|
2406
2507
|
const aggregateFunc = this.tryAggregateFunc();
|
|
2407
2508
|
if (aggregateFunc !== null && allowAggregateResult) {
|
|
2408
|
-
|
|
2509
|
+
const ref = this.parseAggregateRef(aggregateFunc);
|
|
2510
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2511
|
+
return this.continueAggArith(ref);
|
|
2409
2512
|
}
|
|
2410
2513
|
if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
2411
2514
|
return this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
@@ -2930,6 +3033,7 @@ var Parser = class {
|
|
|
2930
3033
|
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
3034
|
}
|
|
2932
3035
|
const ref = this.parseAggregateRef(aggFunc);
|
|
3036
|
+
this.rejectAggregateWindowOutsideSelect();
|
|
2933
3037
|
if (this.isArithOp(this.peek().kind)) {
|
|
2934
3038
|
return {
|
|
2935
3039
|
type: "AGG_FIELD",
|
|
@@ -3388,6 +3492,16 @@ var Parser = class {
|
|
|
3388
3492
|
* フィールド名/alias: 名前 / total
|
|
3389
3493
|
*/
|
|
3390
3494
|
parseOrderByKey(allowGrouping = true) {
|
|
3495
|
+
const aggregateStart = this.tryAggregateFunc();
|
|
3496
|
+
if (aggregateStart !== null) {
|
|
3497
|
+
const start = this.pos;
|
|
3498
|
+
const ref = this.parseAggregateRef(aggregateStart);
|
|
3499
|
+
if (this.isSoftKeyword("OVER")) {
|
|
3500
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F SELECT \u5217\u306B\u306E\u307F\u8A18\u8FF0\u3067\u304D\u307E\u3059", this.peek());
|
|
3501
|
+
}
|
|
3502
|
+
this.pos = start;
|
|
3503
|
+
void ref;
|
|
3504
|
+
}
|
|
3391
3505
|
if (this.isUnsupportedGroupingIdStart()) {
|
|
3392
3506
|
throw new ParseError("B65: GROUPING_ID is not supported in Phase1.", this.peek());
|
|
3393
3507
|
}
|
|
@@ -3911,6 +4025,11 @@ var Parser = class {
|
|
|
3911
4025
|
isSoftKeyword(value) {
|
|
3912
4026
|
return this.peek().kind === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === value;
|
|
3913
4027
|
}
|
|
4028
|
+
rejectAggregateWindowOutsideSelect() {
|
|
4029
|
+
if (this.isSoftKeyword("OVER")) {
|
|
4030
|
+
throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F SELECT \u5217\u306B\u306E\u307F\u8A18\u8FF0\u3067\u304D\u307E\u3059", this.peek());
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
3914
4033
|
validateUpdateFromAssignments(assignments, sourceAlias, tok) {
|
|
3915
4034
|
for (const assignment of assignments) {
|
|
3916
4035
|
if (assignment.value.type === "STRING_FUNC") {
|
|
@@ -4426,7 +4545,11 @@ function selectCompleteInputReasons(stmt) {
|
|
|
4426
4545
|
if (stmt.distinct) reasons.add("DISTINCT");
|
|
4427
4546
|
if (stmt.orderBy.length > 0) reasons.add("LOCAL_ORDER");
|
|
4428
4547
|
for (const column of stmt.columns) {
|
|
4429
|
-
if (column.type === "WINDOW_COL" && column.
|
|
4548
|
+
if (column.type === "WINDOW_COL" && column.windowKind === "AGGREGATE") {
|
|
4549
|
+
reasons.add("AGGREGATE_WINDOW");
|
|
4550
|
+
} else if (column.type === "WINDOW_COL" && column.orderBy.length > 0) {
|
|
4551
|
+
reasons.add("WINDOW_ORDER");
|
|
4552
|
+
}
|
|
4430
4553
|
if (column.type === "SCALAR_SUBQUERY_COL") addReasons(reasons, selectCompleteInputReasons(column.query));
|
|
4431
4554
|
if (column.type === "CASE_COL") {
|
|
4432
4555
|
for (const branch of column.expr.branches) addReasons(reasons, whereCompleteInputReasons(branch.condition));
|
|
@@ -6104,6 +6227,9 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
|
6104
6227
|
case "SCALAR_SUBQUERY_COL":
|
|
6105
6228
|
break;
|
|
6106
6229
|
case "WINDOW_COL":
|
|
6230
|
+
if (col.windowKind === "AGGREGATE" && col.arg.type !== "WILDCARD") {
|
|
6231
|
+
walkAggregateArg(col.arg, "select");
|
|
6232
|
+
}
|
|
6107
6233
|
for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
|
|
6108
6234
|
for (const item of col.orderBy) walkOrderByKey(item.key, "select");
|
|
6109
6235
|
break;
|
|
@@ -11076,7 +11202,7 @@ function valueNeedsFieldMetadata(value) {
|
|
|
11076
11202
|
return Object.values(item).some(valueNeedsFieldMetadata);
|
|
11077
11203
|
}
|
|
11078
11204
|
function selectNeedsOwnMetadata(statement) {
|
|
11079
|
-
return whereNeedsFieldMetadata(statement.where) || normalizeGroupingSpec(statement).type === "GROUPING_SETS" || statement.orderBy.length > 0 || statement.columns.some(
|
|
11205
|
+
return whereNeedsFieldMetadata(statement.where) || statement.groupBy.length > 0 || normalizeGroupingSpec(statement).type === "GROUPING_SETS" || statement.orderBy.length > 0 || statement.columns.some(
|
|
11080
11206
|
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
11081
11207
|
);
|
|
11082
11208
|
}
|
|
@@ -13199,26 +13325,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
13199
13325
|
if (arg.type === "WILDCARD") {
|
|
13200
13326
|
return func === "COUNT" ? rows.length : 0;
|
|
13201
13327
|
}
|
|
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
|
-
}
|
|
13328
|
+
const strValues = aggregateRowValues(func, arg, rows).filter((value) => value !== null);
|
|
13222
13329
|
const statistical = func === "STDDEV_POP" || func === "STDDEV_SAMP" || func === "VAR_POP" || func === "VAR_SAMP" || func === "MEDIAN";
|
|
13223
13330
|
const numericValues = statistical ? strValues.map((value) => {
|
|
13224
13331
|
const numeric = Number(value);
|
|
@@ -13296,6 +13403,27 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
|
|
|
13296
13403
|
}
|
|
13297
13404
|
}
|
|
13298
13405
|
}
|
|
13406
|
+
function aggregateRowValues(func, arg, rows) {
|
|
13407
|
+
return rows.map((row) => {
|
|
13408
|
+
let strVal;
|
|
13409
|
+
if (arg.type === "FIELD_REF") {
|
|
13410
|
+
const raw = row[arg.field];
|
|
13411
|
+
if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") return null;
|
|
13412
|
+
strVal = raw;
|
|
13413
|
+
} else if (arg.type === "ARITH" || arg.type === "NUMBER") {
|
|
13414
|
+
const n = evalArithExpr(arg, row);
|
|
13415
|
+
if (isNaN(n)) return null;
|
|
13416
|
+
strVal = String(n);
|
|
13417
|
+
} else {
|
|
13418
|
+
const value = evalScalarValueExprNullable(arg, row);
|
|
13419
|
+
if (value === null) return null;
|
|
13420
|
+
if (value === "" && func !== "MIN" && func !== "MAX") return null;
|
|
13421
|
+
if (typeof value === "number" && Number.isNaN(value)) return null;
|
|
13422
|
+
strVal = String(value);
|
|
13423
|
+
}
|
|
13424
|
+
return strVal;
|
|
13425
|
+
});
|
|
13426
|
+
}
|
|
13299
13427
|
function toAggregateFieldRef(field) {
|
|
13300
13428
|
const dot = field.indexOf(".");
|
|
13301
13429
|
return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
|
|
@@ -13526,7 +13654,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
|
|
|
13526
13654
|
}
|
|
13527
13655
|
return (name, row) => evaluators.get(name)?.(row);
|
|
13528
13656
|
}
|
|
13529
|
-
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
13657
|
+
function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2, resolveAggSortKind) {
|
|
13530
13658
|
const windows = columns.filter((column) => column.type === "WINDOW_COL");
|
|
13531
13659
|
if (rows.length === 0 || windows.length === 0) return rows;
|
|
13532
13660
|
for (const window of windows) {
|
|
@@ -13540,6 +13668,10 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
|
13540
13668
|
for (const partition of partitions.values()) {
|
|
13541
13669
|
const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
|
|
13542
13670
|
const sorted = sortedResult.rows;
|
|
13671
|
+
if (!isRankingWindow(window)) {
|
|
13672
|
+
applyAggregateWindow(window, sortedResult, resolveAggSortKind);
|
|
13673
|
+
continue;
|
|
13674
|
+
}
|
|
13543
13675
|
let rank = 1;
|
|
13544
13676
|
let denseRank = 1;
|
|
13545
13677
|
for (let index = 0; index < sorted.length; index++) {
|
|
@@ -13554,6 +13686,53 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
|
|
|
13554
13686
|
}
|
|
13555
13687
|
return rows;
|
|
13556
13688
|
}
|
|
13689
|
+
function applyAggregateWindow(window, sortedResult, resolveAggSortKind) {
|
|
13690
|
+
const sorted = sortedResult.rows;
|
|
13691
|
+
const values = window.arg.type === "WILDCARD" ? null : aggregateRowValues(window.aggFunc, window.arg, sorted.map((item) => item.row));
|
|
13692
|
+
const comparison = window.arg.type === "WILDCARD" ? void 0 : resolveAggregateArgSemantics(window.arg, resolveAggSortKind);
|
|
13693
|
+
const semantics = typeof comparison === "string" ? syntheticSemantics(comparison) : comparison ?? syntheticSemantics("string");
|
|
13694
|
+
const output = [];
|
|
13695
|
+
let count = 0;
|
|
13696
|
+
let sum = 0;
|
|
13697
|
+
let best;
|
|
13698
|
+
for (let index = 0; index < sorted.length; index++) {
|
|
13699
|
+
const value = values?.[index] ?? null;
|
|
13700
|
+
if (window.arg.type === "WILDCARD") {
|
|
13701
|
+
count++;
|
|
13702
|
+
} else if (value !== null) {
|
|
13703
|
+
if (window.aggFunc === "COUNT") {
|
|
13704
|
+
count++;
|
|
13705
|
+
} else if (window.aggFunc === "SUM" || window.aggFunc === "AVG") {
|
|
13706
|
+
sum += Number(value);
|
|
13707
|
+
count++;
|
|
13708
|
+
} else if (best === void 0) {
|
|
13709
|
+
best = value;
|
|
13710
|
+
} else {
|
|
13711
|
+
const cmp = compareCanonicalValues(value, best, semantics);
|
|
13712
|
+
if (window.aggFunc === "MAX" && cmp > 0 || window.aggFunc === "MIN" && cmp < 0) {
|
|
13713
|
+
best = value;
|
|
13714
|
+
}
|
|
13715
|
+
}
|
|
13716
|
+
}
|
|
13717
|
+
const result = window.aggFunc === "COUNT" ? count : window.aggFunc === "SUM" ? sum : window.aggFunc === "AVG" ? count === 0 ? 0 : sum / count : best ?? 0;
|
|
13718
|
+
output.push(String(result));
|
|
13719
|
+
}
|
|
13720
|
+
if (window.frame === null) {
|
|
13721
|
+
const finalValue = output[output.length - 1];
|
|
13722
|
+
for (const item of sorted) item.row[window.alias] = finalValue;
|
|
13723
|
+
return;
|
|
13724
|
+
}
|
|
13725
|
+
if (window.frame.unit === "RANGE") {
|
|
13726
|
+
for (let start = 0; start < sorted.length; ) {
|
|
13727
|
+
let end = start;
|
|
13728
|
+
while (end + 1 < sorted.length && sortedResult.compare(sorted[end], sorted[end + 1]) === 0) end++;
|
|
13729
|
+
for (let index = start; index <= end; index++) sorted[index].row[window.alias] = output[end];
|
|
13730
|
+
start = end + 1;
|
|
13731
|
+
}
|
|
13732
|
+
return;
|
|
13733
|
+
}
|
|
13734
|
+
for (let index = 0; index < sorted.length; index++) sorted[index].row[window.alias] = output[index];
|
|
13735
|
+
}
|
|
13557
13736
|
function resolveWindowField(row, ref) {
|
|
13558
13737
|
const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
13559
13738
|
return resolveFieldRef(row, name);
|
|
@@ -14020,12 +14199,19 @@ function mergeKnownColumns(left, right, rows) {
|
|
|
14020
14199
|
...Object.keys(rows[0] ?? {})
|
|
14021
14200
|
])];
|
|
14022
14201
|
}
|
|
14023
|
-
function deriveOutputOrderSemantics(columns) {
|
|
14202
|
+
function deriveOutputOrderSemantics(columns, resolveAggSortKind) {
|
|
14024
14203
|
const result = /* @__PURE__ */ new Map();
|
|
14025
14204
|
for (const column of columns) {
|
|
14026
14205
|
if (!("alias" in column) || !column.alias) continue;
|
|
14027
|
-
if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
14206
|
+
if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
14028
14207
|
result.set(column.alias, syntheticSemantics("number"));
|
|
14208
|
+
} else if (column.type === "WINDOW_COL") {
|
|
14209
|
+
if (isRankingWindow(column) || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
14210
|
+
result.set(column.alias, syntheticSemantics("number"));
|
|
14211
|
+
} else if (column.arg.type !== "WILDCARD") {
|
|
14212
|
+
const semantics = resolveAggregateArgSemantics(column.arg, resolveAggSortKind) ?? "string";
|
|
14213
|
+
result.set(column.alias, typeof semantics === "string" ? syntheticSemantics(semantics) : semantics);
|
|
14214
|
+
}
|
|
14029
14215
|
} else if (column.type === "AGGREGATE") {
|
|
14030
14216
|
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
14217
|
result.set(column.alias, syntheticSemantics("number"));
|
|
@@ -14060,7 +14246,7 @@ function runFullScan(input) {
|
|
|
14060
14246
|
resolvedGroupingSpec,
|
|
14061
14247
|
plainGroupByPlan
|
|
14062
14248
|
} = input;
|
|
14063
|
-
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
|
|
14249
|
+
const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns, aggregateSortKindResolver);
|
|
14064
14250
|
for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
|
|
14065
14251
|
let rows = [];
|
|
14066
14252
|
const mainAlias = stmt.from.alias;
|
|
@@ -14116,7 +14302,14 @@ function runFullScan(input) {
|
|
|
14116
14302
|
}
|
|
14117
14303
|
const resolveHavingSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, aggregateSortKindResolver) : havingFieldSemanticsResolver?.(field);
|
|
14118
14304
|
rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, resolveHavingSemantics);
|
|
14119
|
-
rows = applyWindow(
|
|
14305
|
+
rows = applyWindow(
|
|
14306
|
+
rows,
|
|
14307
|
+
stmt.columns,
|
|
14308
|
+
optionOrders,
|
|
14309
|
+
sortKinds,
|
|
14310
|
+
effectiveOrderSemantics,
|
|
14311
|
+
aggregateSortKindResolver
|
|
14312
|
+
);
|
|
14120
14313
|
if (stmt.distinct) {
|
|
14121
14314
|
rows = applyDistinct(
|
|
14122
14315
|
rows,
|
|
@@ -16601,8 +16794,8 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
16601
16794
|
tempTables
|
|
16602
16795
|
);
|
|
16603
16796
|
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") {
|
|
16797
|
+
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");
|
|
16798
|
+
if (first?.type === "AGGREGATE" && first.func === "MODE" || first?.type === "WINDOW_COL" && first.windowKind === "AGGREGATE" && (first.aggFunc === "MIN" || first.aggFunc === "MAX")) {
|
|
16606
16799
|
const meta = (await inferSelectColumnMeta(
|
|
16607
16800
|
resolvedStmt2.expr.query,
|
|
16608
16801
|
["__scalar__"],
|
|
@@ -17228,8 +17421,21 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
|
|
|
17228
17421
|
if (!("alias" in column) || !column.alias) continue;
|
|
17229
17422
|
let semantics;
|
|
17230
17423
|
if (column.type === "FIELD") semantics = rowResolver(aggregateFieldRef(column.field));
|
|
17231
|
-
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
17424
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
17232
17425
|
semantics = syntheticSemantics("number");
|
|
17426
|
+
} else if (column.type === "WINDOW_COL") {
|
|
17427
|
+
if (column.windowKind !== "AGGREGATE" || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
17428
|
+
semantics = syntheticSemantics("number");
|
|
17429
|
+
} else if (column.arg.type !== "WILDCARD") {
|
|
17430
|
+
semantics = inferAggregateArgMeta(column.arg, (ref) => {
|
|
17431
|
+
const resolved = rowResolver(ref);
|
|
17432
|
+
return resolved ? {
|
|
17433
|
+
sortKind: resolved.compareMode === "number" || resolved.compareMode === "recordNumber" ? "number" : "string",
|
|
17434
|
+
fieldType: resolved.fieldType,
|
|
17435
|
+
semantics: resolved
|
|
17436
|
+
} : void 0;
|
|
17437
|
+
}).semantics;
|
|
17438
|
+
}
|
|
17233
17439
|
} else if (column.type === "AGGREGATE") {
|
|
17234
17440
|
if (column.func === "MIN" || column.func === "MAX" || column.func === "MODE") {
|
|
17235
17441
|
if (column.arg.type !== "WILDCARD") {
|
|
@@ -17591,6 +17797,7 @@ async function validateSelectGroupingPlanning(stmt, client, cacheContext, materi
|
|
|
17591
17797
|
function completeInputErrorPrefix(reasons) {
|
|
17592
17798
|
const reasonList = [...reasons].join(", ");
|
|
17593
17799
|
const aggregateSubjects = [
|
|
17800
|
+
["AGGREGATE_WINDOW", "\u96C6\u8A08\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17594
17801
|
["GROUPING_SETS", "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17595
17802
|
["STATISTICAL_AGGREGATE", "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
17596
17803
|
["AGGREGATE", "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
|
|
@@ -18504,12 +18711,18 @@ function inferAggregateArgMeta(arg, resolveField2) {
|
|
|
18504
18711
|
if (arg.elseResult) results.push(caseResultColumnMeta(arg.elseResult, resolveField2));
|
|
18505
18712
|
return mergeExpressionColumnMeta(results);
|
|
18506
18713
|
}
|
|
18714
|
+
function inferWindowColumnMeta(column, resolveField2) {
|
|
18715
|
+
if (column.windowKind !== "AGGREGATE" || column.aggFunc === "COUNT" || column.aggFunc === "SUM" || column.aggFunc === "AVG") {
|
|
18716
|
+
return syntheticColumnMeta("number");
|
|
18717
|
+
}
|
|
18718
|
+
return column.arg.type === "WILDCARD" ? unknownStringColumnMeta() : inferAggregateArgMeta(column.arg, resolveField2);
|
|
18719
|
+
}
|
|
18507
18720
|
function withDisplayName(meta, displayName) {
|
|
18508
18721
|
return { ...meta ?? {}, displayName };
|
|
18509
18722
|
}
|
|
18510
18723
|
function selectNeedsSourceColumnMeta(stmt) {
|
|
18511
18724
|
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")
|
|
18725
|
+
(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
18726
|
);
|
|
18514
18727
|
}
|
|
18515
18728
|
async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables, forLibraryCapture = false) {
|
|
@@ -18615,7 +18828,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
18615
18828
|
} else if (column.type === "STRFUNC_COL") {
|
|
18616
18829
|
meta = stringFunctionColumnMeta(column.expr);
|
|
18617
18830
|
} else if (column.type === "WINDOW_COL") {
|
|
18618
|
-
meta =
|
|
18831
|
+
meta = inferWindowColumnMeta(column, resolveField2);
|
|
18619
18832
|
} else if (column.type === "CASE_COL") {
|
|
18620
18833
|
const results = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
|
|
18621
18834
|
if (column.expr.elseResult) results.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
|
|
@@ -19542,8 +19755,10 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
|
|
|
19542
19755
|
if (!("alias" in column) || !column.alias) continue;
|
|
19543
19756
|
let meta;
|
|
19544
19757
|
if (column.type === "FIELD") meta = resolveField2(aggregateFieldRef(column.field));
|
|
19545
|
-
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL"
|
|
19758
|
+
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
|
|
19546
19759
|
meta = syntheticColumnMeta("number");
|
|
19760
|
+
} else if (column.type === "WINDOW_COL") {
|
|
19761
|
+
meta = inferWindowColumnMeta(column, resolveField2);
|
|
19547
19762
|
} else if (column.type === "GROUPING_COL") {
|
|
19548
19763
|
meta = syntheticColumnMeta("number");
|
|
19549
19764
|
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta = syntheticColumnMeta("string");
|
|
@@ -23581,6 +23796,20 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23581
23796
|
}
|
|
23582
23797
|
}
|
|
23583
23798
|
}
|
|
23799
|
+
for (const column of stmt.columns) {
|
|
23800
|
+
if (column.type !== "WINDOW_COL" || column.windowKind !== "AGGREGATE") continue;
|
|
23801
|
+
const clauses = [];
|
|
23802
|
+
if (column.partitionBy.length > 0) {
|
|
23803
|
+
clauses.push(`PARTITION BY ${column.partitionBy.map(
|
|
23804
|
+
(ref) => ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field
|
|
23805
|
+
).join(", ")}`);
|
|
23806
|
+
}
|
|
23807
|
+
if (column.orderBy.length > 0) {
|
|
23808
|
+
clauses.push(`ORDER BY ${column.orderBy.map(formatOrderByItem).join(", ")}`);
|
|
23809
|
+
}
|
|
23810
|
+
lines.push(` window ${column.alias}: ${column.aggFunc} OVER (${clauses.join(" ")})`);
|
|
23811
|
+
lines.push(column.frame === null ? " frame: PARTITION ENTIRE" : ` frame: ${column.frame.unit} UNBOUNDED PRECEDING AND CURRENT ROW${column.frame.source === "DEFAULT" ? " (\u65E2\u5B9A)" : ""}`);
|
|
23812
|
+
}
|
|
23584
23813
|
if (totalCountPlan) {
|
|
23585
23814
|
const baseQuery = stmt.where === null ? "" : whereToKintone(stmt.where);
|
|
23586
23815
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|