@rex0220/kintone-sql-tools 2.14.1 → 2.16.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
@@ -87,6 +87,10 @@ var KEYWORDS = /* @__PURE__ */ new Map([
87
87
  ["AVG", "AVG" /* AVG */],
88
88
  ["MAX", "MAX" /* MAX */],
89
89
  ["MIN", "MIN" /* MIN */],
90
+ ["GROUP_CONCAT", "GROUP_CONCAT" /* GROUP_CONCAT */],
91
+ ["ROW_NUMBER", "ROW_NUMBER" /* ROW_NUMBER */],
92
+ ["RANK", "RANK" /* RANK */],
93
+ ["DENSE_RANK", "DENSE_RANK" /* DENSE_RANK */],
90
94
  ["ASSERT", "ASSERT" /* ASSERT */],
91
95
  ["AND", "AND" /* AND */],
92
96
  ["OR", "OR" /* OR */],
@@ -463,6 +467,9 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
463
467
  "AVG" /* AVG */,
464
468
  "MAX" /* MAX */,
465
469
  "MIN" /* MIN */,
470
+ "ROW_NUMBER" /* ROW_NUMBER */,
471
+ "RANK" /* RANK */,
472
+ "DENSE_RANK" /* DENSE_RANK */,
466
473
  "TODAY" /* TODAY */,
467
474
  "NOW" /* NOW */,
468
475
  "LOGINUSER" /* LOGINUSER */,
@@ -981,6 +988,11 @@ var Parser = class {
981
988
  const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
982
989
  const limit = this.consume("LIMIT" /* LIMIT */) ? this.parseUnsignedInt() : null;
983
990
  const offset = this.consume("OFFSET" /* OFFSET */) ? this.parseUnsignedInt() : null;
991
+ const hasWindow = columns.some((column) => column.type === "WINDOW_COL");
992
+ const hasAggregate = columns.some((column) => this.selectColumnHasAggregate(column));
993
+ if (hasWindow && (groupBy.length > 0 || hasAggregate)) {
994
+ throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306F GROUP BY / \u96C6\u8A08\u95A2\u6570\u3068\u540C\u3058 SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
995
+ }
984
996
  return {
985
997
  type: "SELECT",
986
998
  distinct,
@@ -1045,6 +1057,10 @@ var Parser = class {
1045
1057
  if (this.consume("*" /* STAR */)) {
1046
1058
  return { type: "WILDCARD" };
1047
1059
  }
1060
+ const windowFunc = this.tryWindowFunc();
1061
+ if (windowFunc !== null) {
1062
+ return this.parseWindowColumn(windowFunc);
1063
+ }
1048
1064
  if (this.peek().kind === "CASE" /* CASE */) {
1049
1065
  const expr = this.parseCaseWhenExpr();
1050
1066
  const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
@@ -1079,6 +1095,7 @@ var Parser = class {
1079
1095
  func: ref.func,
1080
1096
  distinct: ref.distinct,
1081
1097
  arg: ref.arg,
1098
+ ...ref.separator !== void 0 ? { separator: ref.separator } : {},
1082
1099
  alias: alias2
1083
1100
  };
1084
1101
  }
@@ -1115,6 +1132,56 @@ var Parser = class {
1115
1132
  const alias = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1116
1133
  return { type: "FIELD", field, alias };
1117
1134
  }
1135
+ tryWindowFunc() {
1136
+ switch (this.peek().kind) {
1137
+ case "ROW_NUMBER" /* ROW_NUMBER */:
1138
+ return "ROW_NUMBER";
1139
+ case "RANK" /* RANK */:
1140
+ return "RANK";
1141
+ case "DENSE_RANK" /* DENSE_RANK */:
1142
+ return "DENSE_RANK";
1143
+ default:
1144
+ return null;
1145
+ }
1146
+ }
1147
+ parseWindowColumn(func) {
1148
+ this.advance();
1149
+ this.expect("(" /* LPAREN */);
1150
+ if (this.peek().kind !== ")" /* RPAREN */) {
1151
+ throw new ParseError(`${func} \u306F\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u305B\u3093`, this.peek());
1152
+ }
1153
+ this.expect(")" /* RPAREN */);
1154
+ this.expectSoftKeyword("OVER", `${func} \u306B\u306F OVER (...) \u304C\u5FC5\u8981\u3067\u3059`);
1155
+ this.expect("(" /* LPAREN */);
1156
+ const partitionBy = [];
1157
+ if (this.isSoftKeyword("PARTITION")) {
1158
+ this.advance();
1159
+ this.expect("BY" /* BY */, "PARTITION \u306E\u5F8C\u306B\u306F BY \u304C\u5FC5\u8981\u3067\u3059");
1160
+ do {
1161
+ const ref = this.parseQualifiedIdent();
1162
+ partitionBy.push({ type: "FIELD", tableAlias: ref.tableAlias, field: ref.field });
1163
+ } while (this.consume("," /* COMMA */));
1164
+ }
1165
+ const orderBy = this.consume("ORDER" /* ORDER */) ? (this.expect("BY" /* BY */), this.parseOrderBy()) : [];
1166
+ this.expect(")" /* RPAREN */);
1167
+ if (!this.consume("AS" /* AS */)) {
1168
+ throw new ParseError("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
1169
+ }
1170
+ const alias = this.parseAliasName();
1171
+ return { type: "WINDOW_COL", func, partitionBy, orderBy, alias };
1172
+ }
1173
+ selectColumnHasAggregate(column) {
1174
+ if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
1175
+ if (column.type !== "STRFUNC_COL") return false;
1176
+ return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
1177
+ }
1178
+ stringFuncArgHasAggregate(arg) {
1179
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
1180
+ if (arg.type === "STRING_FUNC") {
1181
+ return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
1182
+ }
1183
+ return false;
1184
+ }
1118
1185
  isArithOp(kind) {
1119
1186
  return kind === "+" /* PLUS */ || kind === "-" /* MINUS */ || kind === "*" /* STAR */ || kind === "/" /* SLASH */ || kind === "%" /* PERCENT */;
1120
1187
  }
@@ -1450,7 +1517,8 @@ var Parser = class {
1450
1517
  ["SUM" /* SUM */]: "SUM",
1451
1518
  ["AVG" /* AVG */]: "AVG",
1452
1519
  ["MAX" /* MAX */]: "MAX",
1453
- ["MIN" /* MIN */]: "MIN"
1520
+ ["MIN" /* MIN */]: "MIN",
1521
+ ["GROUP_CONCAT" /* GROUP_CONCAT */]: "GROUP_CONCAT"
1454
1522
  };
1455
1523
  const kind = this.peek().kind;
1456
1524
  return map[kind] ?? null;
@@ -1462,12 +1530,29 @@ var Parser = class {
1462
1530
  const distinct = this.consume("DISTINCT" /* DISTINCT */);
1463
1531
  let arg;
1464
1532
  if (this.consume("*" /* STAR */)) {
1533
+ if (func === "GROUP_CONCAT") {
1534
+ throw new ParseError("GROUP_CONCAT(*) \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u30D5\u30A3\u30FC\u30EB\u30C9\u307E\u305F\u306F\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", this.prev());
1535
+ }
1465
1536
  arg = { type: "WILDCARD" };
1466
1537
  } else {
1467
1538
  arg = this.parseArithAddSub();
1468
1539
  }
1540
+ let separator;
1541
+ if (this.isSoftKeyword("SEPARATOR")) {
1542
+ const separatorToken = this.advance();
1543
+ if (func !== "GROUP_CONCAT") {
1544
+ throw new ParseError("SEPARATOR \u306F GROUP_CONCAT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059", separatorToken);
1545
+ }
1546
+ separator = this.expect("STRING" /* STRING */, "SEPARATOR \u306E\u5F8C\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059").value;
1547
+ }
1469
1548
  this.expect(")" /* RPAREN */);
1470
- return { type: "AGG_REF", func, distinct, arg };
1549
+ return {
1550
+ type: "AGG_REF",
1551
+ func,
1552
+ distinct,
1553
+ arg,
1554
+ ...separator !== void 0 ? { separator } : {}
1555
+ };
1471
1556
  }
1472
1557
  // ----------------------------------------------------------
1473
1558
  // FROM / JOIN
@@ -1745,10 +1830,20 @@ var Parser = class {
1745
1830
  const distinct = this.consume("DISTINCT" /* DISTINCT */);
1746
1831
  let argStr;
1747
1832
  if (this.consume("*" /* STAR */)) {
1833
+ if (aggFunc === "GROUP_CONCAT") {
1834
+ throw new ParseError("GROUP_CONCAT(*) \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u30D5\u30A3\u30FC\u30EB\u30C9\u307E\u305F\u306F\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", this.prev());
1835
+ }
1748
1836
  argStr = "*";
1749
1837
  } else {
1750
1838
  argStr = this.parseIdentifier();
1751
1839
  }
1840
+ if (this.isSoftKeyword("SEPARATOR")) {
1841
+ const separatorToken = this.advance();
1842
+ if (aggFunc !== "GROUP_CONCAT") {
1843
+ throw new ParseError("SEPARATOR \u306F GROUP_CONCAT \u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059", separatorToken);
1844
+ }
1845
+ this.expect("STRING" /* STRING */, "SEPARATOR \u306E\u5F8C\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
1846
+ }
1752
1847
  this.expect(")" /* RPAREN */);
1753
1848
  const syntheticName = distinct ? `${aggFunc}(DISTINCT ${argStr})` : `${aggFunc}(${argStr})`;
1754
1849
  return { type: "FIELD", tableAlias: null, field: syntheticName };
@@ -2868,12 +2963,16 @@ var KintoneQueryError = class extends Error {
2868
2963
  };
2869
2964
 
2870
2965
  // src/converter/selectToKintone.ts
2966
+ function hasWindowColumns(columns) {
2967
+ return columns.some((column) => column.type === "WINDOW_COL");
2968
+ }
2871
2969
  function resolveSelectMode(stmt) {
2872
2970
  if (stmt.from.subtableCode) return "FULL_SCAN";
2873
2971
  if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
2874
2972
  if (stmt.joins.length > 0) return "FULL_SCAN";
2875
2973
  if (stmt.groupBy.length > 0) return "FULL_SCAN";
2876
2974
  if (stmt.distinct) return "FULL_SCAN";
2975
+ if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
2877
2976
  if (stmt.columns.some(
2878
2977
  (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
2879
2978
  )) return "FULL_SCAN";
@@ -3245,16 +3344,16 @@ function collectRequiredFieldsByTable(stmt) {
3245
3344
  }
3246
3345
  walkStringFunc(k.expr, "groupBy");
3247
3346
  };
3248
- const walkOrderByKey = (k) => {
3347
+ const walkOrderByKey = (k, phase = "orderBy") => {
3249
3348
  if (k.type === "FIELD_NAME") {
3250
- addFieldName(k.name, "orderBy");
3349
+ addFieldName(k.name, phase);
3251
3350
  return;
3252
3351
  }
3253
3352
  if (k.type === "ARITH_KEY") {
3254
- walkArith(k.expr, "orderBy");
3353
+ walkArith(k.expr, phase);
3255
3354
  return;
3256
3355
  }
3257
- walkStringFunc(k.expr, "orderBy");
3356
+ walkStringFunc(k.expr, phase);
3258
3357
  };
3259
3358
  for (const col of stmt.columns) {
3260
3359
  switch (col.type) {
@@ -3286,6 +3385,10 @@ function collectRequiredFieldsByTable(stmt) {
3286
3385
  break;
3287
3386
  case "SCALAR_SUBQUERY_COL":
3288
3387
  break;
3388
+ case "WINDOW_COL":
3389
+ for (const ref of col.partitionBy) addFieldRef(ref.field, ref.tableAlias, "select");
3390
+ for (const item of col.orderBy) walkOrderByKey(item.key, "select");
3391
+ break;
3289
3392
  }
3290
3393
  }
3291
3394
  for (const join2 of stmt.joins) {
@@ -3332,6 +3435,10 @@ function collectSelectOutputNames(columns) {
3332
3435
  }
3333
3436
  if (col.type === "SCALAR_SUBQUERY_COL") {
3334
3437
  names.add(col.alias ?? "(subquery)");
3438
+ continue;
3439
+ }
3440
+ if (col.type === "WINDOW_COL") {
3441
+ names.add(col.alias);
3335
3442
  }
3336
3443
  }
3337
3444
  return names;
@@ -3357,7 +3464,7 @@ function stringFuncLabel(expr) {
3357
3464
  return `${expr.func}(${args.join(",")})`;
3358
3465
  }
3359
3466
  function isAggregateSyntheticName(name) {
3360
- return /^(COUNT|SUM|AVG|MAX|MIN)\(/i.test(name);
3467
+ return /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT)\(/i.test(name);
3361
3468
  }
3362
3469
 
3363
3470
  // src/core/cteInlining.ts
@@ -5123,7 +5230,7 @@ function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
5123
5230
  for (const col of columns) {
5124
5231
  if (col.type === "AGGREGATE") {
5125
5232
  const syntheticKey = aggregateSyntheticName2(col.func, col.distinct, col.arg);
5126
- const value = String(evalAggregate(col.func, col.distinct, col.arg, groupRows, resolveAggSortKind));
5233
+ const value = String(evalAggregate(col.func, col.distinct, col.arg, col.separator, groupRows, resolveAggSortKind));
5127
5234
  outRow[col.alias ?? syntheticKey] = value;
5128
5235
  if (col.alias) outRow[syntheticKey] = value;
5129
5236
  } else if (col.type === "ARITH_AGG_COL") {
@@ -5144,7 +5251,7 @@ function evalGroupByKey(key, row) {
5144
5251
  if (key.type === "FUNC_KEY") return evalStringFunc(key.expr, row);
5145
5252
  return String(evalArithExpr(key.expr, row));
5146
5253
  }
5147
- function evalAggregate(func, distinct, arg, rows, resolveAggSortKind) {
5254
+ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind) {
5148
5255
  if (arg.type === "WILDCARD") {
5149
5256
  return func === "COUNT" ? rows.length : 0;
5150
5257
  }
@@ -5164,6 +5271,7 @@ function evalAggregate(func, distinct, arg, rows, resolveAggSortKind) {
5164
5271
  }
5165
5272
  const eff = distinct ? [...new Set(strValues)] : strValues;
5166
5273
  if (func === "COUNT") return eff.length;
5274
+ if (func === "GROUP_CONCAT") return eff.join(separator ?? ",");
5167
5275
  const sortKind = (func === "MIN" || func === "MAX") && arg.type === "FIELD_REF" ? resolveAggSortKind?.(toAggregateFieldRef(arg.field)) : void 0;
5168
5276
  if (sortKind === "string") {
5169
5277
  if (eff.length === 0) return "";
@@ -5208,7 +5316,7 @@ function minOf(nums) {
5208
5316
  }
5209
5317
  function evalAggArithExpr(node, rows, resolveAggSortKind) {
5210
5318
  if (node.type === "NUMBER") return node.value;
5211
- if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, rows, resolveAggSortKind));
5319
+ if (node.type === "AGG_REF") return Number(evalAggregate(node.func, node.distinct, node.arg, node.separator, rows, resolveAggSortKind));
5212
5320
  const l = evalAggArithExpr(node.left, rows, resolveAggSortKind);
5213
5321
  const r = evalAggArithExpr(node.right, rows, resolveAggSortKind);
5214
5322
  switch (node.op) {
@@ -5278,6 +5386,10 @@ function buildDistinctKeyBuilder(rows, columns) {
5278
5386
  values.push(row[col.field] ?? "");
5279
5387
  continue;
5280
5388
  }
5389
+ if (col.type === "WINDOW_COL") {
5390
+ values.push(row[col.alias] ?? "");
5391
+ continue;
5392
+ }
5281
5393
  if (col.type === "PARENT_WILDCARD") {
5282
5394
  for (const k of sortedParentKeys) {
5283
5395
  values.push(row[k] !== void 0 ? row[k] : null);
@@ -5289,6 +5401,9 @@ function buildDistinctKeyBuilder(rows, columns) {
5289
5401
  }
5290
5402
  function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
5291
5403
  if (orderBy.length === 0) return rows;
5404
+ return sortDecoratedRows(rows, orderBy, optionOrders, sortKinds).rows.map((item) => item.row);
5405
+ }
5406
+ function sortDecoratedRows(rows, orderBy, optionOrders, sortKinds) {
5292
5407
  const keyMeta = orderBy.map(({ key }) => ({
5293
5408
  orderMap: key.type === "FIELD_NAME" ? optionOrders?.get(key.name) : void 0,
5294
5409
  sortKind: key.type === "FIELD_NAME" ? sortKinds?.get(key.name) : void 0
@@ -5307,14 +5422,16 @@ function applyOrderBy(rows, orderBy, optionOrders, sortKinds) {
5307
5422
  };
5308
5423
  })
5309
5424
  }));
5310
- decorated.sort((a, b) => {
5311
- for (let i = 0; i < orderBy.length; i++) {
5312
- const cmp = compareSortKeys(a.keys[i], b.keys[i], keyMeta[i]);
5313
- if (cmp !== 0) return orderBy[i].direction === "ASC" ? cmp : -cmp;
5314
- }
5315
- return 0;
5316
- });
5317
- return decorated.map((d) => d.row);
5425
+ const compare = (a, b) => compareDecoratedRows(a, b, orderBy, keyMeta);
5426
+ decorated.sort(compare);
5427
+ return { rows: decorated, compare };
5428
+ }
5429
+ function compareDecoratedRows(a, b, orderBy, keyMeta) {
5430
+ for (let i = 0; i < orderBy.length; i++) {
5431
+ const cmp = compareSortKeys(a.keys[i], b.keys[i], keyMeta[i]);
5432
+ if (cmp !== 0) return orderBy[i].direction === "ASC" ? cmp : -cmp;
5433
+ }
5434
+ return 0;
5318
5435
  }
5319
5436
  function compareSortKeys(a, b, meta) {
5320
5437
  if (meta.orderMap) {
@@ -5359,6 +5476,38 @@ function minChoiceIndex(values, orderMap) {
5359
5476
  }
5360
5477
  return min;
5361
5478
  }
5479
+ function applyWindow(rows, columns, optionOrders, sortKinds) {
5480
+ const windows = columns.filter((column) => column.type === "WINDOW_COL");
5481
+ if (rows.length === 0 || windows.length === 0) return rows;
5482
+ for (const window of windows) {
5483
+ const partitions = /* @__PURE__ */ new Map();
5484
+ for (const row of rows) {
5485
+ const key = JSON.stringify(window.partitionBy.map((ref) => resolveWindowField(row, ref)));
5486
+ const partition = partitions.get(key);
5487
+ if (partition) partition.push(row);
5488
+ else partitions.set(key, [row]);
5489
+ }
5490
+ for (const partition of partitions.values()) {
5491
+ const sortedResult = sortDecoratedRows(partition, window.orderBy, optionOrders, sortKinds);
5492
+ const sorted = sortedResult.rows;
5493
+ let rank = 1;
5494
+ let denseRank = 1;
5495
+ for (let index = 0; index < sorted.length; index++) {
5496
+ if (index > 0 && sortedResult.compare(sorted[index - 1], sorted[index]) !== 0) {
5497
+ rank = index + 1;
5498
+ denseRank++;
5499
+ }
5500
+ const value = window.func === "ROW_NUMBER" ? index + 1 : window.func === "RANK" ? rank : denseRank;
5501
+ sorted[index].row[window.alias] = String(value);
5502
+ }
5503
+ }
5504
+ }
5505
+ return rows;
5506
+ }
5507
+ function resolveWindowField(row, ref) {
5508
+ const name = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
5509
+ return resolveFieldRef(row, name);
5510
+ }
5362
5511
  function applyLimit(rows, limit, offset) {
5363
5512
  const start = offset ?? 0;
5364
5513
  if (limit === null) return rows.slice(start);
@@ -5449,6 +5598,12 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns) {
5449
5598
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
5450
5599
  break;
5451
5600
  }
5601
+ case "WINDOW_COL": {
5602
+ const key = outputKeys?.[colIdx] ?? col.alias;
5603
+ out[key] = row[col.alias] ?? "";
5604
+ if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
5605
+ break;
5606
+ }
5452
5607
  }
5453
5608
  }
5454
5609
  return out;
@@ -5489,6 +5644,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
5489
5644
  return col.alias ?? stringFuncDefaultKey(col.expr);
5490
5645
  case "SCALAR_SUBQUERY_COL":
5491
5646
  return col.alias ?? "(subquery)";
5647
+ case "WINDOW_COL":
5648
+ return col.alias;
5492
5649
  case "WILDCARD":
5493
5650
  case "PARENT_WILDCARD":
5494
5651
  throw new Error("internal: computeOutputKey received a wildcard column");
@@ -5557,7 +5714,7 @@ function hasAggregateInStringFuncExpr2(expr) {
5557
5714
  }
5558
5715
  function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
5559
5716
  if (arg.type === "AGG_REF") {
5560
- const value = evalAggregate(arg.func, arg.distinct, arg.arg, rows, resolveAggSortKind);
5717
+ const value = evalAggregate(arg.func, arg.distinct, arg.arg, arg.separator, rows, resolveAggSortKind);
5561
5718
  return typeof value === "number" ? { type: "NUMBER", value } : { type: "STRING", value };
5562
5719
  }
5563
5720
  if (arg.type === "AGG_ARITH") {
@@ -5603,6 +5760,7 @@ function runFullScan(input) {
5603
5760
  rows = applyGroupBy(rows, stmt.groupBy, stmt.columns, aggregateSortKindResolver);
5604
5761
  }
5605
5762
  rows = applyHaving(rows, stmt.having, havingFieldTypeResolver);
5763
+ rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds);
5606
5764
  if (stmt.distinct) {
5607
5765
  rows = applyDistinct(rows, stmt.columns);
5608
5766
  }
@@ -5803,7 +5961,8 @@ function isValidTemporal(value, type) {
5803
5961
  const date = new Date(Date.UTC(year, month - 1, day));
5804
5962
  if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return false;
5805
5963
  if (type === "DATE") return true;
5806
- return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && isValidTemporal(value.slice(11, value.endsWith("Z") ? -1 : value.length - 6), "TIME");
5964
+ const timePart = value.slice(11, value.endsWith("Z") ? -1 : value.length - 6).replace(/\.\d+$/, "");
5965
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && isValidTemporal(timePart, "TIME");
5807
5966
  }
5808
5967
 
5809
5968
  // src/core/dmlValidationCandidates.ts
@@ -5883,6 +6042,8 @@ var SearchAbortedError = class extends Error {
5883
6042
  this.name = "SearchAbortedError";
5884
6043
  }
5885
6044
  };
6045
+ var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
6046
+ var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
5886
6047
  async function execute(sql, client, options = {}) {
5887
6048
  const startedAt = Date.now();
5888
6049
  const stmt = parseSql(sql);
@@ -6028,16 +6189,25 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
6028
6189
  }
6029
6190
  }
6030
6191
  var TEMP_TABLE_MAX_ROWS = 1e4;
6031
- function appendValidationErrors(tempTables, name, columns, rows, maxRows) {
6192
+ function appendValidationErrors(tempTables, name, columns, rows, maxRows, columnMeta) {
6032
6193
  const current = tempTables.get(name);
6033
- if (current && (current.columns.length !== columns.length || current.columns.some((c, i) => c !== columns[i]))) {
6194
+ if (current && (current.columns.length !== columns.length || current.columns.some((c, i) => c !== columns[i]) || !materializedColumnMetaEqual(current.columnMeta, columnMeta))) {
6034
6195
  throw new Error(`ArgumentError: validation error table ${name} has a different schema.`);
6035
6196
  }
6036
6197
  const existingRows = current?.rows ?? [];
6037
6198
  if (existingRows.length + rows.length > maxRows) {
6038
6199
  throw new Error(`ArgumentError: temp table ${name} exceeds max rows (${maxRows}).`);
6039
6200
  }
6040
- tempTables.set(name, { columns: [...columns], rows: [...existingRows, ...rows] });
6201
+ tempTables.set(name, { columns: [...columns], rows: [...existingRows, ...rows], columnMeta });
6202
+ }
6203
+ function materializedColumnMetaEqual(left, right) {
6204
+ if (left === right) return true;
6205
+ if (!left || !right || left.size !== right.size) return false;
6206
+ for (const [column, meta] of left) {
6207
+ const candidate = right.get(column);
6208
+ if (!candidate || candidate.sortKind !== meta.sortKind || candidate.fieldType !== meta.fieldType) return false;
6209
+ }
6210
+ return true;
6041
6211
  }
6042
6212
  var BatchTimeoutError = class extends Error {
6043
6213
  constructor() {
@@ -6199,7 +6369,8 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
6199
6369
  resolvedStmt.validationErrorTable,
6200
6370
  result.columns,
6201
6371
  result.errors,
6202
- options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS
6372
+ options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS,
6373
+ materializedMetaByValidationResult.get(result) ?? /* @__PURE__ */ new Map()
6203
6374
  );
6204
6375
  }
6205
6376
  return { result };
@@ -6223,7 +6394,11 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
6223
6394
  onLimitReached: "error"
6224
6395
  };
6225
6396
  const result = await runSelectLike(resolvedStmt.query, client, materializeOptions, cacheContext, tempTables);
6226
- tempTables.set(resolvedStmt.name, { rows: result.rows, columns: result.columns });
6397
+ tempTables.set(resolvedStmt.name, {
6398
+ rows: result.rows,
6399
+ columns: result.columns,
6400
+ columnMeta: materializedMetaBySelectResult.get(result)
6401
+ });
6227
6402
  return { tempTable: resolvedStmt.name, rowCount: result.rows.length };
6228
6403
  }
6229
6404
  if (stmt.type === "DROP_TEMP_TABLE") {
@@ -6259,9 +6434,9 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
6259
6434
  }
6260
6435
  async function runSelectLike(query, client, options, cacheContext, tempTables) {
6261
6436
  if (query.type === "WITH") {
6262
- return executeWith(query, client, options, cacheContext, tempTables);
6437
+ return executeWith(query, client, options, cacheContext, tempTables, true);
6263
6438
  }
6264
- return executeQueryWithCte(query, client, options, tempTables, cacheContext);
6439
+ return executeQueryWithCte(query, client, options, tempTables, cacheContext, true);
6265
6440
  }
6266
6441
  async function runWithDeadline(work, remainingMs) {
6267
6442
  if (remainingMs === null) return work;
@@ -6474,18 +6649,27 @@ function evalAssertArith(node) {
6474
6649
  }
6475
6650
  throw new Error(`ArgumentError: unsupported operand in ASSERT expression: ${node.type}`);
6476
6651
  }
6477
- async function executeSelect(stmt, client, options, cacheContext, cteCache) {
6652
+ async function executeSelect(stmt, client, options, cacheContext, cteCache, captureColumnMeta = false) {
6653
+ let result;
6478
6654
  if (isNoFromSelect(stmt)) {
6479
- return executeNoFromSelect(stmt);
6655
+ result = executeNoFromSelect(stmt);
6656
+ if (captureColumnMeta) {
6657
+ materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache));
6658
+ }
6659
+ return result;
6480
6660
  }
6481
6661
  await resolveSelectCaseSubqueries(stmt, client, options, cacheContext, cteCache);
6482
6662
  const mode = resolveSelectMode(stmt);
6483
6663
  await validateSelectFieldCodes(stmt, mode, client, cacheContext);
6484
6664
  if (mode === "SIMPLE") {
6485
- return executeSimpleSelect(stmt, client, options, cacheContext);
6665
+ result = await executeSimpleSelect(stmt, client, options, cacheContext);
6486
6666
  } else {
6487
- return executeFullScanSelect(stmt, client, options, cacheContext, cteCache);
6667
+ result = await executeFullScanSelect(stmt, client, options, cacheContext, cteCache);
6668
+ }
6669
+ if (captureColumnMeta) {
6670
+ materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(stmt, result.columns, client, cacheContext, cteCache));
6488
6671
  }
6672
+ return result;
6489
6673
  }
6490
6674
  function isNoFromSelect(stmt) {
6491
6675
  return stmt.from.appId === 0 && stmt.from.cteName === NO_FROM_CTE_NAME;
@@ -6521,6 +6705,11 @@ function validateNoFromColumns(stmt) {
6521
6705
  throw new Error("ArgumentError: field reference is not allowed without FROM.");
6522
6706
  }
6523
6707
  break;
6708
+ case "WINDOW_COL":
6709
+ if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
6710
+ throw new Error("ArgumentError: field reference is not allowed without FROM.");
6711
+ }
6712
+ break;
6524
6713
  default:
6525
6714
  throw new Error(`ArgumentError: ${col.type} is not supported without FROM.`);
6526
6715
  }
@@ -6531,7 +6720,8 @@ function executeNoFromSelect(stmt) {
6531
6720
  throw new Error("ArgumentError: JOIN/WHERE/GROUP BY/HAVING/ORDER BY/DISTINCT are not supported without FROM.");
6532
6721
  }
6533
6722
  validateNoFromColumns(stmt);
6534
- const { rows: projected, columns } = project([{}], stmt.columns);
6723
+ const windowed = applyWindow([{}], stmt.columns);
6724
+ const { rows: projected, columns } = project(windowed, stmt.columns);
6535
6725
  const rows = applyLimit(projected, stmt.limit, stmt.offset);
6536
6726
  return { type: "SELECT", rows, columns, rowCount: rows.length, warnings: [] };
6537
6727
  }
@@ -6809,7 +6999,7 @@ function aggregateSortKind(info) {
6809
6999
  if (info.fieldType === "NUMBER" || info.fieldType === "RECORD_NUMBER") return "number";
6810
7000
  return AGGREGATE_STRING_FIELD_TYPES.has(info.fieldType) ? "string" : void 0;
6811
7001
  }
6812
- async function loadAggregateSortKindResolver(stmt, client, cacheContext) {
7002
+ async function loadAggregateSortKindResolver(stmt, client, cacheContext, materializedTables) {
6813
7003
  const refs = collectSelectAggregateSortRefs(stmt.columns);
6814
7004
  if (refs.length === 0) return void 0;
6815
7005
  const appIds = /* @__PURE__ */ new Set();
@@ -6825,11 +7015,9 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext) {
6825
7015
  } else if (stmt.joins.length === 0) {
6826
7016
  if (stmt.from.cteName === null) appIds.add(stmt.from.appId);
6827
7017
  } else {
6828
- if ([stmt.from, ...stmt.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)) continue;
6829
7018
  for (const table of physicalTables) appIds.add(table.appId);
6830
7019
  }
6831
7020
  }
6832
- if (appIds.size === 0) return void 0;
6833
7021
  const fieldInfosByApp = new Map(
6834
7022
  await Promise.all([...appIds].map(async (appId) => {
6835
7023
  const infos = await getFieldsCached(appId, client, cacheContext);
@@ -6844,17 +7032,28 @@ async function loadAggregateSortKindResolver(stmt, client, cacheContext) {
6844
7032
  info = fieldInfosByApp.get(stmt.from.appId)?.get(ref.field);
6845
7033
  } else {
6846
7034
  const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
6847
- if (!table || table.cteName !== null) return void 0;
7035
+ if (!table) return void 0;
7036
+ if (table.cteName !== null) {
7037
+ return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field)?.sortKind;
7038
+ }
6848
7039
  info = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
6849
7040
  }
6850
7041
  } else if (stmt.joins.length === 0) {
6851
- if (stmt.from.cteName !== null) return void 0;
7042
+ if (stmt.from.cteName !== null) {
7043
+ return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field)?.sortKind;
7044
+ }
6852
7045
  info = fieldInfosByApp.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
6853
7046
  } else {
6854
- if (tables.some((table) => table.cteName !== null)) return void 0;
6855
- const matches = physicalTables.map((table) => fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field))).filter((candidate) => candidate !== void 0);
7047
+ const matches = tables.flatMap((table) => {
7048
+ if (table.cteName !== null) {
7049
+ const materialized = materializedTables?.get(table.cteName);
7050
+ return materialized?.columns.includes(ref.field) ? [materialized.columnMeta?.get(ref.field)?.sortKind] : [];
7051
+ }
7052
+ const candidate = fieldInfosByApp.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
7053
+ return candidate ? [aggregateSortKind(candidate)] : [];
7054
+ });
6856
7055
  if (matches.length !== 1) return void 0;
6857
- info = matches[0];
7056
+ return matches[0];
6858
7057
  }
6859
7058
  return info ? aggregateSortKind(info) : void 0;
6860
7059
  };
@@ -6863,6 +7062,108 @@ function fieldCodeForTypeLookup(table, field) {
6863
7062
  if (table.subtableCode && field.startsWith("_p.")) return field.slice(3);
6864
7063
  return field;
6865
7064
  }
7065
+ function materializedMetaFromFieldInfo(info) {
7066
+ return { sortKind: aggregateSortKind(info), fieldType: info.fieldType };
7067
+ }
7068
+ function selectNeedsSourceColumnMeta(stmt) {
7069
+ return stmt.columns.some(
7070
+ (column) => column.type === "FIELD" || column.type === "WILDCARD" || column.type === "PARENT_WILDCARD" || column.type === "AGGREGATE" && (column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF"
7071
+ );
7072
+ }
7073
+ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
7074
+ const physicalInfos = /* @__PURE__ */ new Map();
7075
+ if (selectNeedsSourceColumnMeta(stmt)) {
7076
+ await Promise.all(physicalSelectTables(stmt).map(async (table) => {
7077
+ if (physicalInfos.has(table.appId)) return;
7078
+ const infos = await getFieldsCached(table.appId, client, cacheContext);
7079
+ physicalInfos.set(table.appId, new Map(infos.map((info) => [info.code, info])));
7080
+ }));
7081
+ }
7082
+ const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
7083
+ const resolveField2 = (ref) => {
7084
+ if (ref.tableAlias !== null) {
7085
+ if (ref.tableAlias === "_p" && stmt.from.subtableCode && stmt.from.cteName === null) {
7086
+ const info2 = physicalInfos.get(stmt.from.appId)?.get(ref.field);
7087
+ return info2 ? materializedMetaFromFieldInfo(info2) : void 0;
7088
+ }
7089
+ const table = tables.find((candidate) => candidate.alias === ref.tableAlias);
7090
+ if (!table) return void 0;
7091
+ if (table.cteName !== null) return materializedTables?.get(table.cteName)?.columnMeta?.get(ref.field);
7092
+ const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
7093
+ return info ? materializedMetaFromFieldInfo(info) : void 0;
7094
+ }
7095
+ if (stmt.joins.length === 0) {
7096
+ if (stmt.from.cteName !== null) return materializedTables?.get(stmt.from.cteName)?.columnMeta?.get(ref.field);
7097
+ const info = physicalInfos.get(stmt.from.appId)?.get(fieldCodeForTypeLookup(stmt.from, ref.field));
7098
+ return info ? materializedMetaFromFieldInfo(info) : void 0;
7099
+ }
7100
+ const matches = tables.flatMap((table) => {
7101
+ if (table.cteName !== null) {
7102
+ const materialized = materializedTables?.get(table.cteName);
7103
+ if (!materialized?.columns.includes(ref.field)) return [];
7104
+ return [materialized.columnMeta?.get(ref.field)];
7105
+ }
7106
+ const info = physicalInfos.get(table.appId)?.get(fieldCodeForTypeLookup(table, ref.field));
7107
+ return info ? [materializedMetaFromFieldInfo(info)] : [];
7108
+ });
7109
+ return matches.length === 1 ? matches[0] : void 0;
7110
+ };
7111
+ const inferred = /* @__PURE__ */ new Map();
7112
+ const hasWildcard = stmt.columns.some((column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD");
7113
+ if (stmt.columns.length === 1 && (stmt.columns[0].type === "WILDCARD" || stmt.columns[0].type === "PARENT_WILDCARD")) {
7114
+ for (const output of outputColumns) {
7115
+ const meta = resolveField2(aggregateFieldRef(output));
7116
+ if (meta) inferred.set(output, meta);
7117
+ }
7118
+ return inferred;
7119
+ }
7120
+ if (hasWildcard) {
7121
+ for (const output of outputColumns) {
7122
+ const meta = resolveField2(aggregateFieldRef(output));
7123
+ if (meta) inferred.set(output, meta);
7124
+ }
7125
+ }
7126
+ const explicitColumns = stmt.columns.filter(
7127
+ (column) => column.type !== "WILDCARD" && column.type !== "PARENT_WILDCARD"
7128
+ );
7129
+ explicitColumns.forEach((column, index) => {
7130
+ const output = hasWildcard ? "alias" in column && column.alias ? column.alias : void 0 : outputColumns[index];
7131
+ if (!output) return;
7132
+ let meta;
7133
+ if (column.type === "FIELD") {
7134
+ meta = resolveField2(aggregateFieldRef(column.field));
7135
+ } else if (column.type === "AGGREGATE") {
7136
+ if (column.func === "GROUP_CONCAT") {
7137
+ meta = { sortKind: "string" };
7138
+ } else if (column.func === "COUNT" || column.func === "SUM" || column.func === "AVG") {
7139
+ meta = { sortKind: "number" };
7140
+ } else if ((column.func === "MIN" || column.func === "MAX") && column.arg.type === "FIELD_REF") {
7141
+ const source = resolveField2(aggregateFieldRef(column.arg.field));
7142
+ if (source?.sortKind) meta = { sortKind: source.sortKind };
7143
+ }
7144
+ } else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
7145
+ meta = { sortKind: "number" };
7146
+ } else if (column.type === "LITERAL_COL") {
7147
+ meta = { sortKind: "string" };
7148
+ } else if (column.type === "WINDOW_COL") {
7149
+ meta = { sortKind: "number" };
7150
+ }
7151
+ if (meta) inferred.set(output, meta);
7152
+ });
7153
+ return inferred;
7154
+ }
7155
+ function mergeUnionColumnMeta(left, right) {
7156
+ const leftMeta = materializedMetaBySelectResult.get(left);
7157
+ const rightMeta = materializedMetaBySelectResult.get(right);
7158
+ const merged = /* @__PURE__ */ new Map();
7159
+ left.columns.forEach((column, index) => {
7160
+ const a = leftMeta?.get(column);
7161
+ const rightColumn = right.columns[index];
7162
+ const b = rightColumn === void 0 ? void 0 : rightMeta?.get(rightColumn);
7163
+ if (a && b && a.sortKind === b.sortKind && a.fieldType === b.fieldType) merged.set(column, a);
7164
+ });
7165
+ return merged;
7166
+ }
6866
7167
  function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
6867
7168
  const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
6868
7169
  const physicalTables = tables.filter((table) => table.cteName === null);
@@ -6907,7 +7208,7 @@ async function executeFullScanSelect(stmt, client, options, cacheContext, cteCac
6907
7208
  const [pushdownMeta, typedInFieldTypes, aggregateSortKindResolver] = await Promise.all([
6908
7209
  loadTypedPushdownMeta(stmt, client, cacheContext),
6909
7210
  loadTypedInFieldTypes(stmt, client, cacheContext),
6910
- loadAggregateSortKindResolver(stmt, client, cacheContext)
7211
+ loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
6911
7212
  ]);
6912
7213
  const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
6913
7214
  const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
@@ -7027,9 +7328,9 @@ function deduplicateRows(rows, columns) {
7027
7328
  return true;
7028
7329
  });
7029
7330
  }
7030
- async function executeWith(stmt, client, options, cacheContext, seed) {
7331
+ async function executeWith(stmt, client, options, cacheContext, seed, captureColumnMeta = false) {
7031
7332
  if ((seed == null || seed.size === 0) && canInlineSingleCte(stmt)) {
7032
- return executeSelect(buildInlinedQuery(stmt), client, options, cacheContext);
7333
+ return executeSelect(buildInlinedQuery(stmt), client, options, cacheContext, void 0, captureColumnMeta);
7033
7334
  }
7034
7335
  const cteCache = new Map(seed ?? []);
7035
7336
  for (const cte of stmt.ctes) {
@@ -7039,17 +7340,21 @@ async function executeWith(stmt, client, options, cacheContext, seed) {
7039
7340
  } else if (cte.query.type === "DESCRIBE") {
7040
7341
  result = await executeDescribe(cte.query, client, cacheContext);
7041
7342
  } else {
7042
- result = await executeQueryWithCte(cte.query, client, options, cteCache, cacheContext);
7343
+ result = await executeQueryWithCte(cte.query, client, options, cteCache, cacheContext, true);
7043
7344
  }
7044
- cteCache.set(cte.name, { rows: result.rows, columns: result.columns });
7345
+ cteCache.set(cte.name, {
7346
+ rows: result.rows,
7347
+ columns: result.columns,
7348
+ columnMeta: materializedMetaBySelectResult.get(result)
7349
+ });
7045
7350
  }
7046
- return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext);
7351
+ return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext, captureColumnMeta);
7047
7352
  }
7048
- async function executeQueryWithCte(query, client, options, cteCache, cacheContext) {
7353
+ async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false) {
7049
7354
  if (query.type === "UNION") {
7050
7355
  const [leftResult, rightResult] = await Promise.all([
7051
- executeQueryWithCte(query.left, client, options, cteCache, cacheContext),
7052
- executeQueryWithCte(query.right, client, options, cteCache, cacheContext)
7356
+ executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta),
7357
+ executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta)
7053
7358
  ]);
7054
7359
  const leftCols = leftResult.columns;
7055
7360
  const rightCols = rightResult.columns;
@@ -7062,13 +7367,21 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
7062
7367
  });
7063
7368
  const combined = [...leftResult.rows, ...remapped];
7064
7369
  const rows = query.all ? combined : deduplicateRows(combined, leftCols);
7065
- return { type: "SELECT", rows, columns: leftCols, rowCount: rows.length };
7370
+ const result2 = { type: "SELECT", rows, columns: leftCols, rowCount: rows.length };
7371
+ if (captureColumnMeta) {
7372
+ materializedMetaBySelectResult.set(result2, mergeUnionColumnMeta(leftResult, rightResult));
7373
+ }
7374
+ return result2;
7066
7375
  }
7067
7376
  const hasCteRef = query.from.cteName != null && query.from.cteName !== NO_FROM_CTE_NAME || query.joins.some((j) => j.table.cteName != null);
7068
7377
  if (!hasCteRef) {
7069
- return executeSelect(query, client, options, cacheContext, cteCache);
7378
+ return executeSelect(query, client, options, cacheContext, cteCache, captureColumnMeta);
7070
7379
  }
7071
- return executeFullScanWithCte(query, client, options, cteCache, cacheContext);
7380
+ const result = await executeFullScanWithCte(query, client, options, cteCache, cacheContext);
7381
+ if (captureColumnMeta) {
7382
+ materializedMetaBySelectResult.set(result, await inferSelectColumnMeta(query, result.columns, client, cacheContext, cteCache));
7383
+ }
7384
+ return result;
7072
7385
  }
7073
7386
  async function executeFullScanWithCte(stmt, client, options, cteCache, cacheContext) {
7074
7387
  const maxRecords = options.maxRecords ?? 1e4;
@@ -7082,7 +7395,7 @@ async function executeFullScanWithCte(stmt, client, options, cteCache, cacheCont
7082
7395
  const [pushdownMeta, typedInFieldTypes, aggregateSortKindResolver] = await Promise.all([
7083
7396
  loadTypedPushdownMeta(stmt, client, cacheContext),
7084
7397
  loadTypedInFieldTypes(stmt, client, cacheContext),
7085
- loadAggregateSortKindResolver(stmt, client, cacheContext)
7398
+ loadAggregateSortKindResolver(stmt, client, cacheContext, cteCache)
7086
7399
  ]);
7087
7400
  const fieldTypeResolvers = buildSelectFieldTypeResolvers(stmt, typedInFieldTypes);
7088
7401
  const pushdownPlan = buildKlikePushdownPlan(stmt, pushdownMeta);
@@ -7419,7 +7732,10 @@ async function getSortKindMapByApp(appId, client, cacheContext) {
7419
7732
  return map;
7420
7733
  }
7421
7734
  async function buildOrderByMetaForSelect(stmt, client, cacheContext) {
7422
- if (stmt.orderBy.length === 0) {
7735
+ const hasWindowOrderBy = stmt.columns.some(
7736
+ (column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
7737
+ );
7738
+ if (stmt.orderBy.length === 0 && !hasWindowOrderBy) {
7423
7739
  return { optionOrders: /* @__PURE__ */ new Map(), sortKinds: /* @__PURE__ */ new Map() };
7424
7740
  }
7425
7741
  const [optionOrders, sortKinds] = await Promise.all([
@@ -7560,7 +7876,23 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
7560
7876
  errors,
7561
7877
  ...stmt.validationErrorTable ? { errTable: stmt.validationErrorTable } : stmt.onErrorSkip && stmt.errorTable ? { errTable: stmt.errorTable } : {}
7562
7878
  };
7563
- return { result, candidates, invalidRowNumbers };
7879
+ const columnMeta = /* @__PURE__ */ new Map();
7880
+ for (const column of payloadFields) {
7881
+ if (column === "$id") {
7882
+ columnMeta.set(column, { sortKind: "number", fieldType: "RECORD_NUMBER" });
7883
+ continue;
7884
+ }
7885
+ const info = infoByCode.get(column);
7886
+ if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info));
7887
+ }
7888
+ columnMeta.set("$err_statement", { sortKind: "number" });
7889
+ columnMeta.set("$err_operation", { sortKind: "string" });
7890
+ columnMeta.set("$err_row", { sortKind: "number" });
7891
+ columnMeta.set("$err_field", { sortKind: "string" });
7892
+ columnMeta.set("$err_code", { sortKind: "string" });
7893
+ columnMeta.set("$err_message", { sortKind: "string" });
7894
+ materializedMetaByValidationResult.set(result, columnMeta);
7895
+ return { result, candidates, invalidRowNumbers, columnMeta };
7564
7896
  }
7565
7897
  async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTables, statementNumber) {
7566
7898
  const prepared = await prepareDmlValidation(
@@ -7578,7 +7910,8 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
7578
7910
  errTable,
7579
7911
  prepared.result.columns,
7580
7912
  prepared.result.errors,
7581
- options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS
7913
+ options.tempTableMaxRows ?? TEMP_TABLE_MAX_ROWS,
7914
+ prepared.columnMeta
7582
7915
  );
7583
7916
  const rejectLimit = stmt.rejectLimit ?? null;
7584
7917
  if (rejectLimit !== null && prepared.result.invalidRows > rejectLimit) {
@@ -8864,6 +9197,8 @@ function collectFullScanReasons(stmt) {
8864
9197
  r.push("DISTINCT \u3042\u308A");
8865
9198
  if (stmt.columns.some((c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL"))
8866
9199
  r.push("\u96C6\u8A08\u95A2\u6570\uFF08COUNT / SUM \u7B49\uFF09\u3042\u308A");
9200
+ if (stmt.columns.some((c) => c.type === "WINDOW_COL"))
9201
+ r.push("\u30A6\u30A3\u30F3\u30C9\u30A6\u95A2\u6570\u3042\u308A");
8867
9202
  if (stmt.columns.some((c) => c.type === "SCALAR_SUBQUERY_COL"))
8868
9203
  r.push("SELECT \u5217\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA");
8869
9204
  if (whereRequiresJsEval(stmt.where))