@rex0220/kintone-sql-tools 3.43.0 → 3.44.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
@@ -683,6 +683,7 @@ function arithLabel(node, topLevel = false) {
683
683
  function fieldValueLabel(value) {
684
684
  if (value.type === "FIELD") return value.tableAlias ? `${value.tableAlias}.${value.field}` : value.field;
685
685
  if (value.type === "FUNC_FIELD") return stringFuncLabel(value.expr);
686
+ if (value.type === "AGG_FIELD") return aggregateOperandLabel(value.expr);
686
687
  if (value.type === "ARITH_FIELD") return arithLabel(value.expr);
687
688
  if (value.type === "GROUPING_FIELD") {
688
689
  const field = value.ref.field;
@@ -736,6 +737,8 @@ function whereLabel(expr) {
736
737
  }
737
738
  function caseResultLabel(result) {
738
739
  if (result.type === "ARRAY") return `[${result.elements.map((entry) => quote(entry.value)).join(",")}]`;
740
+ if (result.type === "AGG_REF") return aggregateSyntheticName(result.func, result.distinct, result.arg);
741
+ if (result.type === "AGG_ARITH") return aggregateOperandLabel(result);
739
742
  if (result.type === "FIELD_REF" || result.type === "ARITH") return arithLabel(result);
740
743
  return scalarValueLabel(result);
741
744
  }
@@ -2079,8 +2082,17 @@ var Parser = class {
2079
2082
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
2080
2083
  if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
2081
2084
  if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
2085
+ if (column.type === "CASE_COL") return this.nodeHasAggregate(column.expr);
2082
2086
  return false;
2083
2087
  }
2088
+ nodeHasAggregate(node) {
2089
+ if (node === null || typeof node !== "object") return false;
2090
+ if (Array.isArray(node)) return node.some((value2) => this.nodeHasAggregate(value2));
2091
+ const value = node;
2092
+ if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
2093
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
2094
+ return Object.values(value).some((child) => this.nodeHasAggregate(child));
2095
+ }
2084
2096
  stringFuncArgHasAggregate(arg) {
2085
2097
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
2086
2098
  return this.scalarValueHasAggregate(arg);
@@ -2091,11 +2103,7 @@ var Parser = class {
2091
2103
  return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
2092
2104
  }
2093
2105
  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
- });
2106
+ return this.nodeHasAggregate(expr);
2099
2107
  }
2100
2108
  return false;
2101
2109
  }
@@ -2352,9 +2360,9 @@ var Parser = class {
2352
2360
  this.expect("(" /* LPAREN */);
2353
2361
  const condition = this.parseCaseCondition(allowGroupingCondition);
2354
2362
  this.expect("," /* COMMA */);
2355
- const thenResult = this.parseCaseResult();
2363
+ const thenResult = this.parseCaseResult(allowGroupingCondition);
2356
2364
  this.expect("," /* COMMA */);
2357
- const elseResult = this.parseCaseResult();
2365
+ const elseResult = this.parseCaseResult(allowGroupingCondition);
2358
2366
  this.expect(")" /* RPAREN */);
2359
2367
  return {
2360
2368
  type: "CASE_WHEN",
@@ -2369,7 +2377,7 @@ var Parser = class {
2369
2377
  this.advance();
2370
2378
  const condition = this.parseCaseCondition(allowGroupingCondition);
2371
2379
  this.expect("THEN" /* THEN */);
2372
- const result = this.parseCaseResult();
2380
+ const result = this.parseCaseResult(allowGroupingCondition);
2373
2381
  branches.push({ condition, result });
2374
2382
  }
2375
2383
  if (branches.length === 0) {
@@ -2377,7 +2385,7 @@ var Parser = class {
2377
2385
  }
2378
2386
  let elseResult = null;
2379
2387
  if (this.consume("ELSE" /* ELSE */)) {
2380
- elseResult = this.parseCaseResult();
2388
+ elseResult = this.parseCaseResult(allowGroupingCondition);
2381
2389
  }
2382
2390
  this.expect("END" /* END */);
2383
2391
  return { type: "CASE_WHEN", branches, elseResult };
@@ -2387,7 +2395,7 @@ var Parser = class {
2387
2395
  return this.parseWhereExpr("SELECT_CASE");
2388
2396
  }
2389
2397
  /** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
2390
- parseCaseResult() {
2398
+ parseCaseResult(allowAggregateResult = false) {
2391
2399
  const tok = this.peek();
2392
2400
  if (this.insideAggregateArg > 0 && this.tryAggregateFunc() !== null) {
2393
2401
  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 +2403,10 @@ var Parser = class {
2395
2403
  if (tok.kind === "[" /* LBRACKET */) {
2396
2404
  return this.parseArrayLiteral();
2397
2405
  }
2406
+ const aggregateFunc = this.tryAggregateFunc();
2407
+ if (aggregateFunc !== null && allowAggregateResult) {
2408
+ return this.continueAggArith(this.parseAggregateRef(aggregateFunc));
2409
+ }
2398
2410
  if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
2399
2411
  return this.parseScalarValueExpr({ allowAggregateArgs: true });
2400
2412
  }
@@ -2918,8 +2930,19 @@ var Parser = class {
2918
2930
  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
2931
  }
2920
2932
  const ref = this.parseAggregateRef(aggFunc);
2933
+ if (this.isArithOp(this.peek().kind)) {
2934
+ return {
2935
+ type: "AGG_FIELD",
2936
+ expr: this.continueAggArith(ref)
2937
+ };
2938
+ }
2921
2939
  const syntheticName = aggregateSyntheticName(ref.func, ref.distinct, ref.arg);
2922
- return { type: "FIELD", tableAlias: null, field: syntheticName };
2940
+ return {
2941
+ type: "FIELD",
2942
+ tableAlias: null,
2943
+ field: syntheticName,
2944
+ ...this.groupingFieldContext === "SELECT_CASE" || this.groupingFieldContext === "HAVING" ? { aggregateRef: ref } : {}
2945
+ };
2923
2946
  }
2924
2947
  if (this.peek().kind === "CASE" /* CASE */) {
2925
2948
  const expr = this.parseCaseWhenExpr();
@@ -5118,6 +5141,9 @@ function convertField(field) {
5118
5141
  `WHERE \u53E5\u306E\u95A2\u6570\uFF08${field.expr.func}\uFF09\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093`
5119
5142
  );
5120
5143
  }
5144
+ if (field.type === "AGG_FIELD") {
5145
+ throw new KintoneQueryError("HAVING \u53E5\u306E\u96C6\u8A08\u7B97\u8853\u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093");
5146
+ }
5121
5147
  if (field.type === "ARITH_FIELD") {
5122
5148
  throw new KintoneQueryError("WHERE \u53E5\u306E\u7B97\u8853\u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093");
5123
5149
  }
@@ -5256,193 +5282,464 @@ var KintoneQueryError = class extends Error {
5256
5282
  }
5257
5283
  };
5258
5284
 
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";
5285
+ // src/engine/groupingRowMeta.ts
5286
+ var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
5287
+ var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
5288
+ function attachGroupingRowMeta(row, includedCanonicalIds) {
5289
+ Object.defineProperty(row, groupingRowMetaKey, {
5290
+ value: { includedCanonicalIds },
5291
+ enumerable: false,
5292
+ configurable: false,
5293
+ writable: false
5294
+ });
5295
+ return row;
5276
5296
  }
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
- }
5297
+ function getGroupingRowMeta(row) {
5298
+ return row[groupingRowMetaKey];
5294
5299
  }
5295
- function isFunc(fv) {
5296
- return fv.type === "FUNC_FIELD" || fv.type === "ARITH_FIELD" || fv.type === "CASE_FIELD";
5300
+ function readGroupingMembership(row) {
5301
+ return getGroupingRowMeta(row)?.includedCanonicalIds;
5297
5302
  }
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
- };
5303
+ function bindGroupingRefCanonicalId(ref, canonicalId) {
5304
+ groupingRefCanonicalIds.set(ref, canonicalId);
5323
5305
  }
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));
5306
+ function evalGroupingRef(ref, row) {
5307
+ const membership = readGroupingMembership(row);
5308
+ if (!membership) {
5309
+ throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
5328
5310
  }
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);
5311
+ const canonicalId = groupingRefCanonicalIds.get(ref);
5312
+ if (!canonicalId) {
5313
+ throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
5344
5314
  }
5345
- if (fields.size === 0) fields.add("$id");
5346
- return [...fields];
5315
+ return membership.has(canonicalId) ? "0" : "1";
5347
5316
  }
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");
5317
+
5318
+ // src/core/groupingValidation.ts
5319
+ var enforceGroupingPlanningCandidateLimits = (facts) => {
5320
+ if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
5321
+ throw new Error(
5322
+ `ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
5323
+ );
5352
5324
  }
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
- }
5325
+ if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
5326
+ throw new Error(
5327
+ `ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
5328
+ );
5371
5329
  }
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);
5385
- }
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;
5330
+ };
5331
+ function displayField(field) {
5332
+ return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
5391
5333
  }
5392
- function collectStringFuncFields(expr, out) {
5393
- for (const arg of expr.args) {
5394
- collectStringFuncArgFields(arg, out);
5395
- }
5334
+ function refFromName(name) {
5335
+ const dot = name.indexOf(".");
5336
+ return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
5396
5337
  }
5397
- function collectStringFuncArgFields(arg, out) {
5398
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5399
- collectAggOperandFields(arg, out);
5338
+ function collectGroupingRefs(node, out) {
5339
+ if (node === null || typeof node !== "object") return;
5340
+ if (Array.isArray(node)) {
5341
+ node.forEach((item) => collectGroupingRefs(item, out));
5400
5342
  return;
5401
5343
  }
5402
- collectScalarValueFields(arg, out);
5403
- }
5404
- function collectScalarValueFields(expr, out) {
5405
- if (expr.type === "FIELD") {
5406
- out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
5344
+ const value = node;
5345
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
5346
+ if (value["type"] === "GROUPING_REF") {
5347
+ out.push(value);
5407
5348
  return;
5408
5349
  }
5409
- if (expr.type === "STRING_FUNC") {
5410
- collectStringFuncFields(expr, out);
5350
+ Object.values(value).forEach((item) => collectGroupingRefs(item, out));
5351
+ }
5352
+ function collectAggregateArgumentGroupingRefs(node, out) {
5353
+ if (node === null || typeof node !== "object") return;
5354
+ if (Array.isArray(node)) {
5355
+ node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5411
5356
  return;
5412
5357
  }
5413
- if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5414
- collectScalarValueFields(expr.left, out);
5415
- collectScalarValueFields(expr.right, out);
5358
+ const value = node;
5359
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
5360
+ if (value["type"] === "AGGREGATE" || value["type"] === "AGG_REF") {
5361
+ collectGroupingRefs(value["arg"], out);
5416
5362
  return;
5417
5363
  }
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
- }
5364
+ Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5422
5365
  }
5423
- function collectCaseResultScalarFields(result, out) {
5424
- if (result.type === "ARRAY") return;
5425
- if (result.type === "FIELD_REF" || result.type === "ARITH") {
5426
- collectArithNode(result, out);
5366
+ function collectNonAggregateFieldRefs(node, out) {
5367
+ if (node === null || typeof node !== "object") return;
5368
+ if (Array.isArray(node)) {
5369
+ node.forEach((item) => collectNonAggregateFieldRefs(item, out));
5427
5370
  return;
5428
5371
  }
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);
5372
+ const value = node;
5373
+ const type = value["type"];
5374
+ if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
5375
+ if (type === "FIELD" && value["aggregateRef"] !== void 0) return;
5376
+ if (type === "FIELD" && typeof value["field"] === "string") {
5377
+ out.push({
5378
+ type: "FIELD",
5379
+ tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
5380
+ field: value["field"]
5381
+ });
5434
5382
  return;
5435
5383
  }
5436
- if (node.type === "AGG_ARITH") {
5437
- collectAggOperandFields(node.left, out);
5438
- collectAggOperandFields(node.right, out);
5384
+ if (type === "FIELD_REF" && typeof value["field"] === "string") {
5385
+ out.push(refFromName(value["field"]));
5386
+ return;
5439
5387
  }
5388
+ Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
5440
5389
  }
5441
- function collectAggregateArgFields(node, out) {
5442
- if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
5443
- else collectScalarValueFields(node, out);
5390
+ function containsAggregate2(node) {
5391
+ if (node === null || typeof node !== "object") return false;
5392
+ if (Array.isArray(node)) return node.some(containsAggregate2);
5393
+ const value = node;
5394
+ if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
5395
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
5396
+ return Object.values(value).some(containsAggregate2);
5444
5397
  }
5445
- function hasAggregateInStringFuncExpr(expr) {
5398
+ function isAggregateMaterializedAlias(column) {
5399
+ if (!("alias" in column) || column.alias === null) return false;
5400
+ if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
5401
+ if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL" || column.type === "CASE_COL") {
5402
+ return containsAggregate2(column);
5403
+ }
5404
+ return false;
5405
+ }
5406
+ function outputAliases(columns) {
5407
+ return new Set(columns.flatMap(
5408
+ (column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
5409
+ ));
5410
+ }
5411
+ function isAggregateSyntheticReference(ref) {
5412
+ return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
5413
+ }
5414
+ function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
5415
+ const resolved = resolve2(ref.field);
5416
+ if (!resolved.physical) {
5417
+ throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
5418
+ }
5419
+ if (!canonicalItems.has(resolved.canonicalId)) {
5420
+ throw new Error(
5421
+ `ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
5422
+ );
5423
+ }
5424
+ bindGroupingRefCanonicalId(ref, resolved.canonicalId);
5425
+ }
5426
+ function validateDependency(ref, resolve2, canonicalItems, context) {
5427
+ const resolved = resolve2(ref);
5428
+ if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
5429
+ throw new Error(
5430
+ `ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
5431
+ );
5432
+ }
5433
+ }
5434
+ function keyDependencies(key) {
5435
+ if (key.type === "GROUPING_KEY") return [];
5436
+ if (key.type === "FIELD_NAME") return [refFromName(key.name)];
5437
+ const refs = [];
5438
+ collectNonAggregateFieldRefs(key, refs);
5439
+ return refs;
5440
+ }
5441
+ function validateGroupingStatic(stmt) {
5442
+ const normalized = normalizeGroupingSpec(stmt);
5443
+ const groupingRefs = [];
5444
+ for (const column of stmt.columns) {
5445
+ if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
5446
+ }
5447
+ collectGroupingRefs(stmt.having, groupingRefs);
5448
+ collectGroupingRefs(stmt.orderBy, groupingRefs);
5449
+ const forbiddenGroupingRefs = [];
5450
+ collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
5451
+ collectGroupingRefs(stmt.joins, forbiddenGroupingRefs);
5452
+ collectAggregateArgumentGroupingRefs(stmt.columns, forbiddenGroupingRefs);
5453
+ collectAggregateArgumentGroupingRefs(stmt.having, forbiddenGroupingRefs);
5454
+ for (const column of stmt.columns) {
5455
+ if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
5456
+ }
5457
+ if (forbiddenGroupingRefs.length > 0) {
5458
+ throw new Error(
5459
+ "ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
5460
+ );
5461
+ }
5462
+ if (normalized.type !== "GROUPING_SETS") {
5463
+ if (groupingRefs.length > 0) {
5464
+ throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
5465
+ }
5466
+ return;
5467
+ }
5468
+ if (stmt.orderMode === "KINTONE_NATIVE") {
5469
+ throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
5470
+ }
5471
+ if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
5472
+ throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
5473
+ }
5474
+ if (stmt.columns.some(
5475
+ (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
5476
+ )) {
5477
+ throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
5478
+ }
5479
+ }
5480
+ function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
5481
+ validateGroupingStatic(stmt);
5482
+ const normalized = normalizeGroupingSpec(stmt);
5483
+ const groupingRefs = [];
5484
+ for (const column of stmt.columns) {
5485
+ if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
5486
+ }
5487
+ collectGroupingRefs(stmt.having, groupingRefs);
5488
+ collectGroupingRefs(stmt.orderBy, groupingRefs);
5489
+ if (normalized.type !== "GROUPING_SETS") {
5490
+ return null;
5491
+ }
5492
+ const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
5493
+ const canonicalItems = /* @__PURE__ */ new Set();
5494
+ const resolvedItems = [];
5495
+ for (const item of resolvedSpec.allItems) {
5496
+ const resolved = item;
5497
+ if (!resolved.physical) {
5498
+ throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
5499
+ }
5500
+ if (!canonicalItems.has(resolved.canonicalId)) {
5501
+ canonicalItems.add(resolved.canonicalId);
5502
+ resolvedItems.push(resolved);
5503
+ }
5504
+ }
5505
+ planningGuardHook({
5506
+ expandedSetCount: normalized.sets.length,
5507
+ canonicalItemCount: canonicalItems.size
5508
+ });
5509
+ for (const ref of groupingRefs) {
5510
+ validateGroupingRefMembership(ref, resolve2, canonicalItems);
5511
+ }
5512
+ const aliases = outputAliases(stmt.columns);
5513
+ for (const column of stmt.columns) {
5514
+ 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;
5515
+ const refs = [];
5516
+ if (column.type === "FIELD") refs.push(refFromName(column.field));
5517
+ else collectNonAggregateFieldRefs(column, refs);
5518
+ for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
5519
+ }
5520
+ if (stmt.having) {
5521
+ const refs = [];
5522
+ collectNonAggregateFieldRefs(stmt.having, refs);
5523
+ for (const ref of refs) {
5524
+ if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5525
+ validateDependency(ref, resolve2, canonicalItems, "HAVING");
5526
+ }
5527
+ }
5528
+ for (const order of stmt.orderBy) {
5529
+ for (const ref of keyDependencies(order.key)) {
5530
+ if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5531
+ validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
5532
+ }
5533
+ }
5534
+ const collisionKeys = /* @__PURE__ */ new Set();
5535
+ for (const item of resolvedItems) {
5536
+ collisionKeys.add(item.directKey);
5537
+ if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
5538
+ }
5539
+ for (const column of stmt.columns) {
5540
+ if (!isAggregateMaterializedAlias(column)) continue;
5541
+ const alias = "alias" in column ? column.alias : null;
5542
+ if (alias === null) continue;
5543
+ if (collisionKeys.has(alias)) {
5544
+ throw new Error(
5545
+ `ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
5546
+ );
5547
+ }
5548
+ }
5549
+ return resolvedSpec;
5550
+ }
5551
+
5552
+ // src/converter/selectToKintone.ts
5553
+ function hasWindowColumns(columns) {
5554
+ return columns.some((column) => column.type === "WINDOW_COL");
5555
+ }
5556
+ function resolveSelectMode(stmt) {
5557
+ if (stmt.from.subtableCode) return "FULL_SCAN";
5558
+ if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
5559
+ if (stmt.joins.length > 0) return "FULL_SCAN";
5560
+ if (normalizeGroupingSpec(stmt).type !== "NONE") return "FULL_SCAN";
5561
+ if (stmt.distinct) return "FULL_SCAN";
5562
+ if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
5563
+ if (stmt.columns.some(
5564
+ (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)
5565
+ )) return "FULL_SCAN";
5566
+ if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
5567
+ if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
5568
+ return "SIMPLE";
5569
+ }
5570
+ function whereRequiresJsEval(where) {
5571
+ if (where === null) return false;
5572
+ switch (where.type) {
5573
+ case "BOOLEAN":
5574
+ return true;
5575
+ case "BINARY":
5576
+ 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);
5577
+ case "NULL_CHECK":
5578
+ return isFunc(where.field);
5579
+ case "LOGICAL":
5580
+ return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
5581
+ case "NOT":
5582
+ case "GROUP":
5583
+ return whereRequiresJsEval(where.expr);
5584
+ case "EXISTS":
5585
+ return true;
5586
+ }
5587
+ }
5588
+ function isFunc(fv) {
5589
+ return fv.type === "FUNC_FIELD" || fv.type === "ARITH_FIELD" || fv.type === "CASE_FIELD";
5590
+ }
5591
+ function selectToKintoneParams(stmt) {
5592
+ const queryParts = [];
5593
+ const hasPagination = stmt.limit !== null || stmt.offset !== null;
5594
+ const shouldInjectDefaultOrder = hasPagination && stmt.orderBy.length === 0;
5595
+ if (stmt.where !== null) {
5596
+ queryParts.push(whereToKintone(stmt.where));
5597
+ }
5598
+ if (stmt.orderBy.length > 0) {
5599
+ const orderStr = stmt.orderBy.map(convertOrderBy).join(", ");
5600
+ queryParts.push(`order by ${orderStr}`);
5601
+ } else if (shouldInjectDefaultOrder) {
5602
+ queryParts.push("order by $id asc");
5603
+ }
5604
+ if (stmt.limit !== null) {
5605
+ queryParts.push(`limit ${stmt.limit}`);
5606
+ }
5607
+ if (stmt.offset !== null) {
5608
+ queryParts.push(`offset ${stmt.offset}`);
5609
+ }
5610
+ return {
5611
+ app: stmt.from.appId,
5612
+ query: queryParts.join(" "),
5613
+ fields: extractFields(stmt.columns),
5614
+ totalCount: false
5615
+ };
5616
+ }
5617
+ function selectToFetchAllParams(stmt, appId) {
5618
+ const queryParts = [];
5619
+ if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
5620
+ queryParts.push(whereToKintone(stmt.where));
5621
+ }
5622
+ return {
5623
+ app: appId,
5624
+ query: queryParts.join(" "),
5625
+ fields: []
5626
+ // 全件取得なので全フィールドを取得する
5627
+ };
5628
+ }
5629
+ function selectToFetchAllFields(stmt, targetTable, plainGroupByPlan) {
5630
+ const plan = collectRequiredFieldsByTable(stmt, plainGroupByPlan);
5631
+ const target = plan.get(targetTable);
5632
+ if (!target) return [];
5633
+ if (target.allFields) return [];
5634
+ const fields = new Set(target.fields);
5635
+ if (target.table.subtableCode) {
5636
+ fields.add(target.table.subtableCode);
5637
+ }
5638
+ if (fields.size === 0) fields.add("$id");
5639
+ return [...fields];
5640
+ }
5641
+ function convertOrderBy(item) {
5642
+ const dir = item.direction === "ASC" ? "asc" : "desc";
5643
+ if (item.key.type !== "FIELD_NAME") {
5644
+ 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");
5645
+ }
5646
+ return `${item.key.name} ${dir}`;
5647
+ }
5648
+ function extractFields(columns) {
5649
+ const hasWildcard = columns.some(
5650
+ (c) => c.type === "WILDCARD" || c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "CASE_COL" || c.type === "SCALAR_SUBQUERY_COL"
5651
+ );
5652
+ if (hasWildcard) return [];
5653
+ const fields = [];
5654
+ for (const col of columns) {
5655
+ if (col.type === "FIELD") {
5656
+ fields.push(normalizeSimpleFieldRef(col.field));
5657
+ } else if (col.type === "ARITH_COL") {
5658
+ collectArithNode(col.expr, fields);
5659
+ } else if (col.type === "STRFUNC_COL") {
5660
+ collectStringFuncFields(col.expr, fields);
5661
+ } else if (col.type === "SCALAR_VALUE_COL") {
5662
+ collectScalarValueFields(col.expr, fields);
5663
+ }
5664
+ }
5665
+ return [...new Set(fields)];
5666
+ }
5667
+ function collectArithFields(expr, out) {
5668
+ collectArithNode(expr.left, out);
5669
+ collectArithNode(expr.right, out);
5670
+ }
5671
+ function collectArithNode(node, out) {
5672
+ if (node.type === "VARIABLE") throw new Error(
5673
+ `InternalError: unresolved arithmetic variable @${node.name} reached SELECT field collection.`
5674
+ );
5675
+ if (node.type === "FIELD_REF") out.push(normalizeSimpleFieldRef(node.field));
5676
+ else if (node.type === "ARITH") collectArithFields(node, out);
5677
+ else if (node.type === "STRING_FUNC") collectStringFuncFields(node, out);
5678
+ }
5679
+ function normalizeSimpleFieldRef(field) {
5680
+ const dot = field.indexOf(".");
5681
+ if (dot <= 0) return field;
5682
+ const unqualified = field.slice(dot + 1);
5683
+ return unqualified || field;
5684
+ }
5685
+ function collectStringFuncFields(expr, out) {
5686
+ for (const arg of expr.args) {
5687
+ collectStringFuncArgFields(arg, out);
5688
+ }
5689
+ }
5690
+ function collectStringFuncArgFields(arg, out) {
5691
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5692
+ collectAggOperandFields(arg, out);
5693
+ return;
5694
+ }
5695
+ collectScalarValueFields(arg, out);
5696
+ }
5697
+ function collectScalarValueFields(expr, out) {
5698
+ if (expr.type === "FIELD") {
5699
+ out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
5700
+ return;
5701
+ }
5702
+ if (expr.type === "STRING_FUNC") {
5703
+ collectStringFuncFields(expr, out);
5704
+ return;
5705
+ }
5706
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5707
+ collectScalarValueFields(expr.left, out);
5708
+ collectScalarValueFields(expr.right, out);
5709
+ return;
5710
+ }
5711
+ if (expr.type === "CASE_WHEN") {
5712
+ for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
5713
+ if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
5714
+ }
5715
+ }
5716
+ function collectCaseResultScalarFields(result, out) {
5717
+ if (result.type === "ARRAY") return;
5718
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
5719
+ collectAggOperandFields(result, out);
5720
+ return;
5721
+ }
5722
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
5723
+ collectArithNode(result, out);
5724
+ return;
5725
+ }
5726
+ collectScalarValueFields(result, out);
5727
+ }
5728
+ function collectAggOperandFields(node, out) {
5729
+ if (node.type === "AGG_REF") {
5730
+ if (node.arg.type !== "WILDCARD") collectAggregateArgFields(node.arg, out);
5731
+ return;
5732
+ }
5733
+ if (node.type === "AGG_ARITH") {
5734
+ collectAggOperandFields(node.left, out);
5735
+ collectAggOperandFields(node.right, out);
5736
+ }
5737
+ }
5738
+ function collectAggregateArgFields(node, out) {
5739
+ if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
5740
+ else collectScalarValueFields(node, out);
5741
+ }
5742
+ function hasAggregateInStringFuncExpr(expr) {
5446
5743
  return expr.args.some((arg) => {
5447
5744
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
5448
5745
  return scalarValueHasAggregate(arg);
@@ -5459,6 +5756,7 @@ function scalarValueHasAggregate(expr) {
5459
5756
  return false;
5460
5757
  }
5461
5758
  function caseResultHasAggregate(result) {
5759
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
5462
5760
  if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
5463
5761
  return scalarValueHasAggregate(result);
5464
5762
  }
@@ -5667,6 +5965,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5667
5965
  };
5668
5966
  const walkCaseResult = (result, phase = "select") => {
5669
5967
  if (result.type === "ARRAY") return;
5968
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
5969
+ walkAgg(result, phase);
5970
+ return;
5971
+ }
5670
5972
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
5671
5973
  walkArith(result, phase);
5672
5974
  return;
@@ -5682,6 +5984,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5682
5984
  };
5683
5985
  const walkFieldValue = (fv, phase = "select") => {
5684
5986
  if (fv.type === "FIELD") {
5987
+ if (fv.aggregateRef) {
5988
+ walkAgg(fv.aggregateRef, phase);
5989
+ return;
5990
+ }
5685
5991
  addFieldRef(fv.field, fv.tableAlias, phase);
5686
5992
  return;
5687
5993
  }
@@ -5689,6 +5995,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5689
5995
  walkStringFunc(fv.expr, phase);
5690
5996
  return;
5691
5997
  }
5998
+ if (fv.type === "AGG_FIELD") {
5999
+ walkAgg(fv.expr, phase);
6000
+ return;
6001
+ }
5692
6002
  if (fv.type === "ARITH_FIELD") {
5693
6003
  walkArith(fv.expr, phase);
5694
6004
  return;
@@ -6430,483 +6740,217 @@ function validateNestedSelects(node) {
6430
6740
  if (obj.type === "SELECT") validateSelect(obj);
6431
6741
  }, true);
6432
6742
  }
6433
- function containsKlike(node) {
6434
- let found = false;
6435
- walkObjects(node, (obj) => {
6436
- if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
6437
- });
6438
- return found;
6439
- }
6440
- function containsKlikeOutsideWhereAndNestedSelects(node, allowedWhere) {
6441
- let found = false;
6442
- const visit = (value) => {
6443
- if (found || value === allowedWhere || value === null || typeof value !== "object") return;
6444
- if (Array.isArray(value)) {
6445
- for (const item of value) visit(item);
6446
- return;
6447
- }
6448
- const obj = value;
6449
- if (obj.type === "SELECT") return;
6450
- if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) {
6451
- 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);
6743
+ function containsKlike(node) {
6744
+ let found = false;
6745
+ walkObjects(node, (obj) => {
6746
+ if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
6747
+ });
6748
+ return found;
6628
6749
  }
6629
- function validateStringFunctionArities(stmt) {
6750
+ function containsKlikeOutsideWhereAndNestedSelects(node, allowedWhere) {
6751
+ let found = false;
6630
6752
  const visit = (value) => {
6631
- if (value === null || typeof value !== "object") return;
6753
+ if (found || value === allowedWhere || value === null || typeof value !== "object") return;
6632
6754
  if (Array.isArray(value)) {
6633
- value.forEach(visit);
6755
+ for (const item of value) visit(item);
6634
6756
  return;
6635
6757
  }
6636
- const node = value;
6637
- if (node.type === "STRING_FUNC") {
6638
- const expr = node;
6639
- assertStringFunctionArity(expr.func, expr.args);
6758
+ const obj = value;
6759
+ if (obj.type === "SELECT") return;
6760
+ if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) {
6761
+ found = true;
6762
+ return;
6640
6763
  }
6641
- Object.values(node).forEach(visit);
6764
+ for (const child of Object.values(obj)) visit(child);
6642
6765
  };
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";
6766
+ visit(node);
6767
+ return found;
6677
6768
  }
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
- );
6769
+ function isDescendantOf(root, target) {
6770
+ if (root === null) return false;
6771
+ if (root === target) return true;
6772
+ switch (root.type) {
6773
+ case "LOGICAL":
6774
+ return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
6775
+ case "NOT":
6776
+ case "GROUP":
6777
+ return isDescendantOf(root.expr, target);
6778
+ case "BINARY":
6779
+ case "NULL_CHECK":
6780
+ case "EXISTS":
6781
+ return false;
6782
+ case "BOOLEAN":
6783
+ return false;
6690
6784
  }
6691
- };
6692
- function displayField(field) {
6693
- return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
6694
6785
  }
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
- }
6699
- function collectGroupingRefs(node, out) {
6700
- if (node === null || typeof node !== "object") return;
6786
+ function walkWithoutNestedSelects(node, visitWhere) {
6701
6787
  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);
6788
+ for (const value of node) walkWithoutNestedSelects(value, visitWhere);
6709
6789
  return;
6710
6790
  }
6711
- Object.values(value).forEach((item) => collectGroupingRefs(item, out));
6712
- }
6713
- function collectAggregateArgumentGroupingRefs(node, out) {
6714
6791
  if (node === null || typeof node !== "object") return;
6715
- if (Array.isArray(node)) {
6716
- node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6717
- return;
6792
+ const obj = node;
6793
+ if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
6794
+ visitWhere(obj);
6718
6795
  }
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;
6796
+ for (const value of Object.values(obj)) {
6797
+ if (value !== node && isSelectObject(value)) continue;
6798
+ walkWithoutNestedSelects(value, visitWhere);
6724
6799
  }
6725
- Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6726
6800
  }
6727
- function collectNonAggregateFieldRefs(node, out) {
6728
- if (node === null || typeof node !== "object") return;
6801
+ function walkObjects(node, visit, skipRoot = false) {
6729
6802
  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"]));
6803
+ for (const value of node) walkObjects(value, visit);
6746
6804
  return;
6747
6805
  }
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
- }
6793
- }
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;
6806
+ if (node === null || typeof node !== "object") return;
6807
+ const obj = node;
6808
+ if (!skipRoot) visit(obj);
6809
+ for (const value of Object.values(obj)) walkObjects(value, visit);
6800
6810
  }
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."
6820
- );
6821
- }
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
- }
6811
+ function isSelectObject(value) {
6812
+ return value !== null && typeof value === "object" && value.type === "SELECT";
6839
6813
  }
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);
6814
+
6815
+ // src/core/primaryOrganizationDmlValidation.ts
6816
+ var PrimaryOrganizationDmlValidationError = class extends Error {
6817
+ constructor() {
6818
+ super(
6819
+ "ArgumentError: PRIMARY_ORGANIZATION() \u306F DML \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6820
+ );
6821
+ this.name = "ArgumentError";
6846
6822
  }
6847
- collectGroupingRefs(stmt.having, groupingRefs);
6848
- collectGroupingRefs(stmt.orderBy, groupingRefs);
6849
- if (normalized.type !== "GROUPING_SETS") {
6850
- return null;
6823
+ };
6824
+ function validatePrimaryOrganizationDmlStatement(stmt) {
6825
+ const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
6826
+ switch (target.type) {
6827
+ case "UPDATE":
6828
+ case "DELETE":
6829
+ case "UPSERT":
6830
+ case "UPSERT_SELECT":
6831
+ case "INSERT_SELECT":
6832
+ if (hasPrimaryOrganizationInWhere(target)) {
6833
+ throw new PrimaryOrganizationDmlValidationError();
6834
+ }
6835
+ return;
6836
+ default:
6837
+ return;
6851
6838
  }
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);
6839
+ }
6840
+ function hasPrimaryOrganizationInWhere(node) {
6841
+ let found = false;
6842
+ walkObjects2(node, (obj) => {
6843
+ if (found || !Object.prototype.hasOwnProperty.call(obj, "where")) return;
6844
+ if (containsPrimaryOrganization(obj.where)) found = true;
6845
+ });
6846
+ return found;
6847
+ }
6848
+ function containsPrimaryOrganization(node) {
6849
+ let found = false;
6850
+ walkObjects2(node, (obj) => {
6851
+ if (obj.type === "KINTONE_FUNC" && obj.name === "PRIMARY_ORGANIZATION") {
6852
+ found = true;
6863
6853
  }
6864
- }
6865
- planningGuardHook({
6866
- expandedSetCount: normalized.sets.length,
6867
- canonicalItemCount: canonicalItems.size
6868
6854
  });
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");
6855
+ return found;
6856
+ }
6857
+ function walkObjects2(node, visit) {
6858
+ if (Array.isArray(node)) {
6859
+ for (const value of node) walkObjects2(value, visit);
6860
+ return;
6879
6861
  }
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
- }
6862
+ if (node === null || typeof node !== "object") return;
6863
+ const obj = node;
6864
+ visit(obj);
6865
+ for (const value of Object.values(obj)) walkObjects2(value, visit);
6866
+ }
6867
+
6868
+ // src/core/functionArity.ts
6869
+ function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
6870
+ if (args.length >= min && args.length <= max) return;
6871
+ const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
6872
+ throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
6873
+ }
6874
+ function assertStringFunctionArity(func, args) {
6875
+ switch (func) {
6876
+ case "UPPER":
6877
+ case "LOWER":
6878
+ case "TRIM":
6879
+ case "LTRIM":
6880
+ case "RTRIM":
6881
+ case "LENGTH":
6882
+ case "LENGTH_CHAR":
6883
+ case "YEAR":
6884
+ case "MONTH":
6885
+ case "DAY":
6886
+ case "DAYOFWEEK":
6887
+ case "QUARTER":
6888
+ case "WEEK":
6889
+ case "LAST_DAY":
6890
+ case "ABS":
6891
+ case "SQRT":
6892
+ return assertArity(func, args, 1, 1);
6893
+ case "SUBSTRING":
6894
+ case "LPAD":
6895
+ case "RPAD":
6896
+ case "REGEXP_LIKE":
6897
+ case "REGEXP_SUBSTR":
6898
+ return assertArity(func, args, 2, 3);
6899
+ case "LEFT":
6900
+ case "RIGHT":
6901
+ case "INSTR":
6902
+ case "ISNULL":
6903
+ case "NULLIF":
6904
+ case "MOD":
6905
+ case "POWER":
6906
+ case "FORMAT":
6907
+ case "CAST":
6908
+ case "DATE_FORMAT":
6909
+ case "DATEDIFF":
6910
+ return assertArity(func, args, 2, 2);
6911
+ case "CONCAT":
6912
+ case "COALESCE":
6913
+ case "GREATEST":
6914
+ case "LEAST":
6915
+ return assertArity(func, args, 2);
6916
+ case "REPLACE":
6917
+ case "TRANSLATE":
6918
+ case "DATE_ADD":
6919
+ return assertArity(func, args, 3, 3);
6920
+ case "REGEXP_REPLACE":
6921
+ return assertArity(func, args, 3, 5);
6922
+ case "ROUND":
6923
+ case "FLOOR":
6924
+ case "CEIL":
6925
+ case "TRUNCATE":
6926
+ return assertArity(func, args, 1, 2);
6927
+ case "CURRENT_DATE":
6928
+ case "CURRENT_TIMESTAMP":
6929
+ return assertArity(func, args, 0, 0);
6887
6930
  }
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");
6931
+ }
6932
+
6933
+ // src/core/statementValidation.ts
6934
+ function validateStatementStatic(stmt) {
6935
+ validateStringFunctionArities(stmt);
6936
+ validatePrimaryOrganizationDmlStatement(stmt);
6937
+ validateKlikeStatement(stmt);
6938
+ }
6939
+ function validateStringFunctionArities(stmt) {
6940
+ const visit = (value) => {
6941
+ if (value === null || typeof value !== "object") return;
6942
+ if (Array.isArray(value)) {
6943
+ value.forEach(visit);
6944
+ return;
6892
6945
  }
6893
- }
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);
6898
- }
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
- );
6946
+ const node = value;
6947
+ if (node.type === "STRING_FUNC") {
6948
+ const expr = node;
6949
+ assertStringFunctionArity(expr.func, expr.args);
6907
6950
  }
6908
- }
6909
- return resolvedSpec;
6951
+ Object.values(node).forEach(visit);
6952
+ };
6953
+ visit(stmt);
6910
6954
  }
6911
6955
 
6912
6956
  // src/core/batch.ts
@@ -7985,10 +8029,32 @@ function formatWithComma(num, digits) {
7985
8029
  return decStr ? `${intFmt}.${decStr}` : intFmt;
7986
8030
  }
7987
8031
  function evalStringFuncArg(arg, row, resolveFieldType, resolveFieldSemantics2) {
7988
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
8032
+ if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
8033
+ return String(evalMaterializedAggregateOperand(arg, row));
8034
+ }
7989
8035
  if (arg.type === "NUMBER") return numberLiteralText(arg);
7990
8036
  return String(evalScalarValueExpr(arg, row, resolveFieldType, resolveFieldSemantics2));
7991
8037
  }
8038
+ function evalMaterializedAggregateOperand(node, row) {
8039
+ if (node.type === "NUMBER") return node.value;
8040
+ if (node.type === "AGG_REF") {
8041
+ return row[aggregateSyntheticName(node.func, node.distinct, node.arg)] ?? "";
8042
+ }
8043
+ const left = Number(evalMaterializedAggregateOperand(node.left, row));
8044
+ const right = Number(evalMaterializedAggregateOperand(node.right, row));
8045
+ switch (node.op) {
8046
+ case "+":
8047
+ return left + right;
8048
+ case "-":
8049
+ return left - right;
8050
+ case "*":
8051
+ return left * right;
8052
+ case "/":
8053
+ return right !== 0 ? left / right : NaN;
8054
+ case "%":
8055
+ return right !== 0 ? left % right : NaN;
8056
+ }
8057
+ }
7992
8058
  function resolveFieldRef(row, field) {
7993
8059
  const direct = row[field];
7994
8060
  if (direct !== void 0) return direct;
@@ -8083,7 +8149,7 @@ function semanticsForLeft(left, fieldType, resolveSemantics) {
8083
8149
  if (left.type === "FIELD") {
8084
8150
  return resolveSemantics?.(left) ?? (fieldType ? resolveFieldSemantics({ fieldType }) : syntheticSemantics("string"));
8085
8151
  }
8086
- if (left.type === "ARITH_FIELD") return syntheticSemantics("number");
8152
+ if (left.type === "ARITH_FIELD" || left.type === "AGG_FIELD") return syntheticSemantics("number");
8087
8153
  if (left.type === "FUNC_FIELD") {
8088
8154
  return syntheticSemantics(NUMERIC_STRING_FUNCTIONS.has(left.expr.func) ? "number" : "string");
8089
8155
  }
@@ -8176,6 +8242,7 @@ function evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSem
8176
8242
  }
8177
8243
  function resolveField(field, row, resolveFieldType, resolveFieldSemantics2) {
8178
8244
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
8245
+ if (field.type === "AGG_FIELD") return String(evalMaterializedAggregateOperand(field.expr, row));
8179
8246
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
8180
8247
  if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType, resolveFieldSemantics2);
8181
8248
  if (field.type === "GROUPING_FIELD") return evalGroupingRef(field.ref, row);
@@ -8233,12 +8300,20 @@ function evalCaseWhenNullable(expr, row, resolveFieldType, resolveFieldSemantics
8233
8300
  }
8234
8301
  function evalCaseResultNullable(result, row, resolveFieldType, resolveFieldSemantics2) {
8235
8302
  if (result.type === "ARRAY") return result.elements.map((entry) => entry.value).join(",");
8303
+ if (result.type === "AGG_REF") {
8304
+ return row[aggregateSyntheticName(result.func, result.distinct, result.arg)] ?? "";
8305
+ }
8306
+ if (result.type === "AGG_ARITH") return row[aggregateOperandLabel(result)] ?? "";
8236
8307
  if (result.type === "FIELD_REF") return row[result.field] ?? "";
8237
8308
  if (result.type === "ARITH") return evalArithExpr(result, row);
8238
8309
  return evalScalarValueExprNullable(result, row, resolveFieldType, resolveFieldSemantics2);
8239
8310
  }
8240
8311
  function evalCaseResult(result, row, resolveFieldType, resolveFieldSemantics2) {
8241
8312
  if (result.type === "ARRAY") return result.elements.map((e) => e.value).join(",");
8313
+ if (result.type === "AGG_REF") {
8314
+ return row[aggregateSyntheticName(result.func, result.distinct, result.arg)] ?? "";
8315
+ }
8316
+ if (result.type === "AGG_ARITH") return row[aggregateOperandLabel(result)] ?? "";
8242
8317
  if (result.type === "FIELD_REF") {
8243
8318
  return row[result.field] ?? "";
8244
8319
  }
@@ -8504,6 +8579,10 @@ function collectAggregateArgFields2(node, out) {
8504
8579
  }
8505
8580
  function collectCaseResultFields(result, out) {
8506
8581
  if (result.type === "ARRAY") return;
8582
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8583
+ collectAggOperandFields2(result, out);
8584
+ return;
8585
+ }
8507
8586
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
8508
8587
  collectArithNode2(result, out);
8509
8588
  return;
@@ -8725,6 +8804,9 @@ function evalCaseResultValue(result, row, fieldType) {
8725
8804
  if (result.type === "ARRAY") {
8726
8805
  return convertArray(result.elements.map((e) => e.value), fieldType);
8727
8806
  }
8807
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8808
+ throw new Error("InternalError: aggregate CASE result reached DML evaluation.");
8809
+ }
8728
8810
  if (result.type === "STRING") {
8729
8811
  return convertString2(result.value, fieldType);
8730
8812
  }
@@ -12913,7 +12995,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
12913
12995
  }
12914
12996
  function hasAggregateColumns(columns) {
12915
12997
  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)
12998
+ (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
12999
  );
12918
13000
  }
12919
13001
  function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind, resolutionPlan, aliasEvaluationContext = {}) {
@@ -13018,26 +13100,72 @@ function groupingItemValue(item, row) {
13018
13100
  return row[item.directKey] ?? (item.unqualifiedBridgeKey === null ? void 0 : row[item.unqualifiedBridgeKey]) ?? "";
13019
13101
  }
13020
13102
  function materializeAggregateColumns(outRow, groupRows, columns, resolveAggSortKind) {
13021
- for (const col of columns) {
13103
+ for (const [columnIndex, col] of columns.entries()) {
13022
13104
  if (col.type === "AGGREGATE") {
13023
13105
  const syntheticKey = aggregateSyntheticName(col.func, col.distinct, col.arg);
13024
13106
  const value = String(evalAggregate(col.func, col.distinct, col.arg, col.separator, groupRows, resolveAggSortKind));
13025
13107
  outRow[col.alias ?? syntheticKey] = value;
13026
13108
  if (col.alias) outRow[syntheticKey] = value;
13027
13109
  } else if (col.type === "ARITH_AGG_COL") {
13110
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13028
13111
  const outputKey = col.alias ?? aggArithDefaultKey(col.expr);
13029
13112
  outRow[outputKey] = String(evalAggArithExpr(col.expr, groupRows, resolveAggSortKind));
13030
13113
  } else if (col.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(col.expr)) {
13114
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13031
13115
  const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
13032
13116
  const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
13033
13117
  outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
13034
13118
  } else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
13119
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13035
13120
  const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
13036
13121
  const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
13037
13122
  outRow[outputKey] = String(evalScalarValueExpr(resolvedExpr, outRow));
13123
+ } else if (col.type === "CASE_COL" && containsAggregate2(col.expr)) {
13124
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
13125
+ const resolvedExpr = resolveAggInCaseExpr(col.expr, groupRows, resolveAggSortKind);
13126
+ const resolveAggregateSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, resolveAggSortKind) : void 0;
13127
+ outRow[caseMaterializedKey(col.alias, columnIndex)] = evalCaseWhen(
13128
+ resolvedExpr,
13129
+ outRow,
13130
+ void 0,
13131
+ resolveAggregateSemantics
13132
+ );
13038
13133
  }
13039
13134
  }
13040
13135
  }
13136
+ function caseMaterializedKey(alias, columnIndex) {
13137
+ return alias ?? `__ksql_case_column_${columnIndex}`;
13138
+ }
13139
+ function collectAggregateRefs(node, out) {
13140
+ if (node === null || typeof node !== "object") return;
13141
+ if (Array.isArray(node)) {
13142
+ node.forEach((value2) => collectAggregateRefs(value2, out));
13143
+ return;
13144
+ }
13145
+ const value = node;
13146
+ if (value["type"] === "AGG_REF") {
13147
+ out.push(value);
13148
+ return;
13149
+ }
13150
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
13151
+ Object.values(value).forEach((child) => collectAggregateRefs(child, out));
13152
+ }
13153
+ function materializeAggregateDependencies(outRow, rows, node, resolveAggSortKind) {
13154
+ const refs = [];
13155
+ collectAggregateRefs(node, refs);
13156
+ for (const ref of refs) {
13157
+ const key = aggregateSyntheticName(ref.func, ref.distinct, ref.arg);
13158
+ if (outRow[key] !== void 0) continue;
13159
+ outRow[key] = String(evalAggregate(
13160
+ ref.func,
13161
+ ref.distinct,
13162
+ ref.arg,
13163
+ ref.separator,
13164
+ rows,
13165
+ resolveAggSortKind
13166
+ ));
13167
+ }
13168
+ }
13041
13169
  function evalGroupByKey(key, row, resolution, columns, aliasEvaluationContext) {
13042
13170
  if (key.type === "FIELD_NAME") {
13043
13171
  if (!resolution) return row[key.name] ?? "";
@@ -13078,7 +13206,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
13078
13206
  const raw = row[arg.field];
13079
13207
  if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
13080
13208
  strVal = raw;
13081
- } else if (arg.type === "ARITH" || arg.type === "NUMBER" || arg.type === "STRING_FUNC") {
13209
+ } else if (arg.type === "ARITH" || arg.type === "NUMBER") {
13082
13210
  const n = evalArithExpr(arg, row);
13083
13211
  if (isNaN(n)) continue;
13084
13212
  strVal = String(n);
@@ -13210,6 +13338,16 @@ function resolveAggregateArgSemantics(arg, resolver) {
13210
13338
  const first = results[0];
13211
13339
  return results.every((result) => JSON.stringify(result) === JSON.stringify(first)) ? first : kinds[0];
13212
13340
  }
13341
+ function aggregateResultSemantics(ref, resolver) {
13342
+ 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") {
13343
+ return syntheticSemantics("number");
13344
+ }
13345
+ if (ref.func === "GROUP_CONCAT" || ref.func === "MODE") {
13346
+ return syntheticSemantics("string");
13347
+ }
13348
+ const semantics = ref.arg.type === "WILDCARD" ? "string" : resolveAggregateArgSemantics(ref.arg, resolver) ?? "string";
13349
+ return typeof semantics === "string" ? syntheticSemantics(semantics) : semantics;
13350
+ }
13213
13351
  function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
13214
13352
  if (having === null) return rows;
13215
13353
  return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
@@ -13369,7 +13507,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
13369
13507
  break;
13370
13508
  }
13371
13509
  case "CASE_COL":
13372
- evaluators.set(alias, (row) => evalCaseWhen(column.expr, row, resolveFieldType, resolveFieldSemantics2));
13510
+ evaluators.set(alias, (row) => containsAggregate2(column.expr) ? row[alias] ?? "" : evalCaseWhen(column.expr, row, resolveFieldType, resolveFieldSemantics2));
13373
13511
  break;
13374
13512
  case "SCALAR_VALUE_COL": {
13375
13513
  const source = scalarValueDefaultKey(column.expr);
@@ -13458,7 +13596,7 @@ function evaluateSelectColumnValue(column, row, columnIndex, context = {}) {
13458
13596
  case "ARITH_COL":
13459
13597
  return String(evalArithExpr(column.expr, row));
13460
13598
  case "CASE_COL":
13461
- return evalCaseWhen(
13599
+ return containsAggregate2(column.expr) ? row[caseMaterializedKey(column.alias, columnIndex)] ?? "" : evalCaseWhen(
13462
13600
  column.expr,
13463
13601
  row,
13464
13602
  context.resolveFieldType,
@@ -13523,13 +13661,14 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13523
13661
  return { rows: projected2, columns: cols };
13524
13662
  }
13525
13663
  const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
13664
+ const defaultCaseKeys = buildDefaultCaseOutputKeys(columns);
13526
13665
  const hasWildcard = columns.some(
13527
13666
  (col) => col.type === "WILDCARD" || col.type === "PARENT_WILDCARD"
13528
13667
  );
13529
- const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys);
13668
+ const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys, defaultCaseKeys);
13530
13669
  const orderedKeys = outputKeys ?? [];
13531
13670
  if (hasWildcard && rows.length === 0) {
13532
- return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys) };
13671
+ return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) };
13533
13672
  }
13534
13673
  const projected = rows.map((row, rowIdx) => {
13535
13674
  const out = {};
@@ -13596,7 +13735,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13596
13735
  break;
13597
13736
  }
13598
13737
  case "CASE_COL": {
13599
- const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
13738
+ const key = outputKeys?.[colIdx] ?? col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13600
13739
  out[key] = value;
13601
13740
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
13602
13741
  break;
@@ -13637,15 +13776,15 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13637
13776
  });
13638
13777
  return { rows: projected, columns: orderedKeys };
13639
13778
  }
13640
- function computeOutputKeys(columns, defaultFieldKeys) {
13641
- return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys));
13779
+ function computeOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) {
13780
+ return columns.map((col, colIdx) => computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys));
13642
13781
  }
13643
- function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13782
+ function computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) {
13644
13783
  const keys = [];
13645
13784
  const seen = /* @__PURE__ */ new Set();
13646
13785
  for (const [colIdx, col] of columns.entries()) {
13647
13786
  if (col.type === "WILDCARD" || col.type === "PARENT_WILDCARD") continue;
13648
- const key = computeOutputKey(col, colIdx, defaultFieldKeys);
13787
+ const key = computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys);
13649
13788
  if (!seen.has(key)) {
13650
13789
  seen.add(key);
13651
13790
  keys.push(key);
@@ -13653,7 +13792,7 @@ function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13653
13792
  }
13654
13793
  return keys;
13655
13794
  }
13656
- function computeOutputKey(col, colIdx, defaultFieldKeys) {
13795
+ function computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys) {
13657
13796
  switch (col.type) {
13658
13797
  case "VARIABLE_COL":
13659
13798
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
@@ -13668,7 +13807,7 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13668
13807
  case "ARITH_COL":
13669
13808
  return col.alias ?? arithColDefaultKey(col.expr);
13670
13809
  case "CASE_COL":
13671
- return col.alias ?? "case";
13810
+ return col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13672
13811
  case "STRFUNC_COL":
13673
13812
  return col.alias ?? stringFuncDefaultKey(col.expr);
13674
13813
  case "SCALAR_VALUE_COL":
@@ -13684,6 +13823,24 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13684
13823
  throw new Error("internal: computeOutputKey received a wildcard column");
13685
13824
  }
13686
13825
  }
13826
+ function buildDefaultCaseOutputKeys(columns) {
13827
+ const used = new Set(columns.flatMap(
13828
+ (column) => "alias" in column && column.alias !== null ? [column.alias] : []
13829
+ ));
13830
+ const keys = /* @__PURE__ */ new Map();
13831
+ let suffix = 1;
13832
+ for (const [columnIndex, column] of columns.entries()) {
13833
+ if (column.type !== "CASE_COL" || column.alias !== null) continue;
13834
+ let key;
13835
+ do {
13836
+ key = suffix === 1 ? "case" : `case_${suffix}`;
13837
+ suffix++;
13838
+ } while (used.has(key));
13839
+ used.add(key);
13840
+ keys.set(columnIndex, key);
13841
+ }
13842
+ return keys;
13843
+ }
13687
13844
  function buildDefaultFieldOutputKeys(columns) {
13688
13845
  const qualifierCollisionCount = /* @__PURE__ */ new Map();
13689
13846
  for (const col of columns) {
@@ -13773,6 +13930,7 @@ function scalarValueHasAggregate2(expr) {
13773
13930
  return false;
13774
13931
  }
13775
13932
  function caseResultHasAggregate2(result) {
13933
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
13776
13934
  if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
13777
13935
  return scalarValueHasAggregate2(result);
13778
13936
  }
@@ -13795,6 +13953,7 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
13795
13953
  }
13796
13954
  function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13797
13955
  if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
13956
+ if (expr.type === "CASE_WHEN") return resolveAggInCaseExpr(expr, rows, resolveAggSortKind);
13798
13957
  if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
13799
13958
  return {
13800
13959
  ...expr,
@@ -13804,6 +13963,35 @@ function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13804
13963
  }
13805
13964
  return expr;
13806
13965
  }
13966
+ function resolveAggInCaseResult(result, rows, resolveAggSortKind) {
13967
+ if (result.type === "AGG_REF") {
13968
+ const value = evalAggregate(
13969
+ result.func,
13970
+ result.distinct,
13971
+ result.arg,
13972
+ result.separator,
13973
+ rows,
13974
+ resolveAggSortKind
13975
+ );
13976
+ return typeof value === "number" ? { type: "NUMBER", value, raw: String(value) } : { type: "STRING", value };
13977
+ }
13978
+ if (result.type === "AGG_ARITH") {
13979
+ const value = evalAggArithExpr(result, rows, resolveAggSortKind);
13980
+ return { type: "NUMBER", value, raw: String(value) };
13981
+ }
13982
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return result;
13983
+ return resolveAggInScalarValue(result, rows, resolveAggSortKind);
13984
+ }
13985
+ function resolveAggInCaseExpr(expr, rows, resolveAggSortKind) {
13986
+ return {
13987
+ ...expr,
13988
+ branches: expr.branches.map((branch) => ({
13989
+ ...branch,
13990
+ result: resolveAggInCaseResult(branch.result, rows, resolveAggSortKind)
13991
+ })),
13992
+ elseResult: expr.elseResult === null ? null : resolveAggInCaseResult(expr.elseResult, rows, resolveAggSortKind)
13993
+ };
13994
+ }
13807
13995
  function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
13808
13996
  return {
13809
13997
  type: "STRING_FUNC",
@@ -13926,7 +14114,8 @@ function runFullScan(input) {
13926
14114
  }
13927
14115
  );
13928
14116
  }
13929
- rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, havingFieldSemanticsResolver);
14117
+ const resolveHavingSemantics = (field) => field.aggregateRef ? aggregateResultSemantics(field.aggregateRef, aggregateSortKindResolver) : havingFieldSemanticsResolver?.(field);
14118
+ rows = applyHaving(rows, stmt.having, havingFieldTypeResolver, resolveHavingSemantics);
13930
14119
  rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
13931
14120
  if (stmt.distinct) {
13932
14121
  rows = applyDistinct(
@@ -17468,7 +17657,7 @@ function scalarValueHasFieldRef(expr) {
17468
17657
  }
17469
17658
  if (expr.type === "CASE_WHEN") {
17470
17659
  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)));
17660
+ 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
17661
  }
17473
17662
  return false;
17474
17663
  }
@@ -18020,7 +18209,8 @@ function collectAggregateArgFieldRefs(arg, out) {
18020
18209
  }
18021
18210
  if (arg.type === "CASE_WHEN") {
18022
18211
  for (const result of [...arg.branches.map((branch) => branch.result), ...arg.elseResult ? [arg.elseResult] : []]) {
18023
- if (result.type !== "ARRAY") collectAggregateArgFieldRefs(result, out);
18212
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") collectAggregateOperandRefs(result, out);
18213
+ else if (result.type !== "ARRAY") collectAggregateArgFieldRefs(result, out);
18024
18214
  }
18025
18215
  }
18026
18216
  }
@@ -18057,10 +18247,29 @@ function collectScalarAggregateRefs(expr, out) {
18057
18247
  const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
18058
18248
  for (const result of results) {
18059
18249
  if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
18250
+ else if (result.type === "AGG_REF" || result.type === "AGG_ARITH") collectAggregateOperandRefs(result, out);
18060
18251
  else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
18061
18252
  }
18062
18253
  }
18063
18254
  }
18255
+ function collectCaseAggregateRefs(expr, out) {
18256
+ const visit = (node) => {
18257
+ if (node === null || typeof node !== "object") return;
18258
+ if (Array.isArray(node)) {
18259
+ node.forEach(visit);
18260
+ return;
18261
+ }
18262
+ const value = node;
18263
+ if (value["type"] === "AGG_REF") {
18264
+ const aggregate = value;
18265
+ collectAggregateRef(aggregate.func, aggregate.arg, out);
18266
+ return;
18267
+ }
18268
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
18269
+ Object.values(value).forEach(visit);
18270
+ };
18271
+ visit(expr);
18272
+ }
18064
18273
  function collectSelectAggregateSortRefs(columns) {
18065
18274
  const refs = [];
18066
18275
  for (const column of columns) {
@@ -18072,6 +18281,8 @@ function collectSelectAggregateSortRefs(columns) {
18072
18281
  collectStringFuncAggregateRefs(column.expr, refs);
18073
18282
  } else if (column.type === "SCALAR_VALUE_COL") {
18074
18283
  collectScalarAggregateRefs(column.expr, refs);
18284
+ } else if (column.type === "CASE_COL") {
18285
+ collectCaseAggregateRefs(column.expr, refs);
18075
18286
  }
18076
18287
  }
18077
18288
  return refs;
@@ -18249,6 +18460,13 @@ function stringFunctionColumnMeta(expr) {
18249
18460
  function caseResultColumnMeta(result, resolveField2) {
18250
18461
  if (result.type === "STRING") return syntheticColumnMeta("string");
18251
18462
  if (result.type === "ARRAY") return unsupportedColumnMeta();
18463
+ if (result.type === "AGG_REF") {
18464
+ if (result.func === "MIN" || result.func === "MAX" || result.func === "MODE") {
18465
+ return result.arg.type === "WILDCARD" ? unknownStringColumnMeta() : inferAggregateArgMeta(result.arg, resolveField2);
18466
+ }
18467
+ return result.func === "GROUP_CONCAT" ? syntheticColumnMeta("string") : syntheticColumnMeta("number");
18468
+ }
18469
+ if (result.type === "AGG_ARITH") return syntheticColumnMeta("number");
18252
18470
  if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
18253
18471
  if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
18254
18472
  if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();