@rex0220/kintone-sql-tools 3.42.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
  }
@@ -1038,8 +1041,9 @@ function needsSpaceBetween(prev, cur) {
1038
1041
  return true;
1039
1042
  }
1040
1043
  var ParseError = class extends Error {
1041
- constructor(message, token) {
1042
- super(`${message}\uFF08\u4F4D\u7F6E ${token.pos}\u3001\u30C8\u30FC\u30AF\u30F3: \u300C${token.value}\u300D\uFF09`);
1044
+ constructor(rawMessage, token) {
1045
+ super(`${rawMessage}\uFF08\u4F4D\u7F6E ${token.pos}\u3001\u30C8\u30FC\u30AF\u30F3: \u300C${token.value}\u300D\uFF09`);
1046
+ this.rawMessage = rawMessage;
1043
1047
  this.token = token;
1044
1048
  this.name = "ParseError";
1045
1049
  }
@@ -2078,8 +2082,17 @@ var Parser = class {
2078
2082
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
2079
2083
  if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
2080
2084
  if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
2085
+ if (column.type === "CASE_COL") return this.nodeHasAggregate(column.expr);
2081
2086
  return false;
2082
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
+ }
2083
2096
  stringFuncArgHasAggregate(arg) {
2084
2097
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
2085
2098
  return this.scalarValueHasAggregate(arg);
@@ -2090,11 +2103,7 @@ var Parser = class {
2090
2103
  return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
2091
2104
  }
2092
2105
  if (expr.type === "CASE_WHEN") {
2093
- const results = [...expr.branches.map((b) => b.result), ...expr.elseResult ? [expr.elseResult] : []];
2094
- return results.some((result) => {
2095
- if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
2096
- return this.scalarValueHasAggregate(result);
2097
- });
2106
+ return this.nodeHasAggregate(expr);
2098
2107
  }
2099
2108
  return false;
2100
2109
  }
@@ -2351,9 +2360,9 @@ var Parser = class {
2351
2360
  this.expect("(" /* LPAREN */);
2352
2361
  const condition = this.parseCaseCondition(allowGroupingCondition);
2353
2362
  this.expect("," /* COMMA */);
2354
- const thenResult = this.parseCaseResult();
2363
+ const thenResult = this.parseCaseResult(allowGroupingCondition);
2355
2364
  this.expect("," /* COMMA */);
2356
- const elseResult = this.parseCaseResult();
2365
+ const elseResult = this.parseCaseResult(allowGroupingCondition);
2357
2366
  this.expect(")" /* RPAREN */);
2358
2367
  return {
2359
2368
  type: "CASE_WHEN",
@@ -2368,7 +2377,7 @@ var Parser = class {
2368
2377
  this.advance();
2369
2378
  const condition = this.parseCaseCondition(allowGroupingCondition);
2370
2379
  this.expect("THEN" /* THEN */);
2371
- const result = this.parseCaseResult();
2380
+ const result = this.parseCaseResult(allowGroupingCondition);
2372
2381
  branches.push({ condition, result });
2373
2382
  }
2374
2383
  if (branches.length === 0) {
@@ -2376,7 +2385,7 @@ var Parser = class {
2376
2385
  }
2377
2386
  let elseResult = null;
2378
2387
  if (this.consume("ELSE" /* ELSE */)) {
2379
- elseResult = this.parseCaseResult();
2388
+ elseResult = this.parseCaseResult(allowGroupingCondition);
2380
2389
  }
2381
2390
  this.expect("END" /* END */);
2382
2391
  return { type: "CASE_WHEN", branches, elseResult };
@@ -2386,7 +2395,7 @@ var Parser = class {
2386
2395
  return this.parseWhereExpr("SELECT_CASE");
2387
2396
  }
2388
2397
  /** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
2389
- parseCaseResult() {
2398
+ parseCaseResult(allowAggregateResult = false) {
2390
2399
  const tok = this.peek();
2391
2400
  if (this.insideAggregateArg > 0 && this.tryAggregateFunc() !== null) {
2392
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);
@@ -2394,6 +2403,10 @@ var Parser = class {
2394
2403
  if (tok.kind === "[" /* LBRACKET */) {
2395
2404
  return this.parseArrayLiteral();
2396
2405
  }
2406
+ const aggregateFunc = this.tryAggregateFunc();
2407
+ if (aggregateFunc !== null && allowAggregateResult) {
2408
+ return this.continueAggArith(this.parseAggregateRef(aggregateFunc));
2409
+ }
2397
2410
  if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
2398
2411
  return this.parseScalarValueExpr({ allowAggregateArgs: true });
2399
2412
  }
@@ -2425,16 +2438,33 @@ var Parser = class {
2425
2438
  const byKind = PARSER_SCALAR_FUNCTION_TOKEN_MAP[this.peek().kind] ?? null;
2426
2439
  if (byKind !== null && byKind !== "LEFT" && byKind !== "RIGHT") return byKind;
2427
2440
  if (this.peek().kind === "IDENT" /* IDENT */) {
2428
- const name = this.peek().value.toUpperCase();
2441
+ const nameToken = this.peek();
2442
+ const name = nameToken.value.toUpperCase();
2429
2443
  if (PARSER_IDENT_SCALAR_FUNCTIONS.includes(name)) {
2430
2444
  if (this.peekAt(1).kind === "(" /* LPAREN */) {
2431
2445
  return name;
2432
2446
  }
2433
2447
  }
2448
+ if (this.peekAt(1).kind === "(" /* LPAREN */) {
2449
+ const hint = name === "DATE_SUB" ? "\u3002\u65E5\u4ED8\u3092\u6E1B\u7B97\u3059\u308B\u306B\u306F DATE_ADD \u306E\u52A0\u7B97\u5024\u3078\u8CA0\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044" : "";
2450
+ throw new ParseError(`\u300C${nameToken.value}\u300D\u3068\u3044\u3046\u95A2\u6570\u306F\u3042\u308A\u307E\u305B\u3093${hint}`, nameToken);
2451
+ }
2434
2452
  }
2435
2453
  return null;
2436
2454
  }
2437
2455
  parseStringFuncExpr() {
2456
+ const nameToken = this.peek();
2457
+ const func = this.tryStringFuncName();
2458
+ try {
2459
+ return this.parseStringFuncExprBody();
2460
+ } catch (error) {
2461
+ if (!(error instanceof ParseError)) throw error;
2462
+ const displayName = nameToken.value.toUpperCase();
2463
+ const guidance = func === "DATE_ADD" ? `${displayName} \u306E\u69CB\u6587\u306F DATE_ADD(\u5217, n, '\u5358\u4F4D') \u3067\u3059\u3002` : `${displayName} \u306E\u5F15\u6570\u69CB\u6587\u304C\u4E0D\u6B63\u3067\u3059\u3002`;
2464
+ throw new ParseError(`${guidance}${error.rawMessage}`, error.token);
2465
+ }
2466
+ }
2467
+ parseStringFuncExprBody() {
2438
2468
  const tokenKind = this.peek().kind;
2439
2469
  const func = this.tryStringFuncName();
2440
2470
  this.advance();
@@ -2900,8 +2930,19 @@ var Parser = class {
2900
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());
2901
2931
  }
2902
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
+ }
2903
2939
  const syntheticName = aggregateSyntheticName(ref.func, ref.distinct, ref.arg);
2904
- 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
+ };
2905
2946
  }
2906
2947
  if (this.peek().kind === "CASE" /* CASE */) {
2907
2948
  const expr = this.parseCaseWhenExpr();
@@ -5100,6 +5141,9 @@ function convertField(field) {
5100
5141
  `WHERE \u53E5\u306E\u95A2\u6570\uFF08${field.expr.func}\uFF09\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093`
5101
5142
  );
5102
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
+ }
5103
5147
  if (field.type === "ARITH_FIELD") {
5104
5148
  throw new KintoneQueryError("WHERE \u53E5\u306E\u7B97\u8853\u5F0F\u306F kintone \u30AF\u30A8\u30EA\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093");
5105
5149
  }
@@ -5238,193 +5282,464 @@ var KintoneQueryError = class extends Error {
5238
5282
  }
5239
5283
  };
5240
5284
 
5241
- // src/converter/selectToKintone.ts
5242
- function hasWindowColumns(columns) {
5243
- return columns.some((column) => column.type === "WINDOW_COL");
5244
- }
5245
- function resolveSelectMode(stmt) {
5246
- if (stmt.from.subtableCode) return "FULL_SCAN";
5247
- if (stmt.joins.some((j) => j.table.subtableCode)) return "FULL_SCAN";
5248
- if (stmt.joins.length > 0) return "FULL_SCAN";
5249
- if (normalizeGroupingSpec(stmt).type !== "NONE") return "FULL_SCAN";
5250
- if (stmt.distinct) return "FULL_SCAN";
5251
- if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
5252
- if (stmt.columns.some(
5253
- (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)
5254
- )) return "FULL_SCAN";
5255
- if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
5256
- if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
5257
- 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;
5258
5296
  }
5259
- function whereRequiresJsEval(where) {
5260
- if (where === null) return false;
5261
- switch (where.type) {
5262
- case "BOOLEAN":
5263
- return true;
5264
- case "BINARY":
5265
- 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);
5266
- case "NULL_CHECK":
5267
- return isFunc(where.field);
5268
- case "LOGICAL":
5269
- return whereRequiresJsEval(where.left) || whereRequiresJsEval(where.right);
5270
- case "NOT":
5271
- case "GROUP":
5272
- return whereRequiresJsEval(where.expr);
5273
- case "EXISTS":
5274
- return true;
5275
- }
5297
+ function getGroupingRowMeta(row) {
5298
+ return row[groupingRowMetaKey];
5276
5299
  }
5277
- function isFunc(fv) {
5278
- return fv.type === "FUNC_FIELD" || fv.type === "ARITH_FIELD" || fv.type === "CASE_FIELD";
5300
+ function readGroupingMembership(row) {
5301
+ return getGroupingRowMeta(row)?.includedCanonicalIds;
5279
5302
  }
5280
- function selectToKintoneParams(stmt) {
5281
- const queryParts = [];
5282
- const hasPagination = stmt.limit !== null || stmt.offset !== null;
5283
- const shouldInjectDefaultOrder = hasPagination && stmt.orderBy.length === 0;
5284
- if (stmt.where !== null) {
5285
- queryParts.push(whereToKintone(stmt.where));
5286
- }
5287
- if (stmt.orderBy.length > 0) {
5288
- const orderStr = stmt.orderBy.map(convertOrderBy).join(", ");
5289
- queryParts.push(`order by ${orderStr}`);
5290
- } else if (shouldInjectDefaultOrder) {
5291
- queryParts.push("order by $id asc");
5292
- }
5293
- if (stmt.limit !== null) {
5294
- queryParts.push(`limit ${stmt.limit}`);
5295
- }
5296
- if (stmt.offset !== null) {
5297
- queryParts.push(`offset ${stmt.offset}`);
5298
- }
5299
- return {
5300
- app: stmt.from.appId,
5301
- query: queryParts.join(" "),
5302
- fields: extractFields(stmt.columns),
5303
- totalCount: false
5304
- };
5303
+ function bindGroupingRefCanonicalId(ref, canonicalId) {
5304
+ groupingRefCanonicalIds.set(ref, canonicalId);
5305
5305
  }
5306
- function selectToFetchAllParams(stmt, appId) {
5307
- const queryParts = [];
5308
- if (stmt.where !== null && stmt.joins.length === 0 && !whereRequiresJsEval(stmt.where)) {
5309
- 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.");
5310
5310
  }
5311
- return {
5312
- app: appId,
5313
- query: queryParts.join(" "),
5314
- fields: []
5315
- // 全件取得なので全フィールドを取得する
5316
- };
5317
- }
5318
- function selectToFetchAllFields(stmt, targetTable, plainGroupByPlan) {
5319
- const plan = collectRequiredFieldsByTable(stmt, plainGroupByPlan);
5320
- const target = plan.get(targetTable);
5321
- if (!target) return [];
5322
- if (target.allFields) return [];
5323
- const fields = new Set(target.fields);
5324
- if (target.table.subtableCode) {
5325
- 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.");
5326
5314
  }
5327
- if (fields.size === 0) fields.add("$id");
5328
- return [...fields];
5315
+ return membership.has(canonicalId) ? "0" : "1";
5329
5316
  }
5330
- function convertOrderBy(item) {
5331
- const dir = item.direction === "ASC" ? "asc" : "desc";
5332
- if (item.key.type !== "FIELD_NAME") {
5333
- 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
+ );
5334
5324
  }
5335
- return `${item.key.name} ${dir}`;
5336
- }
5337
- function extractFields(columns) {
5338
- const hasWildcard = columns.some(
5339
- (c) => c.type === "WILDCARD" || c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "CASE_COL" || c.type === "SCALAR_SUBQUERY_COL"
5340
- );
5341
- if (hasWildcard) return [];
5342
- const fields = [];
5343
- for (const col of columns) {
5344
- if (col.type === "FIELD") {
5345
- fields.push(normalizeSimpleFieldRef(col.field));
5346
- } else if (col.type === "ARITH_COL") {
5347
- collectArithNode(col.expr, fields);
5348
- } else if (col.type === "STRFUNC_COL") {
5349
- collectStringFuncFields(col.expr, fields);
5350
- } else if (col.type === "SCALAR_VALUE_COL") {
5351
- collectScalarValueFields(col.expr, fields);
5352
- }
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
+ );
5353
5329
  }
5354
- return [...new Set(fields)];
5355
- }
5356
- function collectArithFields(expr, out) {
5357
- collectArithNode(expr.left, out);
5358
- collectArithNode(expr.right, out);
5359
- }
5360
- function collectArithNode(node, out) {
5361
- if (node.type === "VARIABLE") throw new Error(
5362
- `InternalError: unresolved arithmetic variable @${node.name} reached SELECT field collection.`
5363
- );
5364
- if (node.type === "FIELD_REF") out.push(normalizeSimpleFieldRef(node.field));
5365
- else if (node.type === "ARITH") collectArithFields(node, out);
5366
- else if (node.type === "STRING_FUNC") collectStringFuncFields(node, out);
5367
- }
5368
- function normalizeSimpleFieldRef(field) {
5369
- const dot = field.indexOf(".");
5370
- if (dot <= 0) return field;
5371
- const unqualified = field.slice(dot + 1);
5372
- return unqualified || field;
5330
+ };
5331
+ function displayField(field) {
5332
+ return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
5373
5333
  }
5374
- function collectStringFuncFields(expr, out) {
5375
- for (const arg of expr.args) {
5376
- collectStringFuncArgFields(arg, out);
5377
- }
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 };
5378
5337
  }
5379
- function collectStringFuncArgFields(arg, out) {
5380
- if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5381
- 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));
5382
5342
  return;
5383
5343
  }
5384
- collectScalarValueFields(arg, out);
5385
- }
5386
- function collectScalarValueFields(expr, out) {
5387
- if (expr.type === "FIELD") {
5388
- 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);
5389
5348
  return;
5390
5349
  }
5391
- if (expr.type === "STRING_FUNC") {
5392
- 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));
5393
5356
  return;
5394
5357
  }
5395
- if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5396
- collectScalarValueFields(expr.left, out);
5397
- 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);
5398
5362
  return;
5399
5363
  }
5400
- if (expr.type === "CASE_WHEN") {
5401
- for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
5402
- if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
5403
- }
5364
+ Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5404
5365
  }
5405
- function collectCaseResultScalarFields(result, out) {
5406
- if (result.type === "ARRAY") return;
5407
- if (result.type === "FIELD_REF" || result.type === "ARITH") {
5408
- 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));
5409
5370
  return;
5410
5371
  }
5411
- collectScalarValueFields(result, out);
5412
- }
5413
- function collectAggOperandFields(node, out) {
5414
- if (node.type === "AGG_REF") {
5415
- 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
+ });
5416
5382
  return;
5417
5383
  }
5418
- if (node.type === "AGG_ARITH") {
5419
- collectAggOperandFields(node.left, out);
5420
- collectAggOperandFields(node.right, out);
5384
+ if (type === "FIELD_REF" && typeof value["field"] === "string") {
5385
+ out.push(refFromName(value["field"]));
5386
+ return;
5421
5387
  }
5388
+ Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
5422
5389
  }
5423
- function collectAggregateArgFields(node, out) {
5424
- if (node.type === "FIELD_REF" || node.type === "ARITH") collectArithNode(node, out);
5425
- else collectScalarValueFields(node, out);
5426
- }
5427
- function hasAggregateInStringFuncExpr(expr) {
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);
5397
+ }
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) {
5428
5743
  return expr.args.some((arg) => {
5429
5744
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
5430
5745
  return scalarValueHasAggregate(arg);
@@ -5441,6 +5756,7 @@ function scalarValueHasAggregate(expr) {
5441
5756
  return false;
5442
5757
  }
5443
5758
  function caseResultHasAggregate(result) {
5759
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
5444
5760
  if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
5445
5761
  return scalarValueHasAggregate(result);
5446
5762
  }
@@ -5649,6 +5965,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5649
5965
  };
5650
5966
  const walkCaseResult = (result, phase = "select") => {
5651
5967
  if (result.type === "ARRAY") return;
5968
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
5969
+ walkAgg(result, phase);
5970
+ return;
5971
+ }
5652
5972
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
5653
5973
  walkArith(result, phase);
5654
5974
  return;
@@ -5664,6 +5984,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5664
5984
  };
5665
5985
  const walkFieldValue = (fv, phase = "select") => {
5666
5986
  if (fv.type === "FIELD") {
5987
+ if (fv.aggregateRef) {
5988
+ walkAgg(fv.aggregateRef, phase);
5989
+ return;
5990
+ }
5667
5991
  addFieldRef(fv.field, fv.tableAlias, phase);
5668
5992
  return;
5669
5993
  }
@@ -5671,6 +5995,10 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
5671
5995
  walkStringFunc(fv.expr, phase);
5672
5996
  return;
5673
5997
  }
5998
+ if (fv.type === "AGG_FIELD") {
5999
+ walkAgg(fv.expr, phase);
6000
+ return;
6001
+ }
5674
6002
  if (fv.type === "ARITH_FIELD") {
5675
6003
  walkArith(fv.expr, phase);
5676
6004
  return;
@@ -6182,631 +6510,447 @@ function collectExactServerFunctionLeaves(where) {
6182
6510
  }
6183
6511
  return;
6184
6512
  case "LOGICAL":
6185
- visit(node.left);
6186
- visit(node.right);
6187
- return;
6188
- case "NOT":
6189
- case "GROUP":
6190
- visit(node.expr);
6191
- return;
6192
- case "EXISTS":
6193
- case "NULL_CHECK":
6194
- case "BOOLEAN":
6195
- return;
6196
- }
6197
- };
6198
- visit(where);
6199
- return leaves;
6200
- }
6201
- function sameOccurrenceList(actual, expected) {
6202
- return actual.length === expected.length && actual.every((name, index) => name === expected[index]);
6203
- }
6204
- function serializedMultisetContains(query, expectedNames) {
6205
- const expected = /* @__PURE__ */ new Map();
6206
- for (const name of expectedNames) {
6207
- if (!isServerOnlyWhereFunctionName(name)) return false;
6208
- expected.set(name, (expected.get(name) ?? 0) + 1);
6209
- }
6210
- for (const [name, count] of expected) {
6211
- const matches = query.match(new RegExp(`\\b${name}\\s*\\(`, "g"));
6212
- if ((matches?.length ?? 0) < count) return false;
6213
- }
6214
- return true;
6215
- }
6216
-
6217
- // src/core/klikeValidation.ts
6218
- var KlikeValidationError = class extends Error {
6219
- constructor(message) {
6220
- super(`ArgumentError: ${message}`);
6221
- this.name = "ArgumentError";
6222
- }
6223
- };
6224
- function validateKlikeStatement(stmt) {
6225
- validateStatement(stmt);
6226
- }
6227
- function validateKlikePushdownPlan(plan) {
6228
- if (unappliedKlikes(plan).length > 0) {
6229
- throw new KlikeValidationError(
6230
- "FULL_SCAN \u306E KLIKE / NOT KLIKE \u3092\u5B89\u5168\u306B\u62BC\u3057\u4E0B\u3052\u3089\u308C\u307E\u305B\u3093\u3002OR / NOT \u914D\u4E0B\u3001CTE\u30FB\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3001LEFT / RIGHT JOIN \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044"
6231
- );
6232
- }
6233
- }
6234
- function validateStatement(stmt) {
6235
- switch (stmt.type) {
6236
- case "SELECT":
6237
- validateSelect(stmt);
6238
- return;
6239
- case "UNION":
6240
- validateUnion(stmt);
6241
- return;
6242
- case "WITH":
6243
- validateWith(stmt);
6244
- return;
6245
- case "EXPLAIN":
6246
- validateStatement(stmt.query);
6247
- return;
6248
- case "CREATE_TEMP_TABLE":
6249
- validateSelectLike(stmt.query);
6250
- return;
6251
- case "SET_VARIABLE":
6252
- case "DECLARE_VARIABLE":
6253
- case "ASSERT":
6254
- validateNestedSelects(stmt);
6255
- return;
6256
- case "UPDATE":
6257
- if (stmt.applyBlocks?.length && !isSinglePositiveRecordIdWhere(stmt.where) && whereHasKlike(stmt.where)) {
6258
- validateKlikeWhereExpressions(stmt.where);
6259
- validateNestedSelects(stmt);
6260
- return;
6261
- }
6262
- if (containsKlike(stmt) && stmt.subtableCode) {
6263
- throw new KlikeValidationError(
6264
- "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6265
- );
6266
- }
6267
- if (!stmt.applyBlocks?.length && !stmt.subtableCode && whereHasKlike(stmt.where) && !containsKlikeOutsideWhereAndNestedSelects(stmt, stmt.where)) {
6268
- validateKlikeWhereExpressions(stmt.where);
6269
- validateNestedSelects(stmt);
6270
- return;
6271
- }
6272
- if (containsKlike(stmt)) {
6273
- throw new KlikeValidationError(
6274
- "KLIKE / NOT KLIKE \u306F\u901A\u5E38\u89AA UPDATE \u306E WHERE\u3001\u307E\u305F\u306F APPLY \u8907\u6570\u89AA UPDATE \u306E\u5B89\u5168\u306A\u89AA WHERE \u3060\u3051\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059"
6275
- );
6276
- }
6277
- return;
6278
- case "DELETE":
6279
- if (containsKlike(stmt) && stmt.subtableCode) {
6280
- throw new KlikeValidationError(
6281
- "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6282
- );
6283
- }
6284
- if (!stmt.subtableCode && whereHasKlike(stmt.where)) {
6285
- validateKlikeWhereExpressions(stmt.where);
6286
- validateNestedSelects(stmt);
6287
- return;
6288
- }
6289
- if (containsKlike(stmt)) {
6290
- throw new KlikeValidationError(
6291
- "KLIKE / NOT KLIKE \u306F\u901A\u5E38\u89AA DELETE \u306E WHERE \u3060\u3051\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059"
6292
- );
6293
- }
6294
- return;
6295
- case "INSERT":
6296
- case "INSERT_SELECT":
6297
- if (containsKlike(stmt)) {
6298
- throw new KlikeValidationError(
6299
- "KLIKE / NOT KLIKE \u306F INSERT / INSERT SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6300
- );
6301
- }
6302
- return;
6303
- case "UPSERT":
6304
- case "UPSERT_SELECT":
6305
- if (containsKlike(stmt)) {
6306
- throw new KlikeValidationError(
6307
- "KLIKE / NOT KLIKE \u306F UPSERT / UPSERT SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6308
- );
6309
- }
6310
- return;
6311
- case "REORDER":
6312
- if (containsKlike(stmt)) {
6313
- throw new KlikeValidationError(
6314
- "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB REORDER \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6315
- );
6316
- }
6317
- return;
6318
- case "VALIDATE":
6319
- if (containsKlike(stmt)) {
6320
- throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F VALIDATE \u306E WHERE / CHECK \u3067\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
6321
- }
6322
- return;
6323
- case "SHOW_APPS":
6324
- case "DESCRIBE":
6325
- case "DROP_TEMP_TABLE":
6326
- return;
6327
- }
6328
- }
6329
- function validateKlikeWhereExpressions(where) {
6330
- walkWithoutNestedSelects(where, (expr) => {
6331
- if (!isKlike(expr)) return;
6332
- const right = expr.right;
6333
- if (right.type !== "STRING" && right.type !== "VARIABLE") {
6334
- throw new KlikeValidationError(
6335
- "KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
6336
- );
6337
- }
6338
- if (right.type === "STRING" && right.value.includes("%")) {
6339
- throw new KlikeValidationError(
6340
- "KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
6341
- );
6342
- }
6343
- });
6344
- }
6345
- function validateSelectLike(query) {
6346
- if (query.type === "SELECT") validateSelect(query);
6347
- else if (query.type === "UNION") validateUnion(query);
6348
- else validateWith(query);
6349
- }
6350
- function validateUnion(stmt) {
6351
- validateSelectLike(stmt.left);
6352
- validateSelect(stmt.right);
6353
- }
6354
- function validateWith(stmt) {
6355
- if (canInlineSingleCte(stmt)) {
6356
- validateSelect(buildInlinedQuery(stmt));
6357
- return;
6358
- }
6359
- for (const cte of stmt.ctes) {
6360
- if (cte.query.type === "SELECT") validateSelect(cte.query);
6361
- else if (cte.query.type === "UNION") validateUnion(cte.query);
6362
- }
6363
- validateSelectLike(stmt.query);
6364
- }
6365
- function validateSelect(stmt) {
6366
- validateOwnKlikeExpressions(stmt);
6367
- if (whereHasKlike(stmt.where)) {
6368
- const directKintoneSimple = resolveSelectMode(stmt) === "SIMPLE" && stmt.from.cteName === null && stmt.joins.every((join2) => join2.table.cteName === null);
6369
- if (!directKintoneSimple) {
6370
- const plan = buildKlikePushdownPlan(stmt, { allowUnresolvedVariables: true });
6371
- if (unappliedKlikes(plan).length === 0) {
6372
- validateNestedSelects(stmt);
6373
- return;
6374
- }
6375
- if (canDeferJoinWholeWhereKlikeValidation(stmt)) {
6376
- validateNestedSelects(stmt);
6377
- return;
6378
- }
6379
- throw new KlikeValidationError(
6380
- "FULL_SCAN \u306E KLIKE / NOT KLIKE \u306F\u3001\u7269\u7406\u30C6\u30FC\u30D6\u30EB\u306B\u5BFE\u3059\u308B AND \u30EA\u30FC\u30D5\u3068\u3057\u3066\u5FC5\u305A\u62BC\u3057\u4E0B\u3052\u3089\u308C\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002OR / NOT \u914D\u4E0B\u3001CTE\u30FB\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3001LEFT / RIGHT JOIN \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6381
- );
6382
- }
6383
- }
6384
- validateNestedSelects(stmt);
6385
- }
6386
- function canDeferJoinWholeWhereKlikeValidation(stmt) {
6387
- return stmt.where !== null && serverOnlyFunctionOccurrencesInWhere(stmt.where).length > 0 && stmt.joins.length > 0 && stmt.joins.every((join2) => join2.type === "INNER") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
6388
- (table) => table.alias !== null && table.cteName === null && !table.subtableCode
6389
- );
6390
- }
6391
- function validateOwnKlikeExpressions(stmt) {
6392
- walkWithoutNestedSelects(stmt, (where) => {
6393
- if (!isKlike(where)) return;
6394
- if (!isDescendantOf(stmt.where, where)) {
6395
- throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F SELECT \u306E WHERE \u53E5\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
6396
- }
6397
- const right = where.right;
6398
- if (right.type !== "STRING" && right.type !== "VARIABLE") {
6399
- throw new KlikeValidationError(
6400
- "KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
6401
- );
6402
- }
6403
- if (right.type === "STRING" && right.value.includes("%")) {
6404
- throw new KlikeValidationError(
6405
- "KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
6406
- );
6407
- }
6408
- });
6409
- }
6410
- function validateNestedSelects(node) {
6411
- walkObjects(node, (obj) => {
6412
- if (obj.type === "SELECT") validateSelect(obj);
6413
- }, true);
6414
- }
6415
- function containsKlike(node) {
6416
- let found = false;
6417
- walkObjects(node, (obj) => {
6418
- if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) found = true;
6419
- });
6420
- return found;
6421
- }
6422
- function containsKlikeOutsideWhereAndNestedSelects(node, allowedWhere) {
6423
- let found = false;
6424
- const visit = (value) => {
6425
- if (found || value === allowedWhere || value === null || typeof value !== "object") return;
6426
- if (Array.isArray(value)) {
6427
- for (const item of value) visit(item);
6428
- return;
6429
- }
6430
- const obj = value;
6431
- if (obj.type === "SELECT") return;
6432
- if (obj.type === "BINARY" && (obj.op === "KLIKE" || obj.op === "NOT_KLIKE")) {
6433
- found = true;
6434
- return;
6513
+ visit(node.left);
6514
+ visit(node.right);
6515
+ return;
6516
+ case "NOT":
6517
+ case "GROUP":
6518
+ visit(node.expr);
6519
+ return;
6520
+ case "EXISTS":
6521
+ case "NULL_CHECK":
6522
+ case "BOOLEAN":
6523
+ return;
6435
6524
  }
6436
- for (const child of Object.values(obj)) visit(child);
6437
6525
  };
6438
- visit(node);
6439
- return found;
6526
+ visit(where);
6527
+ return leaves;
6440
6528
  }
6441
- function isDescendantOf(root, target) {
6442
- if (root === null) return false;
6443
- if (root === target) return true;
6444
- switch (root.type) {
6445
- case "LOGICAL":
6446
- return isDescendantOf(root.left, target) || isDescendantOf(root.right, target);
6447
- case "NOT":
6448
- case "GROUP":
6449
- return isDescendantOf(root.expr, target);
6450
- case "BINARY":
6451
- case "NULL_CHECK":
6452
- case "EXISTS":
6453
- return false;
6454
- case "BOOLEAN":
6455
- return false;
6456
- }
6529
+ function sameOccurrenceList(actual, expected) {
6530
+ return actual.length === expected.length && actual.every((name, index) => name === expected[index]);
6457
6531
  }
6458
- function walkWithoutNestedSelects(node, visitWhere) {
6459
- if (Array.isArray(node)) {
6460
- for (const value of node) walkWithoutNestedSelects(value, visitWhere);
6461
- return;
6462
- }
6463
- if (node === null || typeof node !== "object") return;
6464
- const obj = node;
6465
- if (obj.type === "BINARY" || obj.type === "NULL_CHECK" || obj.type === "LOGICAL" || obj.type === "NOT" || obj.type === "GROUP" || obj.type === "EXISTS") {
6466
- visitWhere(obj);
6467
- }
6468
- for (const value of Object.values(obj)) {
6469
- if (value !== node && isSelectObject(value)) continue;
6470
- walkWithoutNestedSelects(value, visitWhere);
6532
+ function serializedMultisetContains(query, expectedNames) {
6533
+ const expected = /* @__PURE__ */ new Map();
6534
+ for (const name of expectedNames) {
6535
+ if (!isServerOnlyWhereFunctionName(name)) return false;
6536
+ expected.set(name, (expected.get(name) ?? 0) + 1);
6471
6537
  }
6472
- }
6473
- function walkObjects(node, visit, skipRoot = false) {
6474
- if (Array.isArray(node)) {
6475
- for (const value of node) walkObjects(value, visit);
6476
- return;
6538
+ for (const [name, count] of expected) {
6539
+ const matches = query.match(new RegExp(`\\b${name}\\s*\\(`, "g"));
6540
+ if ((matches?.length ?? 0) < count) return false;
6477
6541
  }
6478
- if (node === null || typeof node !== "object") return;
6479
- const obj = node;
6480
- if (!skipRoot) visit(obj);
6481
- for (const value of Object.values(obj)) walkObjects(value, visit);
6482
- }
6483
- function isSelectObject(value) {
6484
- return value !== null && typeof value === "object" && value.type === "SELECT";
6542
+ return true;
6485
6543
  }
6486
6544
 
6487
- // src/core/primaryOrganizationDmlValidation.ts
6488
- var PrimaryOrganizationDmlValidationError = class extends Error {
6489
- constructor() {
6490
- super(
6491
- "ArgumentError: PRIMARY_ORGANIZATION() \u306F DML \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6492
- );
6545
+ // src/core/klikeValidation.ts
6546
+ var KlikeValidationError = class extends Error {
6547
+ constructor(message) {
6548
+ super(`ArgumentError: ${message}`);
6493
6549
  this.name = "ArgumentError";
6494
6550
  }
6495
6551
  };
6496
- function validatePrimaryOrganizationDmlStatement(stmt) {
6497
- const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
6498
- switch (target.type) {
6552
+ function validateKlikeStatement(stmt) {
6553
+ validateStatement(stmt);
6554
+ }
6555
+ function validateKlikePushdownPlan(plan) {
6556
+ if (unappliedKlikes(plan).length > 0) {
6557
+ throw new KlikeValidationError(
6558
+ "FULL_SCAN \u306E KLIKE / NOT KLIKE \u3092\u5B89\u5168\u306B\u62BC\u3057\u4E0B\u3052\u3089\u308C\u307E\u305B\u3093\u3002OR / NOT \u914D\u4E0B\u3001CTE\u30FB\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3001LEFT / RIGHT JOIN \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044"
6559
+ );
6560
+ }
6561
+ }
6562
+ function validateStatement(stmt) {
6563
+ switch (stmt.type) {
6564
+ case "SELECT":
6565
+ validateSelect(stmt);
6566
+ return;
6567
+ case "UNION":
6568
+ validateUnion(stmt);
6569
+ return;
6570
+ case "WITH":
6571
+ validateWith(stmt);
6572
+ return;
6573
+ case "EXPLAIN":
6574
+ validateStatement(stmt.query);
6575
+ return;
6576
+ case "CREATE_TEMP_TABLE":
6577
+ validateSelectLike(stmt.query);
6578
+ return;
6579
+ case "SET_VARIABLE":
6580
+ case "DECLARE_VARIABLE":
6581
+ case "ASSERT":
6582
+ validateNestedSelects(stmt);
6583
+ return;
6499
6584
  case "UPDATE":
6585
+ if (stmt.applyBlocks?.length && !isSinglePositiveRecordIdWhere(stmt.where) && whereHasKlike(stmt.where)) {
6586
+ validateKlikeWhereExpressions(stmt.where);
6587
+ validateNestedSelects(stmt);
6588
+ return;
6589
+ }
6590
+ if (containsKlike(stmt) && stmt.subtableCode) {
6591
+ throw new KlikeValidationError(
6592
+ "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6593
+ );
6594
+ }
6595
+ if (!stmt.applyBlocks?.length && !stmt.subtableCode && whereHasKlike(stmt.where) && !containsKlikeOutsideWhereAndNestedSelects(stmt, stmt.where)) {
6596
+ validateKlikeWhereExpressions(stmt.where);
6597
+ validateNestedSelects(stmt);
6598
+ return;
6599
+ }
6600
+ if (containsKlike(stmt)) {
6601
+ throw new KlikeValidationError(
6602
+ "KLIKE / NOT KLIKE \u306F\u901A\u5E38\u89AA UPDATE \u306E WHERE\u3001\u307E\u305F\u306F APPLY \u8907\u6570\u89AA UPDATE \u306E\u5B89\u5168\u306A\u89AA WHERE \u3060\u3051\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059"
6603
+ );
6604
+ }
6605
+ return;
6500
6606
  case "DELETE":
6607
+ if (containsKlike(stmt) && stmt.subtableCode) {
6608
+ throw new KlikeValidationError(
6609
+ "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB DELETE \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6610
+ );
6611
+ }
6612
+ if (!stmt.subtableCode && whereHasKlike(stmt.where)) {
6613
+ validateKlikeWhereExpressions(stmt.where);
6614
+ validateNestedSelects(stmt);
6615
+ return;
6616
+ }
6617
+ if (containsKlike(stmt)) {
6618
+ throw new KlikeValidationError(
6619
+ "KLIKE / NOT KLIKE \u306F\u901A\u5E38\u89AA DELETE \u306E WHERE \u3060\u3051\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059"
6620
+ );
6621
+ }
6622
+ return;
6623
+ case "INSERT":
6624
+ case "INSERT_SELECT":
6625
+ if (containsKlike(stmt)) {
6626
+ throw new KlikeValidationError(
6627
+ "KLIKE / NOT KLIKE \u306F INSERT / INSERT SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6628
+ );
6629
+ }
6630
+ return;
6501
6631
  case "UPSERT":
6502
6632
  case "UPSERT_SELECT":
6503
- case "INSERT_SELECT":
6504
- if (hasPrimaryOrganizationInWhere(target)) {
6505
- throw new PrimaryOrganizationDmlValidationError();
6633
+ if (containsKlike(stmt)) {
6634
+ throw new KlikeValidationError(
6635
+ "KLIKE / NOT KLIKE \u306F UPSERT / UPSERT SELECT \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6636
+ );
6506
6637
  }
6507
6638
  return;
6508
- default:
6639
+ case "REORDER":
6640
+ if (containsKlike(stmt)) {
6641
+ throw new KlikeValidationError(
6642
+ "KLIKE / NOT KLIKE \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB REORDER \u306E WHERE \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6643
+ );
6644
+ }
6645
+ return;
6646
+ case "VALIDATE":
6647
+ if (containsKlike(stmt)) {
6648
+ throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F VALIDATE \u306E WHERE / CHECK \u3067\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
6649
+ }
6650
+ return;
6651
+ case "SHOW_APPS":
6652
+ case "DESCRIBE":
6653
+ case "DROP_TEMP_TABLE":
6509
6654
  return;
6510
6655
  }
6511
6656
  }
6512
- function hasPrimaryOrganizationInWhere(node) {
6513
- let found = false;
6514
- walkObjects2(node, (obj) => {
6515
- if (found || !Object.prototype.hasOwnProperty.call(obj, "where")) return;
6516
- if (containsPrimaryOrganization(obj.where)) found = true;
6517
- });
6518
- return found;
6519
- }
6520
- function containsPrimaryOrganization(node) {
6521
- let found = false;
6522
- walkObjects2(node, (obj) => {
6523
- if (obj.type === "KINTONE_FUNC" && obj.name === "PRIMARY_ORGANIZATION") {
6524
- found = true;
6525
- }
6526
- });
6527
- return found;
6528
- }
6529
- function walkObjects2(node, visit) {
6530
- if (Array.isArray(node)) {
6531
- for (const value of node) walkObjects2(value, visit);
6532
- return;
6533
- }
6534
- if (node === null || typeof node !== "object") return;
6535
- const obj = node;
6536
- visit(obj);
6537
- for (const value of Object.values(obj)) walkObjects2(value, visit);
6538
- }
6539
-
6540
- // src/core/statementValidation.ts
6541
- function validateStatementStatic(stmt) {
6542
- validatePrimaryOrganizationDmlStatement(stmt);
6543
- validateKlikeStatement(stmt);
6544
- }
6545
-
6546
- // src/engine/groupingRowMeta.ts
6547
- var groupingRowMetaKey = /* @__PURE__ */ Symbol("ksql.groupingRowMeta");
6548
- var groupingRefCanonicalIds = /* @__PURE__ */ new WeakMap();
6549
- function attachGroupingRowMeta(row, includedCanonicalIds) {
6550
- Object.defineProperty(row, groupingRowMetaKey, {
6551
- value: { includedCanonicalIds },
6552
- enumerable: false,
6553
- configurable: false,
6554
- writable: false
6555
- });
6556
- return row;
6557
- }
6558
- function getGroupingRowMeta(row) {
6559
- return row[groupingRowMetaKey];
6560
- }
6561
- function readGroupingMembership(row) {
6562
- return getGroupingRowMeta(row)?.includedCanonicalIds;
6563
- }
6564
- function bindGroupingRefCanonicalId(ref, canonicalId) {
6565
- groupingRefCanonicalIds.set(ref, canonicalId);
6566
- }
6567
- function evalGroupingRef(ref, row) {
6568
- const membership = readGroupingMembership(row);
6569
- if (!membership) {
6570
- throw new Error("internal error: GROUPING() evaluation requires B65 grouping row membership.");
6571
- }
6572
- const canonicalId = groupingRefCanonicalIds.get(ref);
6573
- if (!canonicalId) {
6574
- throw new Error("internal error: GROUPING() reference was not resolved during B65 planning.");
6575
- }
6576
- return membership.has(canonicalId) ? "0" : "1";
6577
- }
6578
-
6579
- // src/core/groupingValidation.ts
6580
- var enforceGroupingPlanningCandidateLimits = (facts) => {
6581
- if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
6582
- throw new Error(
6583
- `ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
6584
- );
6585
- }
6586
- if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
6587
- throw new Error(
6588
- `ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
6589
- );
6590
- }
6591
- };
6592
- function displayField(field) {
6593
- return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
6594
- }
6595
- function refFromName(name) {
6596
- const dot = name.indexOf(".");
6597
- return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
6657
+ function validateKlikeWhereExpressions(where) {
6658
+ walkWithoutNestedSelects(where, (expr) => {
6659
+ if (!isKlike(expr)) return;
6660
+ const right = expr.right;
6661
+ if (right.type !== "STRING" && right.type !== "VARIABLE") {
6662
+ throw new KlikeValidationError(
6663
+ "KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
6664
+ );
6665
+ }
6666
+ if (right.type === "STRING" && right.value.includes("%")) {
6667
+ throw new KlikeValidationError(
6668
+ "KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
6669
+ );
6670
+ }
6671
+ });
6598
6672
  }
6599
- function collectGroupingRefs(node, out) {
6600
- if (node === null || typeof node !== "object") return;
6601
- if (Array.isArray(node)) {
6602
- node.forEach((item) => collectGroupingRefs(item, out));
6603
- return;
6604
- }
6605
- const value = node;
6606
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
6607
- if (value["type"] === "GROUPING_REF") {
6608
- out.push(value);
6609
- return;
6610
- }
6611
- Object.values(value).forEach((item) => collectGroupingRefs(item, out));
6673
+ function validateSelectLike(query) {
6674
+ if (query.type === "SELECT") validateSelect(query);
6675
+ else if (query.type === "UNION") validateUnion(query);
6676
+ else validateWith(query);
6612
6677
  }
6613
- function collectAggregateArgumentGroupingRefs(node, out) {
6614
- if (node === null || typeof node !== "object") return;
6615
- if (Array.isArray(node)) {
6616
- node.forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6617
- return;
6618
- }
6619
- const value = node;
6620
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return;
6621
- if (value["type"] === "AGGREGATE" || value["type"] === "AGG_REF") {
6622
- collectGroupingRefs(value["arg"], out);
6623
- return;
6624
- }
6625
- Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
6678
+ function validateUnion(stmt) {
6679
+ validateSelectLike(stmt.left);
6680
+ validateSelect(stmt.right);
6626
6681
  }
6627
- function collectNonAggregateFieldRefs(node, out) {
6628
- if (node === null || typeof node !== "object") return;
6629
- if (Array.isArray(node)) {
6630
- node.forEach((item) => collectNonAggregateFieldRefs(item, out));
6631
- return;
6632
- }
6633
- const value = node;
6634
- const type = value["type"];
6635
- if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
6636
- if (type === "FIELD" && typeof value["field"] === "string") {
6637
- out.push({
6638
- type: "FIELD",
6639
- tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
6640
- field: value["field"]
6641
- });
6682
+ function validateWith(stmt) {
6683
+ if (canInlineSingleCte(stmt)) {
6684
+ validateSelect(buildInlinedQuery(stmt));
6642
6685
  return;
6643
6686
  }
6644
- if (type === "FIELD_REF" && typeof value["field"] === "string") {
6645
- out.push(refFromName(value["field"]));
6646
- return;
6687
+ for (const cte of stmt.ctes) {
6688
+ if (cte.query.type === "SELECT") validateSelect(cte.query);
6689
+ else if (cte.query.type === "UNION") validateUnion(cte.query);
6647
6690
  }
6648
- Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
6649
- }
6650
- function containsAggregate2(node) {
6651
- if (node === null || typeof node !== "object") return false;
6652
- if (Array.isArray(node)) return node.some(containsAggregate2);
6653
- const value = node;
6654
- if (value["type"] === "AGG_REF" || value["type"] === "AGG_ARITH") return true;
6655
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
6656
- return Object.values(value).some(containsAggregate2);
6691
+ validateSelectLike(stmt.query);
6657
6692
  }
6658
- function isAggregateMaterializedAlias(column) {
6659
- if (!("alias" in column) || column.alias === null) return false;
6660
- if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
6661
- if (column.type === "STRFUNC_COL" || column.type === "SCALAR_VALUE_COL") {
6662
- return containsAggregate2(column);
6693
+ function validateSelect(stmt) {
6694
+ validateOwnKlikeExpressions(stmt);
6695
+ if (whereHasKlike(stmt.where)) {
6696
+ const directKintoneSimple = resolveSelectMode(stmt) === "SIMPLE" && stmt.from.cteName === null && stmt.joins.every((join2) => join2.table.cteName === null);
6697
+ if (!directKintoneSimple) {
6698
+ const plan = buildKlikePushdownPlan(stmt, { allowUnresolvedVariables: true });
6699
+ if (unappliedKlikes(plan).length === 0) {
6700
+ validateNestedSelects(stmt);
6701
+ return;
6702
+ }
6703
+ if (canDeferJoinWholeWhereKlikeValidation(stmt)) {
6704
+ validateNestedSelects(stmt);
6705
+ return;
6706
+ }
6707
+ throw new KlikeValidationError(
6708
+ "FULL_SCAN \u306E KLIKE / NOT KLIKE \u306F\u3001\u7269\u7406\u30C6\u30FC\u30D6\u30EB\u306B\u5BFE\u3059\u308B AND \u30EA\u30FC\u30D5\u3068\u3057\u3066\u5FC5\u305A\u62BC\u3057\u4E0B\u3052\u3089\u308C\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002OR / NOT \u914D\u4E0B\u3001CTE\u30FB\u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3001LEFT / RIGHT JOIN \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093"
6709
+ );
6710
+ }
6663
6711
  }
6664
- return false;
6712
+ validateNestedSelects(stmt);
6665
6713
  }
6666
- function outputAliases(columns) {
6667
- return new Set(columns.flatMap(
6668
- (column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
6669
- ));
6714
+ function canDeferJoinWholeWhereKlikeValidation(stmt) {
6715
+ return stmt.where !== null && serverOnlyFunctionOccurrencesInWhere(stmt.where).length > 0 && stmt.joins.length > 0 && stmt.joins.every((join2) => join2.type === "INNER") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
6716
+ (table) => table.alias !== null && table.cteName === null && !table.subtableCode
6717
+ );
6670
6718
  }
6671
- function isAggregateSyntheticReference(ref) {
6672
- return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
6719
+ function validateOwnKlikeExpressions(stmt) {
6720
+ walkWithoutNestedSelects(stmt, (where) => {
6721
+ if (!isKlike(where)) return;
6722
+ if (!isDescendantOf(stmt.where, where)) {
6723
+ throw new KlikeValidationError("KLIKE / NOT KLIKE \u306F SELECT \u306E WHERE \u53E5\u3067\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059");
6724
+ }
6725
+ const right = where.right;
6726
+ if (right.type !== "STRING" && right.type !== "VARIABLE") {
6727
+ throw new KlikeValidationError(
6728
+ "KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u6587\u5B57\u5217\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
6729
+ );
6730
+ }
6731
+ if (right.type === "STRING" && right.value.includes("%")) {
6732
+ throw new KlikeValidationError(
6733
+ "KLIKE / NOT KLIKE \u306E\u691C\u7D22\u8A9E\u306B % \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002SQL \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u691C\u7D22\u306B\u306F LIKE \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044"
6734
+ );
6735
+ }
6736
+ });
6673
6737
  }
6674
- function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
6675
- const resolved = resolve2(ref.field);
6676
- if (!resolved.physical) {
6677
- throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
6678
- }
6679
- if (!canonicalItems.has(resolved.canonicalId)) {
6680
- throw new Error(
6681
- `ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
6682
- );
6683
- }
6684
- bindGroupingRefCanonicalId(ref, resolved.canonicalId);
6738
+ function validateNestedSelects(node) {
6739
+ walkObjects(node, (obj) => {
6740
+ if (obj.type === "SELECT") validateSelect(obj);
6741
+ }, true);
6685
6742
  }
6686
- function validateDependency(ref, resolve2, canonicalItems, context) {
6687
- const resolved = resolve2(ref);
6688
- if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
6689
- throw new Error(
6690
- `ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
6691
- );
6692
- }
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;
6693
6749
  }
6694
- function keyDependencies(key) {
6695
- if (key.type === "GROUPING_KEY") return [];
6696
- if (key.type === "FIELD_NAME") return [refFromName(key.name)];
6697
- const refs = [];
6698
- collectNonAggregateFieldRefs(key, refs);
6699
- return refs;
6750
+ function containsKlikeOutsideWhereAndNestedSelects(node, allowedWhere) {
6751
+ let found = false;
6752
+ const visit = (value) => {
6753
+ if (found || value === allowedWhere || value === null || typeof value !== "object") return;
6754
+ if (Array.isArray(value)) {
6755
+ for (const item of value) visit(item);
6756
+ return;
6757
+ }
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;
6763
+ }
6764
+ for (const child of Object.values(obj)) visit(child);
6765
+ };
6766
+ visit(node);
6767
+ return found;
6700
6768
  }
6701
- function validateGroupingStatic(stmt) {
6702
- const normalized = normalizeGroupingSpec(stmt);
6703
- const groupingRefs = [];
6704
- for (const column of stmt.columns) {
6705
- if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
6706
- }
6707
- collectGroupingRefs(stmt.having, groupingRefs);
6708
- collectGroupingRefs(stmt.orderBy, groupingRefs);
6709
- const forbiddenGroupingRefs = [];
6710
- collectGroupingRefs(stmt.where, forbiddenGroupingRefs);
6711
- collectGroupingRefs(stmt.joins, forbiddenGroupingRefs);
6712
- collectAggregateArgumentGroupingRefs(stmt.columns, forbiddenGroupingRefs);
6713
- collectAggregateArgumentGroupingRefs(stmt.having, forbiddenGroupingRefs);
6714
- for (const column of stmt.columns) {
6715
- if (column.type === "WINDOW_COL") collectGroupingRefs(column, forbiddenGroupingRefs);
6716
- }
6717
- if (forbiddenGroupingRefs.length > 0) {
6718
- throw new Error(
6719
- "ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
6720
- );
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;
6721
6784
  }
6722
- if (normalized.type !== "GROUPING_SETS") {
6723
- if (groupingRefs.length > 0) {
6724
- throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
6725
- }
6785
+ }
6786
+ function walkWithoutNestedSelects(node, visitWhere) {
6787
+ if (Array.isArray(node)) {
6788
+ for (const value of node) walkWithoutNestedSelects(value, visitWhere);
6726
6789
  return;
6727
6790
  }
6728
- if (stmt.orderMode === "KINTONE_NATIVE") {
6729
- throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
6791
+ if (node === null || typeof node !== "object") 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);
6730
6795
  }
6731
- if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
6732
- throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
6796
+ for (const value of Object.values(obj)) {
6797
+ if (value !== node && isSelectObject(value)) continue;
6798
+ walkWithoutNestedSelects(value, visitWhere);
6733
6799
  }
6734
- if (stmt.columns.some(
6735
- (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
6736
- )) {
6737
- throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
6800
+ }
6801
+ function walkObjects(node, visit, skipRoot = false) {
6802
+ if (Array.isArray(node)) {
6803
+ for (const value of node) walkObjects(value, visit);
6804
+ return;
6738
6805
  }
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);
6739
6810
  }
6740
- function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
6741
- validateGroupingStatic(stmt);
6742
- const normalized = normalizeGroupingSpec(stmt);
6743
- const groupingRefs = [];
6744
- for (const column of stmt.columns) {
6745
- if (column.type !== "WINDOW_COL") collectGroupingRefs(column, groupingRefs);
6811
+ function isSelectObject(value) {
6812
+ return value !== null && typeof value === "object" && value.type === "SELECT";
6813
+ }
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";
6746
6822
  }
6747
- collectGroupingRefs(stmt.having, groupingRefs);
6748
- collectGroupingRefs(stmt.orderBy, groupingRefs);
6749
- if (normalized.type !== "GROUPING_SETS") {
6750
- 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;
6751
6838
  }
6752
- const resolvedSpec = resolveGroupingSpec(stmt, resolve2);
6753
- const canonicalItems = /* @__PURE__ */ new Set();
6754
- const resolvedItems = [];
6755
- for (const item of resolvedSpec.allItems) {
6756
- const resolved = item;
6757
- if (!resolved.physical) {
6758
- throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
6759
- }
6760
- if (!canonicalItems.has(resolved.canonicalId)) {
6761
- canonicalItems.add(resolved.canonicalId);
6762
- 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;
6763
6853
  }
6764
- }
6765
- planningGuardHook({
6766
- expandedSetCount: normalized.sets.length,
6767
- canonicalItemCount: canonicalItems.size
6768
6854
  });
6769
- for (const ref of groupingRefs) {
6770
- validateGroupingRefMembership(ref, resolve2, canonicalItems);
6771
- }
6772
- const aliases = outputAliases(stmt.columns);
6773
- for (const column of stmt.columns) {
6774
- 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;
6775
- const refs = [];
6776
- if (column.type === "FIELD") refs.push(refFromName(column.field));
6777
- else collectNonAggregateFieldRefs(column, refs);
6778
- 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;
6779
6861
  }
6780
- if (stmt.having) {
6781
- const refs = [];
6782
- collectNonAggregateFieldRefs(stmt.having, refs);
6783
- for (const ref of refs) {
6784
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
6785
- validateDependency(ref, resolve2, canonicalItems, "HAVING");
6786
- }
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);
6787
6930
  }
6788
- for (const order of stmt.orderBy) {
6789
- for (const ref of keyDependencies(order.key)) {
6790
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
6791
- 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;
6792
6945
  }
6793
- }
6794
- const collisionKeys = /* @__PURE__ */ new Set();
6795
- for (const item of resolvedItems) {
6796
- collisionKeys.add(item.directKey);
6797
- if (item.unqualifiedBridgeKey !== null) collisionKeys.add(item.unqualifiedBridgeKey);
6798
- }
6799
- for (const column of stmt.columns) {
6800
- if (!isAggregateMaterializedAlias(column)) continue;
6801
- const alias = "alias" in column ? column.alias : null;
6802
- if (alias === null) continue;
6803
- if (collisionKeys.has(alias)) {
6804
- throw new Error(
6805
- `ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
6806
- );
6946
+ const node = value;
6947
+ if (node.type === "STRING_FUNC") {
6948
+ const expr = node;
6949
+ assertStringFunctionArity(expr.func, expr.args);
6807
6950
  }
6808
- }
6809
- return resolvedSpec;
6951
+ Object.values(node).forEach(visit);
6952
+ };
6953
+ visit(stmt);
6810
6954
  }
6811
6955
 
6812
6956
  // src/core/batch.ts
@@ -7566,6 +7710,7 @@ function replaceNthMatch(input, globalRe, replacement, n) {
7566
7710
  });
7567
7711
  }
7568
7712
  function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7713
+ assertStringFunctionArity(expr.func, expr.args);
7569
7714
  const args = expr.args.map((a) => evalStringFuncArg(a, row, resolveFieldType, resolveFieldSemantics2));
7570
7715
  switch (expr.func) {
7571
7716
  case "UPPER":
@@ -7581,7 +7726,6 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7581
7726
  case "LENGTH":
7582
7727
  return String((args[0] ?? "").length);
7583
7728
  case "LENGTH_CHAR":
7584
- assertArity("LENGTH_CHAR", args, 1, 1);
7585
7729
  return String([...args[0] ?? ""].length);
7586
7730
  case "SUBSTRING": {
7587
7731
  const str = args[0] ?? "";
@@ -7590,23 +7734,19 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7590
7734
  return sliceSafeRange(str, start, len !== void 0 ? start + len : str.length);
7591
7735
  }
7592
7736
  case "LEFT": {
7593
- assertArity("LEFT", args, 2, 2);
7594
7737
  const str = args[0];
7595
7738
  const n = Math.trunc(Number(args[1]));
7596
7739
  return Number.isNaN(n) || n <= 0 ? "" : sliceSafePrefix(str, n);
7597
7740
  }
7598
7741
  case "RIGHT": {
7599
- assertArity("RIGHT", args, 2, 2);
7600
7742
  const str = args[0];
7601
7743
  const n = Math.trunc(Number(args[1]));
7602
7744
  return Number.isNaN(n) || n <= 0 ? "" : sliceSafeSuffix(str, n);
7603
7745
  }
7604
7746
  case "INSTR":
7605
- assertArity("INSTR", args, 2, 2);
7606
7747
  return String(args[0].indexOf(args[1]) + 1);
7607
7748
  case "LPAD":
7608
7749
  case "RPAD": {
7609
- assertArity(expr.func, args, 2, 3);
7610
7750
  const str = args[0];
7611
7751
  const n = Math.trunc(Number(args[1]));
7612
7752
  if (Number.isNaN(n) || n <= 0) return "";
@@ -7618,7 +7758,6 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7618
7758
  }
7619
7759
  case "GREATEST":
7620
7760
  case "LEAST":
7621
- assertArity(expr.func, args, 2);
7622
7761
  return selectScalarExtreme(args, expr.func === "GREATEST" ? "greatest" : "least");
7623
7762
  case "CONCAT":
7624
7763
  return args.join("");
@@ -7629,22 +7768,18 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7629
7768
  return from === "" ? str : str.split(from).join(to);
7630
7769
  }
7631
7770
  case "REGEXP_LIKE": {
7632
- assertArity("REGEXP_LIKE", args, 2, 3);
7633
7771
  return compileRegexp(args[1], args[2] ?? "").test(args[0]) ? "1" : "0";
7634
7772
  }
7635
7773
  case "REGEXP_REPLACE": {
7636
- assertArity("REGEXP_REPLACE", args, 3, 5);
7637
7774
  assertRegexpReplacement(args[2]);
7638
7775
  const occurrence = parseRegexpOccurrence(args[4]);
7639
7776
  const regexp = compileRegexp(args[1], args[3] ?? "", true);
7640
7777
  return occurrence === 0 ? args[0].replace(regexp, args[2]) : replaceNthMatch(args[0], regexp, args[2], occurrence);
7641
7778
  }
7642
7779
  case "REGEXP_SUBSTR": {
7643
- assertArity("REGEXP_SUBSTR", args, 2, 3);
7644
7780
  return compileRegexp(args[1], args[2] ?? "").exec(args[0])?.[0] ?? "";
7645
7781
  }
7646
7782
  case "TRANSLATE": {
7647
- assertArity("TRANSLATE", args, 3, 3);
7648
7783
  const from = [...args[1]];
7649
7784
  const to = [...args[2]];
7650
7785
  if (from.length !== to.length) {
@@ -7671,7 +7806,6 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7671
7806
  case "CEIL":
7672
7807
  return applyRoundOp("ceil", Number(args[0] ?? "0"), Number(args[1] ?? "0"));
7673
7808
  case "TRUNCATE":
7674
- assertArity("TRUNCATE", args, 1, 2);
7675
7809
  return applyRoundOp("trunc", Number(args[0]), Number(args[1] ?? "0"));
7676
7810
  case "CAST": {
7677
7811
  const val = args[0] ?? "";
@@ -7700,13 +7834,10 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7700
7834
  return d.length >= 10 ? String(parseInt(d.slice(8, 10), 10)) : "";
7701
7835
  }
7702
7836
  case "DAYOFWEEK":
7703
- assertArity(expr.func, args, 1, 1);
7704
7837
  return isValidYmd(args[0]) ? String(dayOfWeekIndex(args[0]) + 1) : "";
7705
7838
  case "QUARTER":
7706
- assertArity(expr.func, args, 1, 1);
7707
7839
  return isValidYmd(args[0]) ? String(Math.ceil(Number(args[0].slice(5, 7)) / 3)) : "";
7708
7840
  case "WEEK":
7709
- assertArity(expr.func, args, 1, 1);
7710
7841
  return isValidYmd(args[0]) ? String(isoWeekNumber(args[0])) : "";
7711
7842
  case "DATE_FORMAT":
7712
7843
  return applyDateFormat(args[0] ?? "", args[1] ?? "");
@@ -7715,7 +7846,6 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7715
7846
  case "DATE_ADD":
7716
7847
  return applyDateAdd(args[0] ?? "", Number(args[1] ?? "0"), (args[2] ?? "DAY").toUpperCase());
7717
7848
  case "LAST_DAY":
7718
- assertArity("LAST_DAY", args, 1, 1);
7719
7849
  return applyLastDay(args[0]);
7720
7850
  case "ABS":
7721
7851
  return String(Math.abs(Number(args[0] ?? "0")));
@@ -7739,11 +7869,6 @@ function evalStringFunc(expr, row, resolveFieldType, resolveFieldSemantics2) {
7739
7869
  return (/* @__PURE__ */ new Date()).toISOString();
7740
7870
  }
7741
7871
  }
7742
- function assertArity(func, args, min, max = Number.POSITIVE_INFINITY) {
7743
- if (args.length >= min && args.length <= max) return;
7744
- const expected = min === max ? String(min) : max === Number.POSITIVE_INFINITY ? `${min} or more` : `${min} to ${max}`;
7745
- throw new Error(`ArgumentError: ${func} expects ${expected} argument(s).`);
7746
- }
7747
7872
  function parseDateParts(s) {
7748
7873
  return {
7749
7874
  y: s.slice(0, 4) || "0000",
@@ -7904,10 +8029,32 @@ function formatWithComma(num, digits) {
7904
8029
  return decStr ? `${intFmt}.${decStr}` : intFmt;
7905
8030
  }
7906
8031
  function evalStringFuncArg(arg, row, resolveFieldType, resolveFieldSemantics2) {
7907
- 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
+ }
7908
8035
  if (arg.type === "NUMBER") return numberLiteralText(arg);
7909
8036
  return String(evalScalarValueExpr(arg, row, resolveFieldType, resolveFieldSemantics2));
7910
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
+ }
7911
8058
  function resolveFieldRef(row, field) {
7912
8059
  const direct = row[field];
7913
8060
  if (direct !== void 0) return direct;
@@ -8002,7 +8149,7 @@ function semanticsForLeft(left, fieldType, resolveSemantics) {
8002
8149
  if (left.type === "FIELD") {
8003
8150
  return resolveSemantics?.(left) ?? (fieldType ? resolveFieldSemantics({ fieldType }) : syntheticSemantics("string"));
8004
8151
  }
8005
- if (left.type === "ARITH_FIELD") return syntheticSemantics("number");
8152
+ if (left.type === "ARITH_FIELD" || left.type === "AGG_FIELD") return syntheticSemantics("number");
8006
8153
  if (left.type === "FUNC_FIELD") {
8007
8154
  return syntheticSemantics(NUMERIC_STRING_FUNCTIONS.has(left.expr.func) ? "number" : "string");
8008
8155
  }
@@ -8095,6 +8242,7 @@ function evalLogical(expr, row, resolveFieldType, appliedKlikes, resolveFieldSem
8095
8242
  }
8096
8243
  function resolveField(field, row, resolveFieldType, resolveFieldSemantics2) {
8097
8244
  if (field.type === "FUNC_FIELD") return evalStringFunc(field.expr, row);
8245
+ if (field.type === "AGG_FIELD") return String(evalMaterializedAggregateOperand(field.expr, row));
8098
8246
  if (field.type === "ARITH_FIELD") return String(evalArithExpr(field.expr, row));
8099
8247
  if (field.type === "CASE_FIELD") return evalCaseWhen(field.expr, row, resolveFieldType, resolveFieldSemantics2);
8100
8248
  if (field.type === "GROUPING_FIELD") return evalGroupingRef(field.ref, row);
@@ -8152,12 +8300,20 @@ function evalCaseWhenNullable(expr, row, resolveFieldType, resolveFieldSemantics
8152
8300
  }
8153
8301
  function evalCaseResultNullable(result, row, resolveFieldType, resolveFieldSemantics2) {
8154
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)] ?? "";
8155
8307
  if (result.type === "FIELD_REF") return row[result.field] ?? "";
8156
8308
  if (result.type === "ARITH") return evalArithExpr(result, row);
8157
8309
  return evalScalarValueExprNullable(result, row, resolveFieldType, resolveFieldSemantics2);
8158
8310
  }
8159
8311
  function evalCaseResult(result, row, resolveFieldType, resolveFieldSemantics2) {
8160
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)] ?? "";
8161
8317
  if (result.type === "FIELD_REF") {
8162
8318
  return row[result.field] ?? "";
8163
8319
  }
@@ -8423,6 +8579,10 @@ function collectAggregateArgFields2(node, out) {
8423
8579
  }
8424
8580
  function collectCaseResultFields(result, out) {
8425
8581
  if (result.type === "ARRAY") return;
8582
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8583
+ collectAggOperandFields2(result, out);
8584
+ return;
8585
+ }
8426
8586
  if (result.type === "FIELD_REF" || result.type === "ARITH") {
8427
8587
  collectArithNode2(result, out);
8428
8588
  return;
@@ -8644,6 +8804,9 @@ function evalCaseResultValue(result, row, fieldType) {
8644
8804
  if (result.type === "ARRAY") {
8645
8805
  return convertArray(result.elements.map((e) => e.value), fieldType);
8646
8806
  }
8807
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") {
8808
+ throw new Error("InternalError: aggregate CASE result reached DML evaluation.");
8809
+ }
8647
8810
  if (result.type === "STRING") {
8648
8811
  return convertString2(result.value, fieldType);
8649
8812
  }
@@ -12832,7 +12995,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
12832
12995
  }
12833
12996
  function hasAggregateColumns(columns) {
12834
12997
  return columns.some(
12835
- (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)
12836
12999
  );
12837
13000
  }
12838
13001
  function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind, resolutionPlan, aliasEvaluationContext = {}) {
@@ -12937,26 +13100,72 @@ function groupingItemValue(item, row) {
12937
13100
  return row[item.directKey] ?? (item.unqualifiedBridgeKey === null ? void 0 : row[item.unqualifiedBridgeKey]) ?? "";
12938
13101
  }
12939
13102
  function materializeAggregateColumns(outRow, groupRows, columns, resolveAggSortKind) {
12940
- for (const col of columns) {
13103
+ for (const [columnIndex, col] of columns.entries()) {
12941
13104
  if (col.type === "AGGREGATE") {
12942
13105
  const syntheticKey = aggregateSyntheticName(col.func, col.distinct, col.arg);
12943
13106
  const value = String(evalAggregate(col.func, col.distinct, col.arg, col.separator, groupRows, resolveAggSortKind));
12944
13107
  outRow[col.alias ?? syntheticKey] = value;
12945
13108
  if (col.alias) outRow[syntheticKey] = value;
12946
13109
  } else if (col.type === "ARITH_AGG_COL") {
13110
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
12947
13111
  const outputKey = col.alias ?? aggArithDefaultKey(col.expr);
12948
13112
  outRow[outputKey] = String(evalAggArithExpr(col.expr, groupRows, resolveAggSortKind));
12949
13113
  } else if (col.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(col.expr)) {
13114
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
12950
13115
  const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
12951
13116
  const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
12952
13117
  outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
12953
13118
  } else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
13119
+ materializeAggregateDependencies(outRow, groupRows, col.expr, resolveAggSortKind);
12954
13120
  const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
12955
13121
  const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
12956
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
+ );
12957
13133
  }
12958
13134
  }
12959
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
+ }
12960
13169
  function evalGroupByKey(key, row, resolution, columns, aliasEvaluationContext) {
12961
13170
  if (key.type === "FIELD_NAME") {
12962
13171
  if (!resolution) return row[key.name] ?? "";
@@ -12997,7 +13206,7 @@ function evalAggregate(func, distinct, arg, separator, rows, resolveAggSortKind)
12997
13206
  const raw = row[arg.field];
12998
13207
  if (raw === void 0 || raw === "" && func !== "MIN" && func !== "MAX") continue;
12999
13208
  strVal = raw;
13000
- } else if (arg.type === "ARITH" || arg.type === "NUMBER" || arg.type === "STRING_FUNC") {
13209
+ } else if (arg.type === "ARITH" || arg.type === "NUMBER") {
13001
13210
  const n = evalArithExpr(arg, row);
13002
13211
  if (isNaN(n)) continue;
13003
13212
  strVal = String(n);
@@ -13129,6 +13338,16 @@ function resolveAggregateArgSemantics(arg, resolver) {
13129
13338
  const first = results[0];
13130
13339
  return results.every((result) => JSON.stringify(result) === JSON.stringify(first)) ? first : kinds[0];
13131
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
+ }
13132
13351
  function applyHaving(rows, having, resolveFieldType, resolveFieldSemantics2) {
13133
13352
  if (having === null) return rows;
13134
13353
  return rows.filter((row) => evalWhere(having, row, resolveFieldType, void 0, resolveFieldSemantics2));
@@ -13288,7 +13507,7 @@ function buildOrderByAliasEvaluator(columns, scalarCache, resolveFieldType, reso
13288
13507
  break;
13289
13508
  }
13290
13509
  case "CASE_COL":
13291
- 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));
13292
13511
  break;
13293
13512
  case "SCALAR_VALUE_COL": {
13294
13513
  const source = scalarValueDefaultKey(column.expr);
@@ -13377,7 +13596,7 @@ function evaluateSelectColumnValue(column, row, columnIndex, context = {}) {
13377
13596
  case "ARITH_COL":
13378
13597
  return String(evalArithExpr(column.expr, row));
13379
13598
  case "CASE_COL":
13380
- return evalCaseWhen(
13599
+ return containsAggregate2(column.expr) ? row[caseMaterializedKey(column.alias, columnIndex)] ?? "" : evalCaseWhen(
13381
13600
  column.expr,
13382
13601
  row,
13383
13602
  context.resolveFieldType,
@@ -13442,13 +13661,14 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13442
13661
  return { rows: projected2, columns: cols };
13443
13662
  }
13444
13663
  const defaultFieldKeys = buildDefaultFieldOutputKeys(columns);
13664
+ const defaultCaseKeys = buildDefaultCaseOutputKeys(columns);
13445
13665
  const hasWildcard = columns.some(
13446
13666
  (col) => col.type === "WILDCARD" || col.type === "PARENT_WILDCARD"
13447
13667
  );
13448
- const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys);
13668
+ const outputKeys = hasWildcard ? null : computeOutputKeys(columns, defaultFieldKeys, defaultCaseKeys);
13449
13669
  const orderedKeys = outputKeys ?? [];
13450
13670
  if (hasWildcard && rows.length === 0) {
13451
- return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys) };
13671
+ return { rows: [], columns: computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) };
13452
13672
  }
13453
13673
  const projected = rows.map((row, rowIdx) => {
13454
13674
  const out = {};
@@ -13515,7 +13735,7 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13515
13735
  break;
13516
13736
  }
13517
13737
  case "CASE_COL": {
13518
- const key = outputKeys?.[colIdx] ?? col.alias ?? "case";
13738
+ const key = outputKeys?.[colIdx] ?? col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13519
13739
  out[key] = value;
13520
13740
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
13521
13741
  break;
@@ -13556,15 +13776,15 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns2, r
13556
13776
  });
13557
13777
  return { rows: projected, columns: orderedKeys };
13558
13778
  }
13559
- function computeOutputKeys(columns, defaultFieldKeys) {
13560
- 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));
13561
13781
  }
13562
- function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13782
+ function computeExplicitOutputKeys(columns, defaultFieldKeys, defaultCaseKeys) {
13563
13783
  const keys = [];
13564
13784
  const seen = /* @__PURE__ */ new Set();
13565
13785
  for (const [colIdx, col] of columns.entries()) {
13566
13786
  if (col.type === "WILDCARD" || col.type === "PARENT_WILDCARD") continue;
13567
- const key = computeOutputKey(col, colIdx, defaultFieldKeys);
13787
+ const key = computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys);
13568
13788
  if (!seen.has(key)) {
13569
13789
  seen.add(key);
13570
13790
  keys.push(key);
@@ -13572,7 +13792,7 @@ function computeExplicitOutputKeys(columns, defaultFieldKeys) {
13572
13792
  }
13573
13793
  return keys;
13574
13794
  }
13575
- function computeOutputKey(col, colIdx, defaultFieldKeys) {
13795
+ function computeOutputKey(col, colIdx, defaultFieldKeys, defaultCaseKeys) {
13576
13796
  switch (col.type) {
13577
13797
  case "VARIABLE_COL":
13578
13798
  throw new Error(`internal error: unresolved SELECT variable @${col.name}`);
@@ -13587,7 +13807,7 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13587
13807
  case "ARITH_COL":
13588
13808
  return col.alias ?? arithColDefaultKey(col.expr);
13589
13809
  case "CASE_COL":
13590
- return col.alias ?? "case";
13810
+ return col.alias ?? defaultCaseKeys.get(colIdx) ?? "case";
13591
13811
  case "STRFUNC_COL":
13592
13812
  return col.alias ?? stringFuncDefaultKey(col.expr);
13593
13813
  case "SCALAR_VALUE_COL":
@@ -13603,6 +13823,24 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
13603
13823
  throw new Error("internal: computeOutputKey received a wildcard column");
13604
13824
  }
13605
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
+ }
13606
13844
  function buildDefaultFieldOutputKeys(columns) {
13607
13845
  const qualifierCollisionCount = /* @__PURE__ */ new Map();
13608
13846
  for (const col of columns) {
@@ -13692,6 +13930,7 @@ function scalarValueHasAggregate2(expr) {
13692
13930
  return false;
13693
13931
  }
13694
13932
  function caseResultHasAggregate2(result) {
13933
+ if (result.type === "AGG_REF" || result.type === "AGG_ARITH") return true;
13695
13934
  if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
13696
13935
  return scalarValueHasAggregate2(result);
13697
13936
  }
@@ -13714,6 +13953,7 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
13714
13953
  }
13715
13954
  function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13716
13955
  if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
13956
+ if (expr.type === "CASE_WHEN") return resolveAggInCaseExpr(expr, rows, resolveAggSortKind);
13717
13957
  if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
13718
13958
  return {
13719
13959
  ...expr,
@@ -13723,6 +13963,35 @@ function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
13723
13963
  }
13724
13964
  return expr;
13725
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
+ }
13726
13995
  function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
13727
13996
  return {
13728
13997
  type: "STRING_FUNC",
@@ -13845,7 +14114,8 @@ function runFullScan(input) {
13845
14114
  }
13846
14115
  );
13847
14116
  }
13848
- 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);
13849
14119
  rows = applyWindow(rows, stmt.columns, optionOrders, sortKinds, effectiveOrderSemantics);
13850
14120
  if (stmt.distinct) {
13851
14121
  rows = applyDistinct(
@@ -17387,7 +17657,7 @@ function scalarValueHasFieldRef(expr) {
17387
17657
  }
17388
17658
  if (expr.type === "CASE_WHEN") {
17389
17659
  const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
17390
- 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)));
17391
17661
  }
17392
17662
  return false;
17393
17663
  }
@@ -17939,7 +18209,8 @@ function collectAggregateArgFieldRefs(arg, out) {
17939
18209
  }
17940
18210
  if (arg.type === "CASE_WHEN") {
17941
18211
  for (const result of [...arg.branches.map((branch) => branch.result), ...arg.elseResult ? [arg.elseResult] : []]) {
17942
- 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);
17943
18214
  }
17944
18215
  }
17945
18216
  }
@@ -17976,10 +18247,29 @@ function collectScalarAggregateRefs(expr, out) {
17976
18247
  const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
17977
18248
  for (const result of results) {
17978
18249
  if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
18250
+ else if (result.type === "AGG_REF" || result.type === "AGG_ARITH") collectAggregateOperandRefs(result, out);
17979
18251
  else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
17980
18252
  }
17981
18253
  }
17982
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
+ }
17983
18273
  function collectSelectAggregateSortRefs(columns) {
17984
18274
  const refs = [];
17985
18275
  for (const column of columns) {
@@ -17991,6 +18281,8 @@ function collectSelectAggregateSortRefs(columns) {
17991
18281
  collectStringFuncAggregateRefs(column.expr, refs);
17992
18282
  } else if (column.type === "SCALAR_VALUE_COL") {
17993
18283
  collectScalarAggregateRefs(column.expr, refs);
18284
+ } else if (column.type === "CASE_COL") {
18285
+ collectCaseAggregateRefs(column.expr, refs);
17994
18286
  }
17995
18287
  }
17996
18288
  return refs;
@@ -18168,6 +18460,13 @@ function stringFunctionColumnMeta(expr) {
18168
18460
  function caseResultColumnMeta(result, resolveField2) {
18169
18461
  if (result.type === "STRING") return syntheticColumnMeta("string");
18170
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");
18171
18470
  if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
18172
18471
  if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
18173
18472
  if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();