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