@rex0220/kintone-sql-tools 3.44.0 → 3.45.0

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