@rex0220/kintone-sql-tools 3.43.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 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
  }
@@ -683,6 +686,7 @@ function arithLabel(node, topLevel = false) {
683
686
  function fieldValueLabel(value) {
684
687
  if (value.type === "FIELD") return value.tableAlias ? `${value.tableAlias}.${value.field}` : value.field;
685
688
  if (value.type === "FUNC_FIELD") return stringFuncLabel(value.expr);
689
+ if (value.type === "AGG_FIELD") return aggregateOperandLabel(value.expr);
686
690
  if (value.type === "ARITH_FIELD") return arithLabel(value.expr);
687
691
  if (value.type === "GROUPING_FIELD") {
688
692
  const field = value.ref.field;
@@ -736,6 +740,8 @@ function whereLabel(expr) {
736
740
  }
737
741
  function caseResultLabel(result) {
738
742
  if (result.type === "ARRAY") return `[${result.elements.map((entry) => quote(entry.value)).join(",")}]`;
743
+ if (result.type === "AGG_REF") return aggregateSyntheticName(result.func, result.distinct, result.arg);
744
+ if (result.type === "AGG_ARITH") return aggregateOperandLabel(result);
739
745
  if (result.type === "FIELD_REF" || result.type === "ARITH") return arithLabel(result);
740
746
  return scalarValueLabel(result);
741
747
  }
@@ -1315,6 +1321,11 @@ var Parser = class {
1315
1321
  }
1316
1322
  throw new ParseError(msg, tok);
1317
1323
  }
1324
+ consumeSoftKeyword(word) {
1325
+ if (!this.isSoftKeyword(word)) return false;
1326
+ this.advance();
1327
+ return true;
1328
+ }
1318
1329
  parseTempTableName() {
1319
1330
  const tok = this.peek();
1320
1331
  if (tok.kind === "IDENT" /* IDENT */ && tok.value.startsWith("#")) {
@@ -1954,6 +1965,12 @@ var Parser = class {
1954
1965
  const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1955
1966
  return this.withAliasDisplay({ type: "GROUPING_COL", ref, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
1956
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
+ }
1957
1974
  if (this.tryAggregateFunc() === null && this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
1958
1975
  const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
1959
1976
  const parsedAlias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
@@ -1998,6 +2015,9 @@ var Parser = class {
1998
2015
  const aggFunc = this.tryAggregateFunc();
1999
2016
  if (aggFunc !== null) {
2000
2017
  const ref = this.parseAggregateRef(aggFunc);
2018
+ if (this.isSoftKeyword("OVER")) {
2019
+ return this.parseAggregateWindowColumn(ref);
2020
+ }
2001
2021
  if (this.isArithOp(this.peek().kind)) {
2002
2022
  const expr = this.continueAggArith(ref);
2003
2023
  const parsedAlias3 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
@@ -2049,6 +2069,28 @@ var Parser = class {
2049
2069
  tryWindowFunc() {
2050
2070
  return PARSER_WINDOW_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
2051
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
+ }
2052
2094
  parseWindowColumn(func) {
2053
2095
  this.advance();
2054
2096
  this.expect("(" /* LPAREN */);
@@ -2075,12 +2117,81 @@ var Parser = class {
2075
2117
  const parsedAlias = this.parseAliasName();
2076
2118
  return this.withAliasDisplay({ type: "WINDOW_COL", func, partitionBy, orderBy, alias: parsedAlias.alias }, parsedAlias);
2077
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
+ }
2078
2180
  selectColumnHasAggregate(column) {
2079
2181
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
2080
2182
  if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
2081
2183
  if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
2184
+ if (column.type === "CASE_COL") return this.nodeHasAggregate(column.expr);
2082
2185
  return false;
2083
2186
  }
2187
+ nodeHasAggregate(node) {
2188
+ if (node === null || typeof node !== "object") return false;
2189
+ if (Array.isArray(node)) return node.some((value2) => this.nodeHasAggregate(value2));
2190
+ const value = node;
2191
+ if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
2192
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
2193
+ return Object.values(value).some((child) => this.nodeHasAggregate(child));
2194
+ }
2084
2195
  stringFuncArgHasAggregate(arg) {
2085
2196
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
2086
2197
  return this.scalarValueHasAggregate(arg);
@@ -2091,11 +2202,7 @@ var Parser = class {
2091
2202
  return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
2092
2203
  }
2093
2204
  if (expr.type === "CASE_WHEN") {
2094
- const results = [...expr.branches.map((b) => b.result), ...expr.elseResult ? [expr.elseResult] : []];
2095
- return results.some((result) => {
2096
- if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
2097
- return this.scalarValueHasAggregate(result);
2098
- });
2205
+ return this.nodeHasAggregate(expr);
2099
2206
  }
2100
2207
  return false;
2101
2208
  }
@@ -2148,7 +2255,9 @@ var Parser = class {
2148
2255
  }
2149
2256
  const aggFunc = this.tryAggregateFunc();
2150
2257
  if (aggFunc !== null) {
2151
- return this.parseAggregateRef(aggFunc);
2258
+ const ref = this.parseAggregateRef(aggFunc);
2259
+ this.rejectAggregateWindowOutsideSelect();
2260
+ return ref;
2152
2261
  }
2153
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());
2154
2263
  }
@@ -2352,9 +2461,9 @@ var Parser = class {
2352
2461
  this.expect("(" /* LPAREN */);
2353
2462
  const condition = this.parseCaseCondition(allowGroupingCondition);
2354
2463
  this.expect("," /* COMMA */);
2355
- const thenResult = this.parseCaseResult();
2464
+ const thenResult = this.parseCaseResult(allowGroupingCondition);
2356
2465
  this.expect("," /* COMMA */);
2357
- const elseResult = this.parseCaseResult();
2466
+ const elseResult = this.parseCaseResult(allowGroupingCondition);
2358
2467
  this.expect(")" /* RPAREN */);
2359
2468
  return {
2360
2469
  type: "CASE_WHEN",
@@ -2369,7 +2478,7 @@ var Parser = class {
2369
2478
  this.advance();
2370
2479
  const condition = this.parseCaseCondition(allowGroupingCondition);
2371
2480
  this.expect("THEN" /* THEN */);
2372
- const result = this.parseCaseResult();
2481
+ const result = this.parseCaseResult(allowGroupingCondition);
2373
2482
  branches.push({ condition, result });
2374
2483
  }
2375
2484
  if (branches.length === 0) {
@@ -2377,7 +2486,7 @@ var Parser = class {
2377
2486
  }
2378
2487
  let elseResult = null;
2379
2488
  if (this.consume("ELSE" /* ELSE */)) {
2380
- elseResult = this.parseCaseResult();
2489
+ elseResult = this.parseCaseResult(allowGroupingCondition);
2381
2490
  }
2382
2491
  this.expect("END" /* END */);
2383
2492
  return { type: "CASE_WHEN", branches, elseResult };
@@ -2387,7 +2496,7 @@ var Parser = class {
2387
2496
  return this.parseWhereExpr("SELECT_CASE");
2388
2497
  }
2389
2498
  /** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
2390
- parseCaseResult() {
2499
+ parseCaseResult(allowAggregateResult = false) {
2391
2500
  const tok = this.peek();
2392
2501
  if (this.insideAggregateArg > 0 && this.tryAggregateFunc() !== null) {
2393
2502
  throw new ParseError("\u96C6\u8A08\u95A2\u6570\u306E\u5F15\u6570\u5185\u306B\u96C6\u8A08\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
@@ -2395,6 +2504,12 @@ var Parser = class {
2395
2504
  if (tok.kind === "[" /* LBRACKET */) {
2396
2505
  return this.parseArrayLiteral();
2397
2506
  }
2507
+ const aggregateFunc = this.tryAggregateFunc();
2508
+ if (aggregateFunc !== null && allowAggregateResult) {
2509
+ const ref = this.parseAggregateRef(aggregateFunc);
2510
+ this.rejectAggregateWindowOutsideSelect();
2511
+ return this.continueAggArith(ref);
2512
+ }
2398
2513
  if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
2399
2514
  return this.parseScalarValueExpr({ allowAggregateArgs: true });
2400
2515
  }
@@ -2918,8 +3033,20 @@ var Parser = class {
2918
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());
2919
3034
  }
2920
3035
  const ref = this.parseAggregateRef(aggFunc);
3036
+ this.rejectAggregateWindowOutsideSelect();
3037
+ if (this.isArithOp(this.peek().kind)) {
3038
+ return {
3039
+ type: "AGG_FIELD",
3040
+ expr: this.continueAggArith(ref)
3041
+ };
3042
+ }
2921
3043
  const syntheticName = aggregateSyntheticName(ref.func, ref.distinct, ref.arg);
2922
- return { type: "FIELD", tableAlias: null, field: syntheticName };
3044
+ return {
3045
+ type: "FIELD",
3046
+ tableAlias: null,
3047
+ field: syntheticName,
3048
+ ...this.groupingFieldContext === "SELECT_CASE" || this.groupingFieldContext === "HAVING" ? { aggregateRef: ref } : {}
3049
+ };
2923
3050
  }
2924
3051
  if (this.peek().kind === "CASE" /* CASE */) {
2925
3052
  const expr = this.parseCaseWhenExpr();
@@ -3365,6 +3492,16 @@ var Parser = class {
3365
3492
  * フィールド名/alias: 名前 / total
3366
3493
  */
3367
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
+ }
3368
3505
  if (this.isUnsupportedGroupingIdStart()) {
3369
3506
  throw new ParseError("B65: GROUPING_ID is not supported in Phase1.", this.peek());
3370
3507
  }
@@ -3888,6 +4025,11 @@ var Parser = class {
3888
4025
  isSoftKeyword(value) {
3889
4026
  return this.peek().kind === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === value;
3890
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
+ }
3891
4033
  validateUpdateFromAssignments(assignments, sourceAlias, tok) {
3892
4034
  for (const assignment of assignments) {
3893
4035
  if (assignment.value.type === "STRING_FUNC") {
@@ -4403,7 +4545,11 @@ function selectCompleteInputReasons(stmt) {
4403
4545
  if (stmt.distinct) reasons.add("DISTINCT");
4404
4546
  if (stmt.orderBy.length > 0) reasons.add("LOCAL_ORDER");
4405
4547
  for (const column of stmt.columns) {
4406
- if (column.type === "WINDOW_COL" && column.orderBy.length > 0) reasons.add("WINDOW_ORDER");
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
+ }
4407
4553
  if (column.type === "SCALAR_SUBQUERY_COL") addReasons(reasons, selectCompleteInputReasons(column.query));
4408
4554
  if (column.type === "CASE_COL") {
4409
4555
  for (const branch of column.expr.branches) addReasons(reasons, whereCompleteInputReasons(branch.condition));
@@ -5118,6 +5264,9 @@ function convertField(field) {
5118
5264
  `WHERE \u53E5\u306E\u95A2\u6570\uFF08${field.expr.func}\uFF09\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093`
5119
5265
  );
5120
5266
  }
5267
+ if (field.type === "AGG_FIELD") {
5268
+ throw new KintoneQueryError("HAVING \u53E5\u306E\u96C6\u8A08\u7B97\u8853\u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093");
5269
+ }
5121
5270
  if (field.type === "ARITH_FIELD") {
5122
5271
  throw new KintoneQueryError("WHERE \u53E5\u306E\u7B97\u8853\u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093");
5123
5272
  }
@@ -5256,292 +5405,564 @@ var KintoneQueryError = class extends Error {
5256
5405
  }
5257
5406
  };
5258
5407
 
5259
- // src/converter/selectToKintone.ts
5260
- function hasWindowColumns(columns) {
5261
- return columns.some((column) => column.type === "WINDOW_COL");
5262
- }
5263
- function resolveSelectMode(stmt) {
5264
- if (stmt.from.subtableCode) return "FULL_SCAN";
5265
- if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
5266
- if (stmt.joins.length > 0) return "FULL_SCAN";
5267
- if (normalizeGroupingSpec(stmt).type !== "NONE") return "FULL_SCAN";
5268
- if (stmt.distinct) return "FULL_SCAN";
5269
- if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
5270
- if (stmt.columns.some(
5271
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate(c.expr)
5272
- )) return "FULL_SCAN";
5273
- if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
5274
- if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
5275
- return "SIMPLE";
5408
+ // src/engine/groupingRowMeta.ts
5409
+ var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
5410
+ var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
5411
+ function attachGroupingRowMeta(row, includedCanonicalIds) {
5412
+ Object.defineProperty(row, groupingRowMetaKey, {
5413
+ value: { includedCanonicalIds },
5414
+ enumerable: false,
5415
+ configurable: false,
5416
+ writable: false
5417
+ });
5418
+ return row;
5276
5419
  }
5277
- function whereRequiresJsEval(where) {
5278
- if (where === null) return false;
5279
- switch (where.type) {
5280
- case "BOOLEAN":
5281
- return true;
5282
- case "BINARY":
5283
- return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY" || isLike(where);
5284
- case "NULL_CHECK":
5285
- return isFunc(where.field);
5286
- case "LOGICAL":
5287
- return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
5288
- case "NOT":
5289
- case "GROUP":
5290
- return whereRequiresJsEval(where.expr);
5291
- case "EXISTS":
5292
- return true;
5293
- }
5420
+ function getGroupingRowMeta(row) {
5421
+ return row[groupingRowMetaKey];
5294
5422
  }
5295
- function isFunc(fv) {
5296
- return fv.type === "FUNC_FIELD" || fv.type === "ARITH_FIELD" || fv.type === "CASE_FIELD";
5423
+ function readGroupingMembership(row) {
5424
+ return getGroupingRowMeta(row)?.includedCanonicalIds;
5297
5425
  }
5298
- function selectToKintoneParams(stmt) {
5299
- const queryParts = [];
5300
- const hasPagination = stmt.limit !== null || stmt.offset !== null;
5301
- const shouldInjectDefaultOrder = hasPagination && stmt.orderBy.length === 0;
5302
- if (stmt.where !== null) {
5303
- queryParts.push(whereToKintone(stmt.where));
5304
- }
5305
- if (stmt.orderBy.length > 0) {
5306
- const orderStr = stmt.orderBy.map(convertOrderBy).join(", ");
5307
- queryParts.push(`order by ${orderStr}`);
5308
- } else if (shouldInjectDefaultOrder) {
5309
- queryParts.push("order by $id asc");
5310
- }
5311
- if (stmt.limit !== null) {
5312
- queryParts.push(`limit ${stmt.limit}`);
5313
- }
5314
- if (stmt.offset !== null) {
5315
- queryParts.push(`offset ${stmt.offset}`);
5316
- }
5317
- return {
5318
- app: stmt.from.appId,
5319
- query: queryParts.join(" "),
5320
- fields: extractFields(stmt.columns),
5321
- totalCount: false
5322
- };
5426
+ function bindGroupingRefCanonicalId(ref, canonicalId) {
5427
+ groupingRefCanonicalIds.set(ref, canonicalId);
5323
5428
  }
5324
- function selectToFetchAllParams(stmt, appId) {
5325
- const queryParts = [];
5326
- if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
5327
- queryParts.push(whereToKintone(stmt.where));
5429
+ function evalGroupingRef(ref, row) {
5430
+ const membership = readGroupingMembership(row);
5431
+ if (!membership) {
5432
+ throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
5328
5433
  }
5329
- return {
5330
- app: appId,
5331
- query: queryParts.join(" "),
5332
- fields: []
5333
- // 全件取得なので全フィールドを取得する
5334
- };
5335
- }
5336
- function selectToFetchAllFields(stmt, targetTable, plainGroupByPlan) {
5337
- const plan = collectRequiredFieldsByTable(stmt, plainGroupByPlan);
5338
- const target = plan.get(targetTable);
5339
- if (!target) return [];
5340
- if (target.allFields) return [];
5341
- const fields = new Set(target.fields);
5342
- if (target.table.subtableCode) {
5343
- fields.add(target.table.subtableCode);
5434
+ const canonicalId = groupingRefCanonicalIds.get(ref);
5435
+ if (!canonicalId) {
5436
+ throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
5344
5437
  }
5345
- if (fields.size === 0) fields.add("$id");
5346
- return [...fields];
5438
+ return membership.has(canonicalId) ? "0" : "1";
5347
5439
  }
5348
- function convertOrderBy(item) {
5349
- const dir = item.direction === "ASC" ? "asc" : "desc";
5350
- if (item.key.type !== "FIELD_NAME") {
5351
- throw new Error("ORDER BY \u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\uFF08FULL_SCAN \u304C\u5FC5\u8981\u3067\u3059\uFF09");
5440
+
5441
+ // src/core/groupingValidation.ts
5442
+ var enforceGroupingPlanningCandidateLimits = (facts) => {
5443
+ if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
5444
+ throw new Error(
5445
+ `ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
5446
+ );
5352
5447
  }
5353
- return `${item.key.name} ${dir}`;
5354
- }
5355
- function extractFields(columns) {
5356
- const hasWildcard = columns.some(
5357
- (c) => c.type === "WILDCARD" || c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "CASE_COL" || c.type === "SCALAR_SUBQUERY_COL"
5358
- );
5359
- if (hasWildcard) return [];
5360
- const fields = [];
5361
- for (const col of columns) {
5362
- if (col.type === "FIELD") {
5363
- fields.push(normalizeSimpleFieldRef(col.field));
5364
- } else if (col.type === "ARITH_COL") {
5365
- collectArithNode(col.expr, fields);
5366
- } else if (col.type === "STRFUNC_COL") {
5367
- collectStringFuncFields(col.expr, fields);
5368
- } else if (col.type === "SCALAR_VALUE_COL") {
5369
- collectScalarValueFields(col.expr, fields);
5370
- }
5448
+ if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
5449
+ throw new Error(
5450
+ `ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
5451
+ );
5371
5452
  }
5372
- return [...new Set(fields)];
5373
- }
5374
- function collectArithFields(expr, out) {
5375
- collectArithNode(expr.left, out);
5376
- collectArithNode(expr.right, out);
5377
- }
5378
- function collectArithNode(node, out) {
5379
- if (node.type === "VARIABLE") throw new Error(
5380
- `InternalError: unresolved arithmetic variable @${node.name} reached SELECT field collection.`
5381
- );
5382
- if (node.type === "FIELD_REF") out.push(normalizeSimpleFieldRef(node.field));
5383
- else if (node.type === "ARITH") collectArithFields(node, out);
5384
- else if (node.type === "STRING_FUNC") collectStringFuncFields(node, out);
5453
+ };
5454
+ function displayField(field) {
5455
+ return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
5385
5456
  }
5386
- function normalizeSimpleFieldRef(field) {
5387
- const dot = field.indexOf(".");
5388
- if (dot <= 0) return field;
5389
- const unqualified = field.slice(dot + 1);
5390
- return unqualified || field;
5457
+ function refFromName(name) {
5458
+ const dot = name.indexOf(".");
5459
+ return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
5391
5460
  }
5392
- function collectStringFuncFields(expr, out) {
5393
- for (const arg of expr.args) {
5394
- collectStringFuncArgFields(arg, out);
5461
+ function collectGroupingRefs(node, out) {
5462
+ if (node === null || typeof node !== "object") return;
5463
+ if (Array.isArray(node)) {
5464
+ node.forEach((item) => collectGroupingRefs(item, out));
5465
+ return;
5395
5466
  }
5396
- }
5397
- function collectStringFuncArgFields(arg, out) {
5398
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5399
- collectAggOperandFields(arg, out);
5467
+ const value = node;
5468
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
5469
+ if (value["type"] === "GROUPING_REF") {
5470
+ out.push(value);
5400
5471
  return;
5401
5472
  }
5402
- collectScalarValueFields(arg, out);
5473
+ Object.values(value).forEach((item) => collectGroupingRefs(item, out));
5403
5474
  }
5404
- function collectScalarValueFields(expr, out) {
5405
- if (expr.type === "FIELD") {
5406
- out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
5475
+ function collectAggregateArgumentGroupingRefs(node, out) {
5476
+ if (node === null || typeof node !== "object") return;
5477
+ if (Array.isArray(node)) {
5478
+ node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5407
5479
  return;
5408
5480
  }
5409
- if (expr.type === "STRING_FUNC") {
5410
- collectStringFuncFields(expr, out);
5481
+ const value = node;
5482
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
5483
+ if (value["type"] === "AGGREGATE" || value["type"] === "AGG_REF") {
5484
+ collectGroupingRefs(value["arg"], out);
5411
5485
  return;
5412
5486
  }
5413
- if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5414
- collectScalarValueFields(expr.left, out);
5415
- collectScalarValueFields(expr.right, out);
5487
+ Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5488
+ }
5489
+ function collectNonAggregateFieldRefs(node, out) {
5490
+ if (node === null || typeof node !== "object") return;
5491
+ if (Array.isArray(node)) {
5492
+ node.forEach((item) => collectNonAggregateFieldRefs(item, out));
5416
5493
  return;
5417
5494
  }
5418
- if (expr.type === "CASE_WHEN") {
5419
- for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
5420
- if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
5421
- }
5422
- }
5423
- function collectCaseResultScalarFields(result, out) {
5424
- if (result.type === "ARRAY") return;
5425
- if (result.type === "FIELD_REF" || result.type === "ARITH") {
5426
- collectArithNode(result, out);
5495
+ const value = node;
5496
+ const type = value["type"];
5497
+ if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
5498
+ if (type === "FIELD" && value["aggregateRef"] !== void 0) return;
5499
+ if (type === "FIELD" && typeof value["field"] === "string") {
5500
+ out.push({
5501
+ type: "FIELD",
5502
+ tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
5503
+ field: value["field"]
5504
+ });
5427
5505
  return;
5428
5506
  }
5429
- collectScalarValueFields(result, out);
5430
- }
5431
- function collectAggOperandFields(node, out) {
5432
- if (node.type === "AGG_REF") {
5433
- if (node.arg.type !== "WILDCARD") collectAggregateArgFields(node.arg, out);
5507
+ if (type === "FIELD_REF" && typeof value["field"] === "string") {
5508
+ out.push(refFromName(value["field"]));
5434
5509
  return;
5435
5510
  }
5436
- if (node.type === "AGG_ARITH") {
5437
- collectAggOperandFields(node.left, out);
5438
- collectAggOperandFields(node.right, out);
5511
+ Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
5512
+ }
5513
+ function containsAggregate2(node) {
5514
+ if (node === null || typeof node !== "object") return false;
5515
+ if (Array.isArray(node)) return node.some(containsAggregate2);
5516
+ const value = node;
5517
+ if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
5518
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
5519
+ return Object.values(value).some(containsAggregate2);
5520
+ }
5521
+ function isAggregateMaterializedAlias(column) {
5522
+ if (!("alias" in column) || column.alias === null) return false;
5523
+ if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
5524
+ if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL" || column.type === "CASE_COL") {
5525
+ return containsAggregate2(column);
5439
5526
  }
5527
+ return false;
5440
5528
  }
5441
- function collectAggregateArgFields(node, out) {
5442
- if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
5443
- else collectScalarValueFields(node, out);
5529
+ function outputAliases(columns) {
5530
+ return new Set(columns.flatMap(
5531
+ (column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
5532
+ ));
5444
5533
  }
5445
- function hasAggregateInStringFuncExpr(expr) {
5446
- return expr.args.some((arg) => {
5447
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
5448
- return scalarValueHasAggregate(arg);
5449
- });
5534
+ function isAggregateSyntheticReference(ref) {
5535
+ return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
5450
5536
  }
5451
- function scalarValueHasAggregate(expr) {
5452
- if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(expr);
5453
- if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5454
- return scalarValueHasAggregate(expr.left) || scalarValueHasAggregate(expr.right);
5537
+ function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
5538
+ const resolved = resolve2(ref.field);
5539
+ if (!resolved.physical) {
5540
+ throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
5455
5541
  }
5456
- if (expr.type === "CASE_WHEN") {
5457
- return expr.branches.some((b) => caseResultHasAggregate(b.result)) || expr.elseResult !== null && caseResultHasAggregate(expr.elseResult);
5542
+ if (!canonicalItems.has(resolved.canonicalId)) {
5543
+ throw new Error(
5544
+ `ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
5545
+ );
5458
5546
  }
5459
- return false;
5547
+ bindGroupingRefCanonicalId(ref, resolved.canonicalId);
5460
5548
  }
5461
- function caseResultHasAggregate(result) {
5462
- if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
5463
- return scalarValueHasAggregate(result);
5549
+ function validateDependency(ref, resolve2, canonicalItems, context) {
5550
+ const resolved = resolve2(ref);
5551
+ if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
5552
+ throw new Error(
5553
+ `ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
5554
+ );
5555
+ }
5464
5556
  }
5465
- function collectSelectFieldReferencesBySource(stmt, plainGroupByPlan) {
5466
- const unqualified = /* @__PURE__ */ new Set();
5467
- const states = collectRequiredFieldsByTable(stmt, plainGroupByPlan, {
5468
- includeMaterialized: true,
5469
- unqualified
5470
- });
5471
- return {
5472
- bySource: new Map(
5473
- [...states.entries()].map(([table, state]) => [table, new Set(state.fields)])
5474
- ),
5475
- unqualified
5476
- };
5557
+ function keyDependencies(key) {
5558
+ if (key.type === "GROUPING_KEY") return [];
5559
+ if (key.type === "FIELD_NAME") return [refFromName(key.name)];
5560
+ const refs = [];
5561
+ collectNonAggregateFieldRefs(key, refs);
5562
+ return refs;
5477
5563
  }
5478
- function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5479
- const allTables = [stmt.from, ...stmt.joins.map((j) => j.table)];
5480
- const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
5481
- const targetTables = sourceAware ? allTables : physicalTables;
5482
- const states = /* @__PURE__ */ new Map();
5483
- for (const table of targetTables) {
5484
- states.set(table, { table, allFields: false, fields: /* @__PURE__ */ new Set() });
5564
+ function validateGroupingStatic(stmt) {
5565
+ const normalized = normalizeGroupingSpec(stmt);
5566
+ const groupingRefs = [];
5567
+ for (const column of stmt.columns) {
5568
+ if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
5485
5569
  }
5486
- if (states.size === 0) return states;
5487
- const firstTargetTable = targetTables[0] ?? null;
5488
- const subtableTable = targetTables.find((t) => !!t.subtableCode) ?? null;
5489
- const aliasToTable = /* @__PURE__ */ new Map();
5490
- for (const table of targetTables) {
5491
- if (table.alias) aliasToTable.set(table.alias, table);
5492
- if (table.cteName !== null) {
5493
- aliasToTable.set(table.cteName, table);
5494
- } else if (!table.subtableCode) {
5495
- aliasToTable.set(`APP${table.appId}`, table);
5496
- aliasToTable.set(`app${table.appId}`, table);
5570
+ collectGroupingRefs(stmt.having, groupingRefs);
5571
+ collectGroupingRefs(stmt.orderBy, groupingRefs);
5572
+ const forbiddenGroupingRefs = [];
5573
+ collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
5574
+ collectGroupingRefs(stmt.joins, forbiddenGroupingRefs);
5575
+ collectAggregateArgumentGroupingRefs(stmt.columns, forbiddenGroupingRefs);
5576
+ collectAggregateArgumentGroupingRefs(stmt.having, forbiddenGroupingRefs);
5577
+ for (const column of stmt.columns) {
5578
+ if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
5579
+ }
5580
+ if (forbiddenGroupingRefs.length > 0) {
5581
+ throw new Error(
5582
+ "ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
5583
+ );
5584
+ }
5585
+ if (normalized.type !== "GROUPING_SETS") {
5586
+ if (groupingRefs.length > 0) {
5587
+ throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
5497
5588
  }
5589
+ return;
5498
5590
  }
5499
- const selectAliases = collectSelectOutputNames(stmt.columns);
5500
- const markAll = (table) => {
5501
- const st = states.get(table);
5502
- if (!st) return;
5503
- st.allFields = true;
5504
- st.fields.clear();
5505
- };
5506
- const markAllTargetTables = () => {
5507
- for (const t of targetTables) markAll(t);
5508
- };
5509
- const markAllSubtableTables = () => {
5510
- for (const t of targetTables) {
5511
- if (t.subtableCode) markAll(t);
5591
+ if (stmt.orderMode === "KINTONE_NATIVE") {
5592
+ throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
5593
+ }
5594
+ if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
5595
+ throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
5596
+ }
5597
+ if (stmt.columns.some(
5598
+ (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
5599
+ )) {
5600
+ throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
5601
+ }
5602
+ }
5603
+ function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
5604
+ validateGroupingStatic(stmt);
5605
+ const normalized = normalizeGroupingSpec(stmt);
5606
+ const groupingRefs = [];
5607
+ for (const column of stmt.columns) {
5608
+ if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
5609
+ }
5610
+ collectGroupingRefs(stmt.having, groupingRefs);
5611
+ collectGroupingRefs(stmt.orderBy, groupingRefs);
5612
+ if (normalized.type !== "GROUPING_SETS") {
5613
+ return null;
5614
+ }
5615
+ const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
5616
+ const canonicalItems = /* @__PURE__ */ new Set();
5617
+ const resolvedItems = [];
5618
+ for (const item of resolvedSpec.allItems) {
5619
+ const resolved = item;
5620
+ if (!resolved.physical) {
5621
+ throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
5512
5622
  }
5513
- };
5514
- const addFieldToTable = (table, fieldName) => {
5515
- const st = states.get(table);
5516
- if (!st || st.allFields) return;
5517
- if (table.subtableCode) {
5518
- if (fieldName.startsWith("_p.")) {
5519
- const parentField = fieldName.slice(3);
5520
- if (parentField && parentField !== "*") st.fields.add(parentField);
5521
- return;
5522
- }
5523
- if (fieldName === "_pid" || fieldName === "_rid" || fieldName === "_idx" || fieldName === "$id") {
5524
- return;
5525
- }
5526
- return;
5623
+ if (!canonicalItems.has(resolved.canonicalId)) {
5624
+ canonicalItems.add(resolved.canonicalId);
5625
+ resolvedItems.push(resolved);
5527
5626
  }
5528
- if (!fieldName) return;
5529
- st.fields.add(fieldName);
5530
- };
5531
- const addFieldName = (rawName, phase = "select", groupResolution) => {
5532
- if (!rawName || rawName === "*") return;
5533
- if (rawName === "_p.*") {
5534
- markAllSubtableTables();
5535
- return;
5627
+ }
5628
+ planningGuardHook({
5629
+ expandedSetCount: normalized.sets.length,
5630
+ canonicalItemCount: canonicalItems.size
5631
+ });
5632
+ for (const ref of groupingRefs) {
5633
+ validateGroupingRefMembership(ref, resolve2, canonicalItems);
5634
+ }
5635
+ const aliases = outputAliases(stmt.columns);
5636
+ for (const column of stmt.columns) {
5637
+ 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;
5638
+ const refs = [];
5639
+ if (column.type === "FIELD") refs.push(refFromName(column.field));
5640
+ else collectNonAggregateFieldRefs(column, refs);
5641
+ for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
5642
+ }
5643
+ if (stmt.having) {
5644
+ const refs = [];
5645
+ collectNonAggregateFieldRefs(stmt.having, refs);
5646
+ for (const ref of refs) {
5647
+ if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5648
+ validateDependency(ref, resolve2, canonicalItems, "HAVING");
5536
5649
  }
5537
- if (rawName.endsWith(".*")) {
5538
- const qualifier = rawName.slice(0, -2);
5539
- if (!qualifier) {
5540
- markAllTargetTables();
5541
- return;
5542
- }
5543
- if (qualifier === "_p") {
5544
- markAllSubtableTables();
5650
+ }
5651
+ for (const order of stmt.orderBy) {
5652
+ for (const ref of keyDependencies(order.key)) {
5653
+ if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5654
+ validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
5655
+ }
5656
+ }
5657
+ const collisionKeys = /* @__PURE__ */ new Set();
5658
+ for (const item of resolvedItems) {
5659
+ collisionKeys.add(item.directKey);
5660
+ if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
5661
+ }
5662
+ for (const column of stmt.columns) {
5663
+ if (!isAggregateMaterializedAlias(column)) continue;
5664
+ const alias = "alias" in column ? column.alias : null;
5665
+ if (alias === null) continue;
5666
+ if (collisionKeys.has(alias)) {
5667
+ throw new Error(
5668
+ `ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
5669
+ );
5670
+ }
5671
+ }
5672
+ return resolvedSpec;
5673
+ }
5674
+
5675
+ // src/converter/selectToKintone.ts
5676
+ function hasWindowColumns(columns) {
5677
+ return columns.some((column) => column.type === "WINDOW_COL");
5678
+ }
5679
+ function resolveSelectMode(stmt) {
5680
+ if (stmt.from.subtableCode) return "FULL_SCAN";
5681
+ if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
5682
+ if (stmt.joins.length > 0) return "FULL_SCAN";
5683
+ if (normalizeGroupingSpec(stmt).type !== "NONE") return "FULL_SCAN";
5684
+ if (stmt.distinct) return "FULL_SCAN";
5685
+ if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
5686
+ if (stmt.columns.some(
5687
+ (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "CASE_COL" && containsAggregate2(c.expr) || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate(c.expr)
5688
+ )) return "FULL_SCAN";
5689
+ if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
5690
+ if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
5691
+ return "SIMPLE";
5692
+ }
5693
+ function whereRequiresJsEval(where) {
5694
+ if (where === null) return false;
5695
+ switch (where.type) {
5696
+ case "BOOLEAN":
5697
+ return true;
5698
+ case "BINARY":
5699
+ return isFunc(where.left) || where.right.type === "ARITH_VALUE" || where.right.type === "CASE_VALUE" || where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY" || isLike(where);
5700
+ case "NULL_CHECK":
5701
+ return isFunc(where.field);
5702
+ case "LOGICAL":
5703
+ return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
5704
+ case "NOT":
5705
+ case "GROUP":
5706
+ return whereRequiresJsEval(where.expr);
5707
+ case "EXISTS":
5708
+ return true;
5709
+ }
5710
+ }
5711
+ function isFunc(fv) {
5712
+ return fv.type === "FUNC_FIELD" || fv.type === "ARITH_FIELD" || fv.type === "CASE_FIELD";
5713
+ }
5714
+ function selectToKintoneParams(stmt) {
5715
+ const queryParts = [];
5716
+ const hasPagination = stmt.limit !== null || stmt.offset !== null;
5717
+ const shouldInjectDefaultOrder = hasPagination && stmt.orderBy.length === 0;
5718
+ if (stmt.where !== null) {
5719
+ queryParts.push(whereToKintone(stmt.where));
5720
+ }
5721
+ if (stmt.orderBy.length > 0) {
5722
+ const orderStr = stmt.orderBy.map(convertOrderBy).join(", ");
5723
+ queryParts.push(`order by ${orderStr}`);
5724
+ } else if (shouldInjectDefaultOrder) {
5725
+ queryParts.push("order by $id asc");
5726
+ }
5727
+ if (stmt.limit !== null) {
5728
+ queryParts.push(`limit ${stmt.limit}`);
5729
+ }
5730
+ if (stmt.offset !== null) {
5731
+ queryParts.push(`offset ${stmt.offset}`);
5732
+ }
5733
+ return {
5734
+ app: stmt.from.appId,
5735
+ query: queryParts.join(" "),
5736
+ fields: extractFields(stmt.columns),
5737
+ totalCount: false
5738
+ };
5739
+ }
5740
+ function selectToFetchAllParams(stmt, appId) {
5741
+ const queryParts = [];
5742
+ if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
5743
+ queryParts.push(whereToKintone(stmt.where));
5744
+ }
5745
+ return {
5746
+ app: appId,
5747
+ query: queryParts.join(" "),
5748
+ fields: []
5749
+ // 全件取得なので全フィールドを取得する
5750
+ };
5751
+ }
5752
+ function selectToFetchAllFields(stmt, targetTable, plainGroupByPlan) {
5753
+ const plan = collectRequiredFieldsByTable(stmt, plainGroupByPlan);
5754
+ const target = plan.get(targetTable);
5755
+ if (!target) return [];
5756
+ if (target.allFields) return [];
5757
+ const fields = new Set(target.fields);
5758
+ if (target.table.subtableCode) {
5759
+ fields.add(target.table.subtableCode);
5760
+ }
5761
+ if (fields.size === 0) fields.add("$id");
5762
+ return [...fields];
5763
+ }
5764
+ function convertOrderBy(item) {
5765
+ const dir = item.direction === "ASC" ? "asc" : "desc";
5766
+ if (item.key.type !== "FIELD_NAME") {
5767
+ throw new Error("ORDER BY \u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\uFF08FULL_SCAN \u304C\u5FC5\u8981\u3067\u3059\uFF09");
5768
+ }
5769
+ return `${item.key.name} ${dir}`;
5770
+ }
5771
+ function extractFields(columns) {
5772
+ const hasWildcard = columns.some(
5773
+ (c) => c.type === "WILDCARD" || c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "CASE_COL" || c.type === "SCALAR_SUBQUERY_COL"
5774
+ );
5775
+ if (hasWildcard) return [];
5776
+ const fields = [];
5777
+ for (const col of columns) {
5778
+ if (col.type === "FIELD") {
5779
+ fields.push(normalizeSimpleFieldRef(col.field));
5780
+ } else if (col.type === "ARITH_COL") {
5781
+ collectArithNode(col.expr, fields);
5782
+ } else if (col.type === "STRFUNC_COL") {
5783
+ collectStringFuncFields(col.expr, fields);
5784
+ } else if (col.type === "SCALAR_VALUE_COL") {
5785
+ collectScalarValueFields(col.expr, fields);
5786
+ }
5787
+ }
5788
+ return [...new Set(fields)];
5789
+ }
5790
+ function collectArithFields(expr, out) {
5791
+ collectArithNode(expr.left, out);
5792
+ collectArithNode(expr.right, out);
5793
+ }
5794
+ function collectArithNode(node, out) {
5795
+ if (node.type === "VARIABLE") throw new Error(
5796
+ `InternalError: unresolved arithmetic variable @${node.name} reached SELECT field collection.`
5797
+ );
5798
+ if (node.type === "FIELD_REF") out.push(normalizeSimpleFieldRef(node.field));
5799
+ else if (node.type === "ARITH") collectArithFields(node, out);
5800
+ else if (node.type === "STRING_FUNC") collectStringFuncFields(node, out);
5801
+ }
5802
+ function normalizeSimpleFieldRef(field) {
5803
+ const dot = field.indexOf(".");
5804
+ if (dot <= 0) return field;
5805
+ const unqualified = field.slice(dot + 1);
5806
+ return unqualified || field;
5807
+ }
5808
+ function collectStringFuncFields(expr, out) {
5809
+ for (const arg of expr.args) {
5810
+ collectStringFuncArgFields(arg, out);
5811
+ }
5812
+ }
5813
+ function collectStringFuncArgFields(arg, out) {
5814
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5815
+ collectAggOperandFields(arg, out);
5816
+ return;
5817
+ }
5818
+ collectScalarValueFields(arg, out);
5819
+ }
5820
+ function collectScalarValueFields(expr, out) {
5821
+ if (expr.type === "FIELD") {
5822
+ out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
5823
+ return;
5824
+ }
5825
+ if (expr.type === "STRING_FUNC") {
5826
+ collectStringFuncFields(expr, out);
5827
+ return;
5828
+ }
5829
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5830
+ collectScalarValueFields(expr.left, out);
5831
+ collectScalarValueFields(expr.right, out);
5832
+ return;
5833
+ }
5834
+ if (expr.type === "CASE_WHEN") {
5835
+ for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
5836
+ if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
5837
+ }
5838
+ }
5839
+ function collectCaseResultScalarFields(result, out) {
5840
+ if (result.type === "ARRAY") return;
5841
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
5842
+ collectAggOperandFields(result, out);
5843
+ return;
5844
+ }
5845
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
5846
+ collectArithNode(result, out);
5847
+ return;
5848
+ }
5849
+ collectScalarValueFields(result, out);
5850
+ }
5851
+ function collectAggOperandFields(node, out) {
5852
+ if (node.type === "AGG_REF") {
5853
+ if (node.arg.type !== "WILDCARD") collectAggregateArgFields(node.arg, out);
5854
+ return;
5855
+ }
5856
+ if (node.type === "AGG_ARITH") {
5857
+ collectAggOperandFields(node.left, out);
5858
+ collectAggOperandFields(node.right, out);
5859
+ }
5860
+ }
5861
+ function collectAggregateArgFields(node, out) {
5862
+ if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
5863
+ else collectScalarValueFields(node, out);
5864
+ }
5865
+ function hasAggregateInStringFuncExpr(expr) {
5866
+ return expr.args.some((arg) => {
5867
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
5868
+ return scalarValueHasAggregate(arg);
5869
+ });
5870
+ }
5871
+ function scalarValueHasAggregate(expr) {
5872
+ if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(expr);
5873
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5874
+ return scalarValueHasAggregate(expr.left) || scalarValueHasAggregate(expr.right);
5875
+ }
5876
+ if (expr.type === "CASE_WHEN") {
5877
+ return expr.branches.some((b) => caseResultHasAggregate(b.result)) || expr.elseResult !== null && caseResultHasAggregate(expr.elseResult);
5878
+ }
5879
+ return false;
5880
+ }
5881
+ function caseResultHasAggregate(result) {
5882
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
5883
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
5884
+ return scalarValueHasAggregate(result);
5885
+ }
5886
+ function collectSelectFieldReferencesBySource(stmt, plainGroupByPlan) {
5887
+ const unqualified = /* @__PURE__ */ new Set();
5888
+ const states = collectRequiredFieldsByTable(stmt, plainGroupByPlan, {
5889
+ includeMaterialized: true,
5890
+ unqualified
5891
+ });
5892
+ return {
5893
+ bySource: new Map(
5894
+ [...states.entries()].map(([table, state]) => [table, new Set(state.fields)])
5895
+ ),
5896
+ unqualified
5897
+ };
5898
+ }
5899
+ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5900
+ const allTables = [stmt.from, ...stmt.joins.map((j) => j.table)];
5901
+ const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
5902
+ const targetTables = sourceAware ? allTables : physicalTables;
5903
+ const states = /* @__PURE__ */ new Map();
5904
+ for (const table of targetTables) {
5905
+ states.set(table, { table, allFields: false, fields: /* @__PURE__ */ new Set() });
5906
+ }
5907
+ if (states.size === 0) return states;
5908
+ const firstTargetTable = targetTables[0] ?? null;
5909
+ const subtableTable = targetTables.find((t) => !!t.subtableCode) ?? null;
5910
+ const aliasToTable = /* @__PURE__ */ new Map();
5911
+ for (const table of targetTables) {
5912
+ if (table.alias) aliasToTable.set(table.alias, table);
5913
+ if (table.cteName !== null) {
5914
+ aliasToTable.set(table.cteName, table);
5915
+ } else if (!table.subtableCode) {
5916
+ aliasToTable.set(`APP${table.appId}`, table);
5917
+ aliasToTable.set(`app${table.appId}`, table);
5918
+ }
5919
+ }
5920
+ const selectAliases = collectSelectOutputNames(stmt.columns);
5921
+ const markAll = (table) => {
5922
+ const st = states.get(table);
5923
+ if (!st) return;
5924
+ st.allFields = true;
5925
+ st.fields.clear();
5926
+ };
5927
+ const markAllTargetTables = () => {
5928
+ for (const t of targetTables) markAll(t);
5929
+ };
5930
+ const markAllSubtableTables = () => {
5931
+ for (const t of targetTables) {
5932
+ if (t.subtableCode) markAll(t);
5933
+ }
5934
+ };
5935
+ const addFieldToTable = (table, fieldName) => {
5936
+ const st = states.get(table);
5937
+ if (!st || st.allFields) return;
5938
+ if (table.subtableCode) {
5939
+ if (fieldName.startsWith("_p.")) {
5940
+ const parentField = fieldName.slice(3);
5941
+ if (parentField && parentField !== "*") st.fields.add(parentField);
5942
+ return;
5943
+ }
5944
+ if (fieldName === "_pid" || fieldName === "_rid" || fieldName === "_idx" || fieldName === "$id") {
5945
+ return;
5946
+ }
5947
+ return;
5948
+ }
5949
+ if (!fieldName) return;
5950
+ st.fields.add(fieldName);
5951
+ };
5952
+ const addFieldName = (rawName, phase = "select", groupResolution) => {
5953
+ if (!rawName || rawName === "*") return;
5954
+ if (rawName === "_p.*") {
5955
+ markAllSubtableTables();
5956
+ return;
5957
+ }
5958
+ if (rawName.endsWith(".*")) {
5959
+ const qualifier = rawName.slice(0, -2);
5960
+ if (!qualifier) {
5961
+ markAllTargetTables();
5962
+ return;
5963
+ }
5964
+ if (qualifier === "_p") {
5965
+ markAllSubtableTables();
5545
5966
  return;
5546
5967
  }
5547
5968
  const target = aliasToTable.get(qualifier);
@@ -5667,6 +6088,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5667
6088
  };
5668
6089
  const walkCaseResult = (result, phase = "select") => {
5669
6090
  if (result.type === "ARRAY") return;
6091
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
6092
+ walkAgg(result, phase);
6093
+ return;
6094
+ }
5670
6095
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
5671
6096
  walkArith(result, phase);
5672
6097
  return;
@@ -5682,6 +6107,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5682
6107
  };
5683
6108
  const walkFieldValue = (fv, phase = "select") => {
5684
6109
  if (fv.type === "FIELD") {
6110
+ if (fv.aggregateRef) {
6111
+ walkAgg(fv.aggregateRef, phase);
6112
+ return;
6113
+ }
5685
6114
  addFieldRef(fv.field, fv.tableAlias, phase);
5686
6115
  return;
5687
6116
  }
@@ -5689,6 +6118,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5689
6118
  walkStringFunc(fv.expr, phase);
5690
6119
  return;
5691
6120
  }
6121
+ if (fv.type === "AGG_FIELD") {
6122
+ walkAgg(fv.expr, phase);
6123
+ return;
6124
+ }
5692
6125
  if (fv.type === "ARITH_FIELD") {
5693
6126
  walkArith(fv.expr, phase);
5694
6127
  return;
@@ -5794,6 +6227,9 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5794
6227
  case "SCALAR_SUBQUERY_COL":
5795
6228
  break;
5796
6229
  case "WINDOW_COL":
6230
+ if (col.windowKind === "AGGREGATE" && col.arg.type !== "WILDCARD") {
6231
+ walkAggregateArg(col.arg, "select");
6232
+ }
5797
6233
  for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
5798
6234
  for (const item of col.orderBy) walkOrderByKey(item.key, "select");
5799
6235
  break;
@@ -6449,464 +6885,198 @@ function containsKlikeOutsideWhereAndNestedSelects(node, allowedWhere) {
6449
6885
  if (obj.type === "SELECT") return;
6450
6886
  if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) {
6451
6887
  found = true;
6452
- return;
6453
- }
6454
- for (const child of Object.values(obj)) visit(child);
6455
- };
6456
- visit(node);
6457
- return found;
6458
- }
6459
- function isDescendantOf(root, target) {
6460
- if (root === null) return false;
6461
- if (root === target) return true;
6462
- switch (root.type) {
6463
- case "LOGICAL":
6464
- return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
6465
- case "NOT":
6466
- case "GROUP":
6467
- return isDescendantOf(root.expr, target);
6468
- case "BINARY":
6469
- case "NULL_CHECK":
6470
- case "EXISTS":
6471
- return false;
6472
- case "BOOLEAN":
6473
- return false;
6474
- }
6475
- }
6476
- function walkWithoutNestedSelects(node, visitWhere) {
6477
- if (Array.isArray(node)) {
6478
- for (const value of node) walkWithoutNestedSelects(value, visitWhere);
6479
- return;
6480
- }
6481
- if (node === null || typeof node !== "object") return;
6482
- const obj = node;
6483
- if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
6484
- visitWhere(obj);
6485
- }
6486
- for (const value of Object.values(obj)) {
6487
- if (value !== node && isSelectObject(value)) continue;
6488
- walkWithoutNestedSelects(value, visitWhere);
6489
- }
6490
- }
6491
- function walkObjects(node, visit, skipRoot = false) {
6492
- if (Array.isArray(node)) {
6493
- for (const value of node) walkObjects(value, visit);
6494
- return;
6495
- }
6496
- if (node === null || typeof node !== "object") return;
6497
- const obj = node;
6498
- if (!skipRoot) visit(obj);
6499
- for (const value of Object.values(obj)) walkObjects(value, visit);
6500
- }
6501
- function isSelectObject(value) {
6502
- return value !== null && typeof value === "object" && value.type === "SELECT";
6503
- }
6504
-
6505
- // src/core/primaryOrganizationDmlValidation.ts
6506
- var PrimaryOrganizationDmlValidationError = class extends Error {
6507
- constructor() {
6508
- super(
6509
- "ArgumentError: PRIMARY_ORGANIZATION() \u306F DML \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6510
- );
6511
- this.name = "ArgumentError";
6512
- }
6513
- };
6514
- function validatePrimaryOrganizationDmlStatement(stmt) {
6515
- const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
6516
- switch (target.type) {
6517
- case "UPDATE":
6518
- case "DELETE":
6519
- case "UPSERT":
6520
- case "UPSERT_SELECT":
6521
- case "INSERT_SELECT":
6522
- if (hasPrimaryOrganizationInWhere(target)) {
6523
- throw new PrimaryOrganizationDmlValidationError();
6524
- }
6525
- return;
6526
- default:
6527
- return;
6528
- }
6529
- }
6530
- function hasPrimaryOrganizationInWhere(node) {
6531
- let found = false;
6532
- walkObjects2(node, (obj) => {
6533
- if (found || !Object.prototype.hasOwnProperty.call(obj, "where")) return;
6534
- if (containsPrimaryOrganization(obj.where)) found = true;
6535
- });
6536
- return found;
6537
- }
6538
- function containsPrimaryOrganization(node) {
6539
- let found = false;
6540
- walkObjects2(node, (obj) => {
6541
- if (obj.type === "KINTONE_FUNC" && obj.name === "PRIMARY_ORGANIZATION") {
6542
- found = true;
6543
- }
6544
- });
6545
- return found;
6546
- }
6547
- function walkObjects2(node, visit) {
6548
- if (Array.isArray(node)) {
6549
- for (const value of node) walkObjects2(value, visit);
6550
- return;
6551
- }
6552
- if (node === null || typeof node !== "object") return;
6553
- const obj = node;
6554
- visit(obj);
6555
- for (const value of Object.values(obj)) walkObjects2(value, visit);
6556
- }
6557
-
6558
- // src/core/functionArity.ts
6559
- function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
6560
- if (args.length >= min && args.length <= max) return;
6561
- const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
6562
- throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
6563
- }
6564
- function assertStringFunctionArity(func, args) {
6565
- switch (func) {
6566
- case "UPPER":
6567
- case "LOWER":
6568
- case "TRIM":
6569
- case "LTRIM":
6570
- case "RTRIM":
6571
- case "LENGTH":
6572
- case "LENGTH_CHAR":
6573
- case "YEAR":
6574
- case "MONTH":
6575
- case "DAY":
6576
- case "DAYOFWEEK":
6577
- case "QUARTER":
6578
- case "WEEK":
6579
- case "LAST_DAY":
6580
- case "ABS":
6581
- case "SQRT":
6582
- return assertArity(func, args, 1, 1);
6583
- case "SUBSTRING":
6584
- case "LPAD":
6585
- case "RPAD":
6586
- case "REGEXP_LIKE":
6587
- case "REGEXP_SUBSTR":
6588
- return assertArity(func, args, 2, 3);
6589
- case "LEFT":
6590
- case "RIGHT":
6591
- case "INSTR":
6592
- case "ISNULL":
6593
- case "NULLIF":
6594
- case "MOD":
6595
- case "POWER":
6596
- case "FORMAT":
6597
- case "CAST":
6598
- case "DATE_FORMAT":
6599
- case "DATEDIFF":
6600
- return assertArity(func, args, 2, 2);
6601
- case "CONCAT":
6602
- case "COALESCE":
6603
- case "GREATEST":
6604
- case "LEAST":
6605
- return assertArity(func, args, 2);
6606
- case "REPLACE":
6607
- case "TRANSLATE":
6608
- case "DATE_ADD":
6609
- return assertArity(func, args, 3, 3);
6610
- case "REGEXP_REPLACE":
6611
- return assertArity(func, args, 3, 5);
6612
- case "ROUND":
6613
- case "FLOOR":
6614
- case "CEIL":
6615
- case "TRUNCATE":
6616
- return assertArity(func, args, 1, 2);
6617
- case "CURRENT_DATE":
6618
- case "CURRENT_TIMESTAMP":
6619
- return assertArity(func, args, 0, 0);
6620
- }
6621
- }
6622
-
6623
- // src/core/statementValidation.ts
6624
- function validateStatementStatic(stmt) {
6625
- validateStringFunctionArities(stmt);
6626
- validatePrimaryOrganizationDmlStatement(stmt);
6627
- validateKlikeStatement(stmt);
6628
- }
6629
- function validateStringFunctionArities(stmt) {
6630
- const visit = (value) => {
6631
- if (value === null || typeof value !== "object") return;
6632
- if (Array.isArray(value)) {
6633
- value.forEach(visit);
6634
- return;
6635
- }
6636
- const node = value;
6637
- if (node.type === "STRING_FUNC") {
6638
- const expr = node;
6639
- assertStringFunctionArity(expr.func, expr.args);
6640
- }
6641
- Object.values(node).forEach(visit);
6642
- };
6643
- visit(stmt);
6644
- }
6645
-
6646
- // src/engine/groupingRowMeta.ts
6647
- var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
6648
- var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
6649
- function attachGroupingRowMeta(row, includedCanonicalIds) {
6650
- Object.defineProperty(row, groupingRowMetaKey, {
6651
- value: { includedCanonicalIds },
6652
- enumerable: false,
6653
- configurable: false,
6654
- writable: false
6655
- });
6656
- return row;
6657
- }
6658
- function getGroupingRowMeta(row) {
6659
- return row[groupingRowMetaKey];
6660
- }
6661
- function readGroupingMembership(row) {
6662
- return getGroupingRowMeta(row)?.includedCanonicalIds;
6663
- }
6664
- function bindGroupingRefCanonicalId(ref, canonicalId) {
6665
- groupingRefCanonicalIds.set(ref, canonicalId);
6666
- }
6667
- function evalGroupingRef(ref, row) {
6668
- const membership = readGroupingMembership(row);
6669
- if (!membership) {
6670
- throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
6671
- }
6672
- const canonicalId = groupingRefCanonicalIds.get(ref);
6673
- if (!canonicalId) {
6674
- throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
6675
- }
6676
- return membership.has(canonicalId) ? "0" : "1";
6888
+ return;
6889
+ }
6890
+ for (const child of Object.values(obj)) visit(child);
6891
+ };
6892
+ visit(node);
6893
+ return found;
6677
6894
  }
6678
-
6679
- // src/core/groupingValidation.ts
6680
- var enforceGroupingPlanningCandidateLimits = (facts) => {
6681
- if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
6682
- throw new Error(
6683
- `ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
6684
- );
6685
- }
6686
- if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
6687
- throw new Error(
6688
- `ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
6689
- );
6895
+ function isDescendantOf(root, target) {
6896
+ if (root === null) return false;
6897
+ if (root === target) return true;
6898
+ switch (root.type) {
6899
+ case "LOGICAL":
6900
+ return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
6901
+ case "NOT":
6902
+ case "GROUP":
6903
+ return isDescendantOf(root.expr, target);
6904
+ case "BINARY":
6905
+ case "NULL_CHECK":
6906
+ case "EXISTS":
6907
+ return false;
6908
+ case "BOOLEAN":
6909
+ return false;
6690
6910
  }
6691
- };
6692
- function displayField(field) {
6693
- return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
6694
- }
6695
- function refFromName(name) {
6696
- const dot = name.indexOf(".");
6697
- return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
6698
6911
  }
6699
- function collectGroupingRefs(node, out) {
6700
- if (node === null || typeof node !== "object") return;
6912
+ function walkWithoutNestedSelects(node, visitWhere) {
6701
6913
  if (Array.isArray(node)) {
6702
- node.forEach((item) => collectGroupingRefs(item, out));
6703
- return;
6704
- }
6705
- const value = node;
6706
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
6707
- if (value["type"] === "GROUPING_REF") {
6708
- out.push(value);
6914
+ for (const value of node) walkWithoutNestedSelects(value, visitWhere);
6709
6915
  return;
6710
6916
  }
6711
- Object.values(value).forEach((item) => collectGroupingRefs(item, out));
6712
- }
6713
- function collectAggregateArgumentGroupingRefs(node, out) {
6714
6917
  if (node === null || typeof node !== "object") return;
6715
- if (Array.isArray(node)) {
6716
- node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6717
- return;
6918
+ const obj = node;
6919
+ if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
6920
+ visitWhere(obj);
6718
6921
  }
6719
- const value = node;
6720
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
6721
- if (value["type"] === "AGGREGATE" || value["type"] === "AGG_REF") {
6722
- collectGroupingRefs(value["arg"], out);
6723
- return;
6922
+ for (const value of Object.values(obj)) {
6923
+ if (value !== node && isSelectObject(value)) continue;
6924
+ walkWithoutNestedSelects(value, visitWhere);
6724
6925
  }
6725
- Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6726
6926
  }
6727
- function collectNonAggregateFieldRefs(node, out) {
6728
- if (node === null || typeof node !== "object") return;
6927
+ function walkObjects(node, visit, skipRoot = false) {
6729
6928
  if (Array.isArray(node)) {
6730
- node.forEach((item) => collectNonAggregateFieldRefs(item, out));
6731
- return;
6732
- }
6733
- const value = node;
6734
- const type = value["type"];
6735
- if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
6736
- if (type === "FIELD" && typeof value["field"] === "string") {
6737
- out.push({
6738
- type: "FIELD",
6739
- tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
6740
- field: value["field"]
6741
- });
6742
- return;
6743
- }
6744
- if (type === "FIELD_REF" && typeof value["field"] === "string") {
6745
- out.push(refFromName(value["field"]));
6929
+ for (const value of node) walkObjects(value, visit);
6746
6930
  return;
6747
6931
  }
6748
- Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
6749
- }
6750
- function containsAggregate2(node) {
6751
- if (node === null || typeof node !== "object") return false;
6752
- if (Array.isArray(node)) return node.some(containsAggregate2);
6753
- const value = node;
6754
- if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
6755
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
6756
- return Object.values(value).some(containsAggregate2);
6757
- }
6758
- function isAggregateMaterializedAlias(column) {
6759
- if (!("alias" in column) || column.alias === null) return false;
6760
- if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
6761
- if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL") {
6762
- return containsAggregate2(column);
6763
- }
6764
- return false;
6765
- }
6766
- function outputAliases(columns) {
6767
- return new Set(columns.flatMap(
6768
- (column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
6769
- ));
6770
- }
6771
- function isAggregateSyntheticReference(ref) {
6772
- return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
6773
- }
6774
- function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
6775
- const resolved = resolve2(ref.field);
6776
- if (!resolved.physical) {
6777
- throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
6778
- }
6779
- if (!canonicalItems.has(resolved.canonicalId)) {
6780
- throw new Error(
6781
- `ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
6782
- );
6783
- }
6784
- bindGroupingRefCanonicalId(ref, resolved.canonicalId);
6785
- }
6786
- function validateDependency(ref, resolve2, canonicalItems, context) {
6787
- const resolved = resolve2(ref);
6788
- if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
6789
- throw new Error(
6790
- `ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
6791
- );
6792
- }
6932
+ if (node === null || typeof node !== "object") return;
6933
+ const obj = node;
6934
+ if (!skipRoot) visit(obj);
6935
+ for (const value of Object.values(obj)) walkObjects(value, visit);
6793
6936
  }
6794
- function keyDependencies(key) {
6795
- if (key.type === "GROUPING_KEY") return [];
6796
- if (key.type === "FIELD_NAME") return [refFromName(key.name)];
6797
- const refs = [];
6798
- collectNonAggregateFieldRefs(key, refs);
6799
- return refs;
6937
+ function isSelectObject(value) {
6938
+ return value !== null && typeof value === "object" && value.type === "SELECT";
6800
6939
  }
6801
- function validateGroupingStatic(stmt) {
6802
- const normalized = normalizeGroupingSpec(stmt);
6803
- const groupingRefs = [];
6804
- for (const column of stmt.columns) {
6805
- if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
6806
- }
6807
- collectGroupingRefs(stmt.having, groupingRefs);
6808
- collectGroupingRefs(stmt.orderBy, groupingRefs);
6809
- const forbiddenGroupingRefs = [];
6810
- collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
6811
- collectGroupingRefs(stmt.joins, forbiddenGroupingRefs);
6812
- collectAggregateArgumentGroupingRefs(stmt.columns, forbiddenGroupingRefs);
6813
- collectAggregateArgumentGroupingRefs(stmt.having, forbiddenGroupingRefs);
6814
- for (const column of stmt.columns) {
6815
- if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
6816
- }
6817
- if (forbiddenGroupingRefs.length > 0) {
6818
- throw new Error(
6819
- "ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
6940
+
6941
+ // src/core/primaryOrganizationDmlValidation.ts
6942
+ var PrimaryOrganizationDmlValidationError = class extends Error {
6943
+ constructor() {
6944
+ super(
6945
+ "ArgumentError: PRIMARY_ORGANIZATION() \u306F DML \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6820
6946
  );
6947
+ this.name = "ArgumentError";
6821
6948
  }
6822
- if (normalized.type !== "GROUPING_SETS") {
6823
- if (groupingRefs.length > 0) {
6824
- throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
6825
- }
6826
- return;
6827
- }
6828
- if (stmt.orderMode === "KINTONE_NATIVE") {
6829
- throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
6830
- }
6831
- if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
6832
- throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
6833
- }
6834
- if (stmt.columns.some(
6835
- (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
6836
- )) {
6837
- throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
6838
- }
6839
- }
6840
- function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
6841
- validateGroupingStatic(stmt);
6842
- const normalized = normalizeGroupingSpec(stmt);
6843
- const groupingRefs = [];
6844
- for (const column of stmt.columns) {
6845
- if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
6846
- }
6847
- collectGroupingRefs(stmt.having, groupingRefs);
6848
- collectGroupingRefs(stmt.orderBy, groupingRefs);
6849
- if (normalized.type !== "GROUPING_SETS") {
6850
- return null;
6851
- }
6852
- const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
6853
- const canonicalItems = /* @__PURE__ */ new Set();
6854
- const resolvedItems = [];
6855
- for (const item of resolvedSpec.allItems) {
6856
- const resolved = item;
6857
- if (!resolved.physical) {
6858
- throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
6859
- }
6860
- if (!canonicalItems.has(resolved.canonicalId)) {
6861
- canonicalItems.add(resolved.canonicalId);
6862
- resolvedItems.push(resolved);
6863
- }
6864
- }
6865
- planningGuardHook({
6866
- expandedSetCount: normalized.sets.length,
6867
- canonicalItemCount: canonicalItems.size
6868
- });
6869
- for (const ref of groupingRefs) {
6870
- validateGroupingRefMembership(ref, resolve2, canonicalItems);
6871
- }
6872
- const aliases = outputAliases(stmt.columns);
6873
- for (const column of stmt.columns) {
6874
- 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;
6875
- const refs = [];
6876
- if (column.type === "FIELD") refs.push(refFromName(column.field));
6877
- else collectNonAggregateFieldRefs(column, refs);
6878
- for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
6879
- }
6880
- if (stmt.having) {
6881
- const refs = [];
6882
- collectNonAggregateFieldRefs(stmt.having, refs);
6883
- for (const ref of refs) {
6884
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
6885
- validateDependency(ref, resolve2, canonicalItems, "HAVING");
6886
- }
6887
- }
6888
- for (const order of stmt.orderBy) {
6889
- for (const ref of keyDependencies(order.key)) {
6890
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
6891
- validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
6949
+ };
6950
+ function validatePrimaryOrganizationDmlStatement(stmt) {
6951
+ const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
6952
+ switch (target.type) {
6953
+ case "UPDATE":
6954
+ case "DELETE":
6955
+ case "UPSERT":
6956
+ case "UPSERT_SELECT":
6957
+ case "INSERT_SELECT":
6958
+ if (hasPrimaryOrganizationInWhere(target)) {
6959
+ throw new PrimaryOrganizationDmlValidationError();
6960
+ }
6961
+ return;
6962
+ default:
6963
+ return;
6964
+ }
6965
+ }
6966
+ function hasPrimaryOrganizationInWhere(node) {
6967
+ let found = false;
6968
+ walkObjects2(node, (obj) => {
6969
+ if (found || !Object.prototype.hasOwnProperty.call(obj, "where")) return;
6970
+ if (containsPrimaryOrganization(obj.where)) found = true;
6971
+ });
6972
+ return found;
6973
+ }
6974
+ function containsPrimaryOrganization(node) {
6975
+ let found = false;
6976
+ walkObjects2(node, (obj) => {
6977
+ if (obj.type === "KINTONE_FUNC" && obj.name === "PRIMARY_ORGANIZATION") {
6978
+ found = true;
6892
6979
  }
6980
+ });
6981
+ return found;
6982
+ }
6983
+ function walkObjects2(node, visit) {
6984
+ if (Array.isArray(node)) {
6985
+ for (const value of node) walkObjects2(value, visit);
6986
+ return;
6893
6987
  }
6894
- const collisionKeys = /* @__PURE__ */ new Set();
6895
- for (const item of resolvedItems) {
6896
- collisionKeys.add(item.directKey);
6897
- if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
6988
+ if (node === null || typeof node !== "object") return;
6989
+ const obj = node;
6990
+ visit(obj);
6991
+ for (const value of Object.values(obj)) walkObjects2(value, visit);
6992
+ }
6993
+
6994
+ // src/core/functionArity.ts
6995
+ function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
6996
+ if (args.length >= min && args.length <= max) return;
6997
+ const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
6998
+ throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
6999
+ }
7000
+ function assertStringFunctionArity(func, args) {
7001
+ switch (func) {
7002
+ case "UPPER":
7003
+ case "LOWER":
7004
+ case "TRIM":
7005
+ case "LTRIM":
7006
+ case "RTRIM":
7007
+ case "LENGTH":
7008
+ case "LENGTH_CHAR":
7009
+ case "YEAR":
7010
+ case "MONTH":
7011
+ case "DAY":
7012
+ case "DAYOFWEEK":
7013
+ case "QUARTER":
7014
+ case "WEEK":
7015
+ case "LAST_DAY":
7016
+ case "ABS":
7017
+ case "SQRT":
7018
+ return assertArity(func, args, 1, 1);
7019
+ case "SUBSTRING":
7020
+ case "LPAD":
7021
+ case "RPAD":
7022
+ case "REGEXP_LIKE":
7023
+ case "REGEXP_SUBSTR":
7024
+ return assertArity(func, args, 2, 3);
7025
+ case "LEFT":
7026
+ case "RIGHT":
7027
+ case "INSTR":
7028
+ case "ISNULL":
7029
+ case "NULLIF":
7030
+ case "MOD":
7031
+ case "POWER":
7032
+ case "FORMAT":
7033
+ case "CAST":
7034
+ case "DATE_FORMAT":
7035
+ case "DATEDIFF":
7036
+ return assertArity(func, args, 2, 2);
7037
+ case "CONCAT":
7038
+ case "COALESCE":
7039
+ case "GREATEST":
7040
+ case "LEAST":
7041
+ return assertArity(func, args, 2);
7042
+ case "REPLACE":
7043
+ case "TRANSLATE":
7044
+ case "DATE_ADD":
7045
+ return assertArity(func, args, 3, 3);
7046
+ case "REGEXP_REPLACE":
7047
+ return assertArity(func, args, 3, 5);
7048
+ case "ROUND":
7049
+ case "FLOOR":
7050
+ case "CEIL":
7051
+ case "TRUNCATE":
7052
+ return assertArity(func, args, 1, 2);
7053
+ case "CURRENT_DATE":
7054
+ case "CURRENT_TIMESTAMP":
7055
+ return assertArity(func, args, 0, 0);
6898
7056
  }
6899
- for (const column of stmt.columns) {
6900
- if (!isAggregateMaterializedAlias(column)) continue;
6901
- const alias = "alias" in column ? column.alias : null;
6902
- if (alias === null) continue;
6903
- if (collisionKeys.has(alias)) {
6904
- throw new Error(
6905
- `ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
6906
- );
7057
+ }
7058
+
7059
+ // src/core/statementValidation.ts
7060
+ function validateStatementStatic(stmt) {
7061
+ validateStringFunctionArities(stmt);
7062
+ validatePrimaryOrganizationDmlStatement(stmt);
7063
+ validateKlikeStatement(stmt);
7064
+ }
7065
+ function validateStringFunctionArities(stmt) {
7066
+ const visit = (value) => {
7067
+ if (value === null || typeof value !== "object") return;
7068
+ if (Array.isArray(value)) {
7069
+ value.forEach(visit);
7070
+ return;
6907
7071
  }
6908
- }
6909
- return resolvedSpec;
7072
+ const node = value;
7073
+ if (node.type === "STRING_FUNC") {
7074
+ const expr = node;
7075
+ assertStringFunctionArity(expr.func, expr.args);
7076
+ }
7077
+ Object.values(node).forEach(visit);
7078
+ };
7079
+ visit(stmt);
6910
7080
  }
6911
7081
 
6912
7082
  // src/core/batch.ts
@@ -7985,10 +8155,32 @@ function formatWithComma(num, digits) {
7985
8155
  return decStr ? `${intFmt}.${decStr}` : intFmt;
7986
8156
  }
7987
8157
  function evalStringFuncArg(arg, row, resolveFieldType, resolveFieldSemantics2) {
7988
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
8158
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
8159
+ return String(evalMaterializedAggregateOperand(arg, row));
8160
+ }
7989
8161
  if (arg.type === "NUMBER") return numberLiteralText(arg);
7990
8162
  return String(evalScalarValueExpr(arg, row, resolveFieldType, resolveFieldSemantics2));
7991
8163
  }
8164
+ function evalMaterializedAggregateOperand(node, row) {
8165
+ if (node.type === "NUMBER") return node.value;
8166
+ if (node.type === "AGG_REF") {
8167
+ return row[aggregateSyntheticName(node.func, node.distinct, node.arg)] ?? "";
8168
+ }
8169
+ const left = Number(evalMaterializedAggregateOperand(node.left, row));
8170
+ const right = Number(evalMaterializedAggregateOperand(node.right, row));
8171
+ switch (node.op) {
8172
+ case "+":
8173
+ return left + right;
8174
+ case "-":
8175
+ return left - right;
8176
+ case "*":
8177
+ return left * right;
8178
+ case "/":
8179
+ return right !== 0 ? left / right : NaN;
8180
+ case "%":
8181
+ return right !== 0 ? left % right : NaN;
8182
+ }
8183
+ }
7992
8184
  function resolveFieldRef(row, field) {
7993
8185
  const direct = row[field];
7994
8186
  if (direct !== void 0) return direct;
@@ -8083,7 +8275,7 @@ function semanticsForLeft(left, fieldType, resolveSemantics) {
8083
8275
  if (left.type === "FIELD") {
8084
8276
  return resolveSemantics?.(left) ?? (fieldType ? resolveFieldSemantics({ fieldType }) : syntheticSemantics("string"));
8085
8277
  }
8086
- if (left.type === "ARITH_FIELD") return syntheticSemantics("number");
8278
+ if (left.type === "ARITH_FIELD" || left.type === "AGG_FIELD") return syntheticSemantics("number");
8087
8279
  if (left.type === "FUNC_FIELD") {
8088
8280
  return syntheticSemantics(NUMERIC_STRING_FUNCTIONS.has(left.expr.func) ? "number" : "string");
8089
8281
  }
@@ -8176,6 +8368,7 @@ function evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSem
8176
8368
  }
8177
8369
  function resolveField(field, row, resolveFieldType, resolveFieldSemantics2) {
8178
8370
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
8371
+ if (field.type === "AGG_FIELD") return String(evalMaterializedAggregateOperand(field.expr, row));
8179
8372
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
8180
8373
  if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType, resolveFieldSemantics2);
8181
8374
  if (field.type === "GROUPING_FIELD") return evalGroupingRef(field.ref, row);
@@ -8233,12 +8426,20 @@ function evalCaseWhenNullable(expr, row, resolveFieldType, resolveFieldSemantics
8233
8426
  }
8234
8427
  function evalCaseResultNullable(result, row, resolveFieldType, resolveFieldSemantics2) {
8235
8428
  if (result.type === "ARRAY") return result.elements.map((entry) => entry.value).join(",");
8429
+ if (result.type === "AGG_REF") {
8430
+ return row[aggregateSyntheticName(result.func, result.distinct, result.arg)] ?? "";
8431
+ }
8432
+ if (result.type === "AGG_ARITH") return row[aggregateOperandLabel(result)] ?? "";
8236
8433
  if (result.type === "FIELD_REF") return row[result.field] ?? "";
8237
8434
  if (result.type === "ARITH") return evalArithExpr(result, row);
8238
8435
  return evalScalarValueExprNullable(result, row, resolveFieldType, resolveFieldSemantics2);
8239
8436
  }
8240
8437
  function evalCaseResult(result, row, resolveFieldType, resolveFieldSemantics2) {
8241
8438
  if (result.type === "ARRAY") return result.elements.map((e) => e.value).join(",");
8439
+ if (result.type === "AGG_REF") {
8440
+ return row[aggregateSyntheticName(result.func, result.distinct, result.arg)] ?? "";
8441
+ }
8442
+ if (result.type === "AGG_ARITH") return row[aggregateOperandLabel(result)] ?? "";
8242
8443
  if (result.type === "FIELD_REF") {
8243
8444
  return row[result.field] ?? "";
8244
8445
  }
@@ -8504,6 +8705,10 @@ function collectAggregateArgFields2(node, out) {
8504
8705
  }
8505
8706
  function collectCaseResultFields(result, out) {
8506
8707
  if (result.type === "ARRAY") return;
8708
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8709
+ collectAggOperandFields2(result, out);
8710
+ return;
8711
+ }
8507
8712
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
8508
8713
  collectArithNode2(result, out);
8509
8714
  return;
@@ -8725,6 +8930,9 @@ function evalCaseResultValue(result, row, fieldType) {
8725
8930
  if (result.type === "ARRAY") {
8726
8931
  return convertArray(result.elements.map((e) => e.value), fieldType);
8727
8932
  }
8933
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8934
+ throw new Error("InternalError: aggregate CASE result reached DML evaluation.");
8935
+ }
8728
8936
  if (result.type === "STRING") {
8729
8937
  return convertString2(result.value, fieldType);
8730
8938
  }
@@ -10994,7 +11202,7 @@ function valueNeedsFieldMetadata(value) {
10994
11202
  return Object.values(item).some(valueNeedsFieldMetadata);
10995
11203
  }
10996
11204
  function selectNeedsOwnMetadata(statement) {
10997
- 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(
10998
11206
  (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
10999
11207
  );
11000
11208
  }
@@ -12913,7 +13121,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
12913
13121
  }
12914
13122
  function hasAggregateColumns(columns) {
12915
13123
  return columns.some(
12916
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
13124
+ (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "CASE_COL" && containsAggregate2(c.expr) || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
12917
13125
  );
12918
13126
  }
12919
13127
  function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind, resolutionPlan, aliasEvaluationContext = {}) {
@@ -13018,26 +13226,72 @@ function groupingItemValue(item, row) {
13018
13226
  return row[item.directKey] ?? (item.unqualifiedBridgeKey === null ? void 0 : row[item.unqualifiedBridgeKey]) ?? "";
13019
13227
  }
13020
13228
  function materializeAggregateColumns(outRow, groupRows, columns, resolveAggSortKind) {
13021
- for (const col of columns) {
13229
+ for (const [columnIndex, col] of columns.entries()) {
13022
13230
  if (col.type === "AGGREGATE") {
13023
13231
  const syntheticKey = aggregateSyntheticName(col.func, col.distinct, col.arg);
13024
13232
  const value = String(evalAggregate(col.func, col.distinct, col.arg, col.separator, groupRows, resolveAggSortKind));
13025
13233
  outRow[col.alias ?? syntheticKey] = value;
13026
13234
  if (col.alias) outRow[syntheticKey] = value;
13027
13235
  } else if (col.type === "ARITH_AGG_COL") {
13236
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13028
13237
  const outputKey = col.alias ?? aggArithDefaultKey(col.expr);
13029
13238
  outRow[outputKey] = String(evalAggArithExpr(col.expr, groupRows, resolveAggSortKind));
13030
13239
  } else if (col.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(col.expr)) {
13240
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13031
13241
  const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
13032
13242
  const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
13033
13243
  outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
13034
13244
  } else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
13245
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13035
13246
  const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
13036
13247
  const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
13037
13248
  outRow[outputKey] = String(evalScalarValueExpr(resolvedExpr, outRow));
13249
+ } else if (col.type === "CASE_COL" && containsAggregate2(col.expr)) {
13250
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13251
+ const resolvedExpr = resolveAggInCaseExpr(col.expr, groupRows, resolveAggSortKind);
13252
+ const resolveAggregateSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, resolveAggSortKind) : void 0;
13253
+ outRow[caseMaterializedKey(col.alias, columnIndex)] = evalCaseWhen(
13254
+ resolvedExpr,
13255
+ outRow,
13256
+ void 0,
13257
+ resolveAggregateSemantics
13258
+ );
13038
13259
  }
13039
13260
  }
13040
13261
  }
13262
+ function caseMaterializedKey(alias, columnIndex) {
13263
+ return alias ?? `__ksql_case_column_${columnIndex}`;
13264
+ }
13265
+ function collectAggregateRefs(node, out) {
13266
+ if (node === null || typeof node !== "object") return;
13267
+ if (Array.isArray(node)) {
13268
+ node.forEach((value2) => collectAggregateRefs(value2, out));
13269
+ return;
13270
+ }
13271
+ const value = node;
13272
+ if (value["type"] === "AGG_REF") {
13273
+ out.push(value);
13274
+ return;
13275
+ }
13276
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
13277
+ Object.values(value).forEach((child) => collectAggregateRefs(child, out));
13278
+ }
13279
+ function materializeAggregateDependencies(outRow, rows, node, resolveAggSortKind) {
13280
+ const refs = [];
13281
+ collectAggregateRefs(node, refs);
13282
+ for (const ref of refs) {
13283
+ const key = aggregateSyntheticName(ref.func, ref.distinct, ref.arg);
13284
+ if (outRow[key] !== void 0) continue;
13285
+ outRow[key] = String(evalAggregate(
13286
+ ref.func,
13287
+ ref.distinct,
13288
+ ref.arg,
13289
+ ref.separator,
13290
+ rows,
13291
+ resolveAggSortKind
13292
+ ));
13293
+ }
13294
+ }
13041
13295
  function evalGroupByKey(key, row, resolution, columns, aliasEvaluationContext) {
13042
13296
  if (key.type === "FIELD_NAME") {
13043
13297
  if (!resolution) return row[key.name] ?? "";
@@ -13071,26 +13325,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
13071
13325
  if (arg.type === "WILDCARD") {
13072
13326
  return func === "COUNT" ? rows.length : 0;
13073
13327
  }
13074
- const strValues = [];
13075
- for (const row of rows) {
13076
- let strVal;
13077
- if (arg.type === "FIELD_REF") {
13078
- const raw = row[arg.field];
13079
- if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
13080
- strVal = raw;
13081
- } else if (arg.type === "ARITH" || arg.type === "NUMBER" || arg.type === "STRING_FUNC") {
13082
- const n = evalArithExpr(arg, row);
13083
- if (isNaN(n)) continue;
13084
- strVal = String(n);
13085
- } else {
13086
- const value = evalScalarValueExprNullable(arg, row);
13087
- if (value === null) continue;
13088
- if (value === "" && func !== "MIN" && func !== "MAX") continue;
13089
- if (typeof value === "number" && Number.isNaN(value)) continue;
13090
- strVal = String(value);
13091
- }
13092
- strValues.push(strVal);
13093
- }
13328
+ const strValues = aggregateRowValues(func, arg, rows).filter((value) => value !== null);
13094
13329
  const statistical = func === "STDDEV_POP" || func === "STDDEV_SAMP" || func === "VAR_POP" || func === "VAR_SAMP" || func === "MEDIAN";
13095
13330
  const numericValues = statistical ? strValues.map((value) => {
13096
13331
  const numeric = Number(value);
@@ -13168,6 +13403,27 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
13168
13403
  }
13169
13404
  }
13170
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
+ }
13171
13427
  function toAggregateFieldRef(field) {
13172
13428
  const dot = field.indexOf(".");
13173
13429
  return dot > 0 ? { type: "FIELD", tableAlias: field.slice(0, dot), field: field.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field };
@@ -13210,6 +13466,16 @@ function resolveAggregateArgSemantics(arg, resolver) {
13210
13466
  const first = results[0];
13211
13467
  return results.every((result) => JSON.stringify(result) === JSON.stringify(first)) ? first : kinds[0];
13212
13468
  }
13469
+ function aggregateResultSemantics(ref, resolver) {
13470
+ if (ref.func === "COUNT" || ref.func === "SUM" || ref.func === "AVG" || ref.func === "STDDEV_POP" || ref.func === "STDDEV_SAMP" || ref.func === "VAR_POP" || ref.func === "VAR_SAMP" || ref.func === "MEDIAN") {
13471
+ return syntheticSemantics("number");
13472
+ }
13473
+ if (ref.func === "GROUP_CONCAT" || ref.func === "MODE") {
13474
+ return syntheticSemantics("string");
13475
+ }
13476
+ const semantics = ref.arg.type === "WILDCARD" ? "string" : resolveAggregateArgSemantics(ref.arg, resolver) ?? "string";
13477
+ return typeof semantics === "string" ? syntheticSemantics(semantics) : semantics;
13478
+ }
13213
13479
  function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
13214
13480
  if (having === null) return rows;
13215
13481
  return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
@@ -13369,7 +13635,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
13369
13635
  break;
13370
13636
  }
13371
13637
  case "CASE_COL":
13372
- evaluators.set(alias, (row) => evalCaseWhen(column.expr, row, resolveFieldType, resolveFieldSemantics2));
13638
+ evaluators.set(alias, (row) => containsAggregate2(column.expr) ? row[alias] ?? "" : evalCaseWhen(column.expr, row, resolveFieldType, resolveFieldSemantics2));
13373
13639
  break;
13374
13640
  case "SCALAR_VALUE_COL": {
13375
13641
  const source = scalarValueDefaultKey(column.expr);
@@ -13388,7 +13654,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
13388
13654
  }
13389
13655
  return (name, row) => evaluators.get(name)?.(row);
13390
13656
  }
13391
- function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
13657
+ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2, resolveAggSortKind) {
13392
13658
  const windows = columns.filter((column) => column.type === "WINDOW_COL");
13393
13659
  if (rows.length === 0 || windows.length === 0) return rows;
13394
13660
  for (const window of windows) {
@@ -13402,6 +13668,10 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
13402
13668
  for (const partition of partitions.values()) {
13403
13669
  const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds, fieldSemantics2);
13404
13670
  const sorted = sortedResult.rows;
13671
+ if (!isRankingWindow(window)) {
13672
+ applyAggregateWindow(window, sortedResult, resolveAggSortKind);
13673
+ continue;
13674
+ }
13405
13675
  let rank = 1;
13406
13676
  let denseRank = 1;
13407
13677
  for (let index = 0; index < sorted.length; index++) {
@@ -13416,6 +13686,53 @@ function applyWindow(rows, columns, optionOrders, sortKinds, fieldSemantics2) {
13416
13686
  }
13417
13687
  return rows;
13418
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
+ }
13419
13736
  function resolveWindowField(row, ref) {
13420
13737
  const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
13421
13738
  return resolveFieldRef(row, name);
@@ -13458,7 +13775,7 @@ function evaluateSelectColumnValue(column, row, columnIndex, context = {}) {
13458
13775
  case "ARITH_COL":
13459
13776
  return String(evalArithExpr(column.expr, row));
13460
13777
  case "CASE_COL":
13461
- return evalCaseWhen(
13778
+ return containsAggregate2(column.expr) ? row[caseMaterializedKey(column.alias, columnIndex)] ?? "" : evalCaseWhen(
13462
13779
  column.expr,
13463
13780
  row,
13464
13781
  context.resolveFieldType,
@@ -13523,13 +13840,14 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13523
13840
  return { rows: projected2, columns: cols };
13524
13841
  }
13525
13842
  const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
13843
+ const defaultCaseKeys = buildDefaultCaseOutputKeys(columns);
13526
13844
  const hasWildcard = columns.some(
13527
13845
  (col) => col.type === "WILDCARD" || col.type === "PARENT_WILDCARD"
13528
13846
  );
13529
- const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys);
13847
+ const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys, defaultCaseKeys);
13530
13848
  const orderedKeys = outputKeys ?? [];
13531
13849
  if (hasWildcard && rows.length === 0) {
13532
- return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys) };
13850
+ return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) };
13533
13851
  }
13534
13852
  const projected = rows.map((row, rowIdx) => {
13535
13853
  const out = {};
@@ -13596,7 +13914,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13596
13914
  break;
13597
13915
  }
13598
13916
  case "CASE_COL": {
13599
- const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
13917
+ const key = outputKeys?.[colIdx] ?? col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13600
13918
  out[key] = value;
13601
13919
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
13602
13920
  break;
@@ -13637,15 +13955,15 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13637
13955
  });
13638
13956
  return { rows: projected, columns: orderedKeys };
13639
13957
  }
13640
- function computeOutputKeys(columns, defaultFieldKeys) {
13641
- return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys));
13958
+ function computeOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) {
13959
+ return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys));
13642
13960
  }
13643
- function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13961
+ function computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) {
13644
13962
  const keys = [];
13645
13963
  const seen = /* @__PURE__ */ new Set();
13646
13964
  for (const [colIdx, col] of columns.entries()) {
13647
13965
  if (col.type === "WILDCARD" || col.type === "PARENT_WILDCARD") continue;
13648
- const key = computeOutputKey(col, colIdx, defaultFieldKeys);
13966
+ const key = computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys);
13649
13967
  if (!seen.has(key)) {
13650
13968
  seen.add(key);
13651
13969
  keys.push(key);
@@ -13653,7 +13971,7 @@ function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13653
13971
  }
13654
13972
  return keys;
13655
13973
  }
13656
- function computeOutputKey(col, colIdx, defaultFieldKeys) {
13974
+ function computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys) {
13657
13975
  switch (col.type) {
13658
13976
  case "VARIABLE_COL":
13659
13977
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
@@ -13668,7 +13986,7 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13668
13986
  case "ARITH_COL":
13669
13987
  return col.alias ?? arithColDefaultKey(col.expr);
13670
13988
  case "CASE_COL":
13671
- return col.alias ?? "case";
13989
+ return col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13672
13990
  case "STRFUNC_COL":
13673
13991
  return col.alias ?? stringFuncDefaultKey(col.expr);
13674
13992
  case "SCALAR_VALUE_COL":
@@ -13684,6 +14002,24 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13684
14002
  throw new Error("internal: computeOutputKey received a wildcard column");
13685
14003
  }
13686
14004
  }
14005
+ function buildDefaultCaseOutputKeys(columns) {
14006
+ const used = new Set(columns.flatMap(
14007
+ (column) => "alias" in column && column.alias !== null ? [column.alias] : []
14008
+ ));
14009
+ const keys = /* @__PURE__ */ new Map();
14010
+ let suffix = 1;
14011
+ for (const [columnIndex, column] of columns.entries()) {
14012
+ if (column.type !== "CASE_COL" || column.alias !== null) continue;
14013
+ let key;
14014
+ do {
14015
+ key = suffix === 1 ? "case" : `case_${suffix}`;
14016
+ suffix++;
14017
+ } while (used.has(key));
14018
+ used.add(key);
14019
+ keys.set(columnIndex, key);
14020
+ }
14021
+ return keys;
14022
+ }
13687
14023
  function buildDefaultFieldOutputKeys(columns) {
13688
14024
  const qualifierCollisionCount = /* @__PURE__ */ new Map();
13689
14025
  for (const col of columns) {
@@ -13773,6 +14109,7 @@ function scalarValueHasAggregate2(expr) {
13773
14109
  return false;
13774
14110
  }
13775
14111
  function caseResultHasAggregate2(result) {
14112
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
13776
14113
  if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
13777
14114
  return scalarValueHasAggregate2(result);
13778
14115
  }
@@ -13795,6 +14132,7 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
13795
14132
  }
13796
14133
  function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13797
14134
  if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
14135
+ if (expr.type === "CASE_WHEN") return resolveAggInCaseExpr(expr, rows, resolveAggSortKind);
13798
14136
  if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
13799
14137
  return {
13800
14138
  ...expr,
@@ -13804,6 +14142,35 @@ function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13804
14142
  }
13805
14143
  return expr;
13806
14144
  }
14145
+ function resolveAggInCaseResult(result, rows, resolveAggSortKind) {
14146
+ if (result.type === "AGG_REF") {
14147
+ const value = evalAggregate(
14148
+ result.func,
14149
+ result.distinct,
14150
+ result.arg,
14151
+ result.separator,
14152
+ rows,
14153
+ resolveAggSortKind
14154
+ );
14155
+ return typeof value === "number" ? { type: "NUMBER", value, raw: String(value) } : { type: "STRING", value };
14156
+ }
14157
+ if (result.type === "AGG_ARITH") {
14158
+ const value = evalAggArithExpr(result, rows, resolveAggSortKind);
14159
+ return { type: "NUMBER", value, raw: String(value) };
14160
+ }
14161
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return result;
14162
+ return resolveAggInScalarValue(result, rows, resolveAggSortKind);
14163
+ }
14164
+ function resolveAggInCaseExpr(expr, rows, resolveAggSortKind) {
14165
+ return {
14166
+ ...expr,
14167
+ branches: expr.branches.map((branch) => ({
14168
+ ...branch,
14169
+ result: resolveAggInCaseResult(branch.result, rows, resolveAggSortKind)
14170
+ })),
14171
+ elseResult: expr.elseResult === null ? null : resolveAggInCaseResult(expr.elseResult, rows, resolveAggSortKind)
14172
+ };
14173
+ }
13807
14174
  function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
13808
14175
  return {
13809
14176
  type: "STRING_FUNC",
@@ -13832,12 +14199,19 @@ function mergeKnownColumns(left, right, rows) {
13832
14199
  ...Object.keys(rows[0] ?? {})
13833
14200
  ])];
13834
14201
  }
13835
- function deriveOutputOrderSemantics(columns) {
14202
+ function deriveOutputOrderSemantics(columns, resolveAggSortKind) {
13836
14203
  const result = /* @__PURE__ */ new Map();
13837
14204
  for (const column of columns) {
13838
14205
  if (!("alias" in column) || !column.alias) continue;
13839
- if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
14206
+ if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
13840
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
+ }
13841
14215
  } else if (column.type === "AGGREGATE") {
13842
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") {
13843
14217
  result.set(column.alias, syntheticSemantics("number"));
@@ -13872,7 +14246,7 @@ function runFullScan(input) {
13872
14246
  resolvedGroupingSpec,
13873
14247
  plainGroupByPlan
13874
14248
  } = input;
13875
- const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns);
14249
+ const effectiveOrderSemantics = deriveOutputOrderSemantics(stmt.columns, aggregateSortKindResolver);
13876
14250
  for (const [key, value] of orderSemantics ?? []) effectiveOrderSemantics.set(key, value);
13877
14251
  let rows = [];
13878
14252
  const mainAlias = stmt.from.alias;
@@ -13926,8 +14300,16 @@ function runFullScan(input) {
13926
14300
  }
13927
14301
  );
13928
14302
  }
13929
- rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
13930
- rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
14303
+ const resolveHavingSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, aggregateSortKindResolver) : havingFieldSemanticsResolver?.(field);
14304
+ rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, resolveHavingSemantics);
14305
+ rows = applyWindow(
14306
+ rows,
14307
+ stmt.columns,
14308
+ optionOrders,
14309
+ sortKinds,
14310
+ effectiveOrderSemantics,
14311
+ aggregateSortKindResolver
14312
+ );
13931
14313
  if (stmt.distinct) {
13932
14314
  rows = applyDistinct(
13933
14315
  rows,
@@ -16412,8 +16794,8 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
16412
16794
  tempTables
16413
16795
  );
16414
16796
  const first = resolvedStmt2.expr.query.columns[0];
16415
- 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");
16416
- 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")) {
16417
16799
  const meta = (await inferSelectColumnMeta(
16418
16800
  resolvedStmt2.expr.query,
16419
16801
  ["__scalar__"],
@@ -17039,8 +17421,21 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
17039
17421
  if (!("alias" in column) || !column.alias) continue;
17040
17422
  let semantics;
17041
17423
  if (column.type === "FIELD") semantics = rowResolver(aggregateFieldRef(column.field));
17042
- else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
17424
+ else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
17043
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
+ }
17044
17439
  } else if (column.type === "AGGREGATE") {
17045
17440
  if (column.func === "MIN" || column.func === "MAX" || column.func === "MODE") {
17046
17441
  if (column.arg.type !== "WILDCARD") {
@@ -17402,6 +17797,7 @@ async function validateSelectGroupingPlanning(stmt, client, cacheContext, materi
17402
17797
  function completeInputErrorPrefix(reasons) {
17403
17798
  const reasonList = [...reasons].join(", ");
17404
17799
  const aggregateSubjects = [
17800
+ ["AGGREGATE_WINDOW", "\u96C6\u8A08\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17405
17801
  ["GROUPING_SETS", "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17406
17802
  ["STATISTICAL_AGGREGATE", "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C"],
17407
17803
  ["AGGREGATE", "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C"],
@@ -17468,7 +17864,7 @@ function scalarValueHasFieldRef(expr) {
17468
17864
  }
17469
17865
  if (expr.type === "CASE_WHEN") {
17470
17866
  const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
17471
- return results.some((result) => result.type !== "ARRAY" && (result.type === "FIELD_REF" || result.type === "ARITH" ? arithHasFieldRef(result) : scalarValueHasFieldRef(result)));
17867
+ return results.some((result) => result.type !== "ARRAY" && (result.type === "FIELD_REF" || result.type === "ARITH" ? arithHasFieldRef(result) : result.type === "AGG_REF" || result.type === "AGG_ARITH" ? true : scalarValueHasFieldRef(result)));
17472
17868
  }
17473
17869
  return false;
17474
17870
  }
@@ -18020,7 +18416,8 @@ function collectAggregateArgFieldRefs(arg, out) {
18020
18416
  }
18021
18417
  if (arg.type === "CASE_WHEN") {
18022
18418
  for (const result of [...arg.branches.map((branch) => branch.result), ...arg.elseResult ? [arg.elseResult] : []]) {
18023
- if (result.type !== "ARRAY") collectAggregateArgFieldRefs(result, out);
18419
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") collectAggregateOperandRefs(result, out);
18420
+ else if (result.type !== "ARRAY") collectAggregateArgFieldRefs(result, out);
18024
18421
  }
18025
18422
  }
18026
18423
  }
@@ -18057,10 +18454,29 @@ function collectScalarAggregateRefs(expr, out) {
18057
18454
  const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
18058
18455
  for (const result of results) {
18059
18456
  if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
18457
+ else if (result.type === "AGG_REF" || result.type === "AGG_ARITH") collectAggregateOperandRefs(result, out);
18060
18458
  else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
18061
18459
  }
18062
18460
  }
18063
18461
  }
18462
+ function collectCaseAggregateRefs(expr, out) {
18463
+ const visit = (node) => {
18464
+ if (node === null || typeof node !== "object") return;
18465
+ if (Array.isArray(node)) {
18466
+ node.forEach(visit);
18467
+ return;
18468
+ }
18469
+ const value = node;
18470
+ if (value["type"] === "AGG_REF") {
18471
+ const aggregate = value;
18472
+ collectAggregateRef(aggregate.func, aggregate.arg, out);
18473
+ return;
18474
+ }
18475
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
18476
+ Object.values(value).forEach(visit);
18477
+ };
18478
+ visit(expr);
18479
+ }
18064
18480
  function collectSelectAggregateSortRefs(columns) {
18065
18481
  const refs = [];
18066
18482
  for (const column of columns) {
@@ -18072,6 +18488,8 @@ function collectSelectAggregateSortRefs(columns) {
18072
18488
  collectStringFuncAggregateRefs(column.expr, refs);
18073
18489
  } else if (column.type === "SCALAR_VALUE_COL") {
18074
18490
  collectScalarAggregateRefs(column.expr, refs);
18491
+ } else if (column.type === "CASE_COL") {
18492
+ collectCaseAggregateRefs(column.expr, refs);
18075
18493
  }
18076
18494
  }
18077
18495
  return refs;
@@ -18249,6 +18667,13 @@ function stringFunctionColumnMeta(expr) {
18249
18667
  function caseResultColumnMeta(result, resolveField2) {
18250
18668
  if (result.type === "STRING") return syntheticColumnMeta("string");
18251
18669
  if (result.type === "ARRAY") return unsupportedColumnMeta();
18670
+ if (result.type === "AGG_REF") {
18671
+ if (result.func === "MIN" || result.func === "MAX" || result.func === "MODE") {
18672
+ return result.arg.type === "WILDCARD" ? unknownStringColumnMeta() : inferAggregateArgMeta(result.arg, resolveField2);
18673
+ }
18674
+ return result.func === "GROUP_CONCAT" ? syntheticColumnMeta("string") : syntheticColumnMeta("number");
18675
+ }
18676
+ if (result.type === "AGG_ARITH") return syntheticColumnMeta("number");
18252
18677
  if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
18253
18678
  if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
18254
18679
  if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();
@@ -18286,12 +18711,18 @@ function inferAggregateArgMeta(arg, resolveField2) {
18286
18711
  if (arg.elseResult) results.push(caseResultColumnMeta(arg.elseResult, resolveField2));
18287
18712
  return mergeExpressionColumnMeta(results);
18288
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
+ }
18289
18720
  function withDisplayName(meta, displayName) {
18290
18721
  return { ...meta ?? {}, displayName };
18291
18722
  }
18292
18723
  function selectNeedsSourceColumnMeta(stmt) {
18293
18724
  return stmt.columns.some(
18294
- (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")
18295
18726
  );
18296
18727
  }
18297
18728
  async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables, forLibraryCapture = false) {
@@ -18397,7 +18828,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
18397
18828
  } else if (column.type === "STRFUNC_COL") {
18398
18829
  meta = stringFunctionColumnMeta(column.expr);
18399
18830
  } else if (column.type === "WINDOW_COL") {
18400
- meta = syntheticColumnMeta("number");
18831
+ meta = inferWindowColumnMeta(column, resolveField2);
18401
18832
  } else if (column.type === "CASE_COL") {
18402
18833
  const results = column.expr.branches.map((branch) => caseResultColumnMeta(branch.result, resolveField2));
18403
18834
  if (column.expr.elseResult) results.push(caseResultColumnMeta(column.expr.elseResult, resolveField2));
@@ -19324,8 +19755,10 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
19324
19755
  if (!("alias" in column) || !column.alias) continue;
19325
19756
  let meta;
19326
19757
  if (column.type === "FIELD") meta = resolveField2(aggregateFieldRef(column.field));
19327
- else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
19758
+ else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL") {
19328
19759
  meta = syntheticColumnMeta("number");
19760
+ } else if (column.type === "WINDOW_COL") {
19761
+ meta = inferWindowColumnMeta(column, resolveField2);
19329
19762
  } else if (column.type === "GROUPING_COL") {
19330
19763
  meta = syntheticColumnMeta("number");
19331
19764
  } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta = syntheticColumnMeta("string");
@@ -23363,6 +23796,20 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
23363
23796
  }
23364
23797
  }
23365
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
+ }
23366
23813
  if (totalCountPlan) {
23367
23814
  const baseQuery = stmt.where === null ? "" : whereToKintone(stmt.where);
23368
23815
  lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);