@rex0220/kintone-sql-tools 3.56.2 → 3.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist-cli/ksql.js CHANGED
@@ -604,7 +604,7 @@ function expandCubeGroupingSets(items) {
604
604
  if (expandedSetCount > Math.floor(B65_MAX_GROUPING_SETS / 2)) {
605
605
  const rejectedSetCount = expandedSetCount * 2;
606
606
  throw new Error(
607
- `ArgumentError: B65 expanded grouping set count ${rejectedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
607
+ `ArgumentError: expanded grouping set count ${rejectedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
608
608
  );
609
609
  }
610
610
  expandedSetCount *= 2;
@@ -5622,26 +5622,488 @@ function evalGroupingRef(ref, row) {
5622
5622
  return membership.has(canonicalId) ? "0" : "1";
5623
5623
  }
5624
5624
 
5625
+ // src/core/systemFields.ts
5626
+ var APP_SYSTEM_FIELD_CODES = [
5627
+ "$id",
5628
+ "$revision",
5629
+ "\u30EC\u30B3\u30FC\u30C9\u756A\u53F7",
5630
+ "\u4F5C\u6210\u8005",
5631
+ "\u4F5C\u6210\u65E5\u6642",
5632
+ "\u66F4\u65B0\u8005",
5633
+ "\u66F4\u65B0\u65E5\u6642",
5634
+ "\u30B9\u30C6\u30FC\u30BF\u30B9",
5635
+ "\u4F5C\u696D\u8005"
5636
+ ];
5637
+ function isSystemLikeFieldCode(code) {
5638
+ return code.startsWith("_") || code.startsWith("$");
5639
+ }
5640
+
5641
+ // src/core/optimization/plainGroupByPlan.ts
5642
+ var AGGREGATE_REFERENCE_PREFIX = /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/;
5643
+ function containsAggregateColumnNode(node) {
5644
+ if (node === null || typeof node !== "object") return false;
5645
+ if (Array.isArray(node)) return node.some(containsAggregateColumnNode);
5646
+ const value = node;
5647
+ if (value["type"] === "AGGREGATE" || value["type"] === "ARITH_AGG_COL") return true;
5648
+ if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
5649
+ if (value["type"] === "FIELD" && typeof value["field"] === "string") {
5650
+ return AGGREGATE_REFERENCE_PREFIX.test(value["field"]);
5651
+ }
5652
+ return Object.values(value).some(containsAggregateColumnNode);
5653
+ }
5654
+ function classifyPreGroupAlias(column) {
5655
+ switch (column.type) {
5656
+ case "AGGREGATE":
5657
+ case "ARITH_AGG_COL":
5658
+ return "AGGREGATE_DEPENDENT";
5659
+ case "GROUPING_COL":
5660
+ case "WINDOW_COL":
5661
+ return "POST_GROUP_ONLY";
5662
+ case "VARIABLE_COL":
5663
+ throw new Error("InternalError: unresolved VARIABLE_COL reached GROUP BY alias planning.");
5664
+ case "WILDCARD":
5665
+ case "PARENT_WILDCARD":
5666
+ case "FIELD":
5667
+ case "LITERAL_COL":
5668
+ case "ARITH_COL":
5669
+ case "CASE_COL":
5670
+ case "STRFUNC_COL":
5671
+ case "SCALAR_VALUE_COL":
5672
+ case "SCALAR_SUBQUERY_COL":
5673
+ return containsAggregate2(column) || containsAggregateColumnNode(column) ? "AGGREGATE_DEPENDENT" : "SAFE";
5674
+ }
5675
+ }
5676
+ var SUBTABLE_SYSTEM_COLUMNS = ["_pid", "_rid", "_idx"];
5677
+ function unique(values) {
5678
+ return [...new Set(values)];
5679
+ }
5680
+ function sourceColumns(input) {
5681
+ switch (input.kind) {
5682
+ case "APP":
5683
+ return unique([
5684
+ ...input.fieldCodes,
5685
+ ...APP_SYSTEM_FIELD_CODES
5686
+ ]);
5687
+ case "SUBTABLE":
5688
+ return unique([
5689
+ ...input.childFieldCodes,
5690
+ ...SUBTABLE_SYSTEM_COLUMNS,
5691
+ ...input.parentFieldCodes.map((field) => `_p.${field}`)
5692
+ ]);
5693
+ case "MATERIALIZED":
5694
+ return unique(input.columns);
5695
+ }
5696
+ }
5697
+ function resolvePlainGroupBySourceSchemas(stmt, lookup) {
5698
+ const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
5699
+ return sources.map((source, sourceIndex) => ({
5700
+ sourceIndex,
5701
+ qualifier: source.alias ?? source.cteName,
5702
+ columns: sourceColumns(lookup(source, sourceIndex))
5703
+ }));
5704
+ }
5705
+ function parseGroupName(name) {
5706
+ if (name.startsWith("_p.")) return { qualifier: null, fieldCode: name };
5707
+ const dot = name.indexOf(".");
5708
+ if (dot <= 0 || dot === name.length - 1) {
5709
+ return { qualifier: null, fieldCode: name };
5710
+ }
5711
+ return { qualifier: name.slice(0, dot), fieldCode: name.slice(dot + 1) };
5712
+ }
5713
+ function runtimeKey(source, fieldCode) {
5714
+ return source.qualifier === null ? fieldCode : `${source.qualifier}.${fieldCode}`;
5715
+ }
5716
+ function resolvePlainFieldReference(ref, schemas) {
5717
+ const name = ref.tableAlias === null ? ref.field : `${ref.tableAlias}.${ref.field}`;
5718
+ const parsed = ref.tableAlias === null ? parseGroupName(ref.field) : { qualifier: ref.tableAlias, fieldCode: ref.field };
5719
+ const candidateSources = parsed.qualifier === null ? schemas : schemas.filter((source2) => source2.qualifier === parsed.qualifier);
5720
+ const physical = candidateSources.filter((source2) => source2.columns.includes(parsed.fieldCode));
5721
+ if (physical.length > 1) return { kind: "AMBIGUOUS", name };
5722
+ if (physical.length === 0) return { kind: "UNKNOWN", name };
5723
+ const source = physical[0];
5724
+ return {
5725
+ kind: "PHYSICAL",
5726
+ sourceIndex: source.sourceIndex,
5727
+ fieldCode: parsed.fieldCode,
5728
+ runtimeKey: runtimeKey(source, parsed.fieldCode)
5729
+ };
5730
+ }
5731
+ function explicitAlias(column) {
5732
+ return "alias" in column && typeof column.alias === "string" ? column.alias : null;
5733
+ }
5734
+ function resolveFieldName(name, columns, schemas) {
5735
+ const parsed = parseGroupName(name);
5736
+ const candidateSources = parsed.qualifier === null ? schemas : schemas.filter((source) => source.qualifier === parsed.qualifier);
5737
+ const physical = candidateSources.filter((source) => source.columns.includes(parsed.fieldCode));
5738
+ if (physical.length > 1) {
5739
+ throw new Error(
5740
+ `ArgumentError: GROUP BY field ${name} is ambiguous across multiple sources (reason=GROUP_BY_FIELD_AMBIGUOUS).`
5741
+ );
5742
+ }
5743
+ if (physical.length === 1) {
5744
+ const source = physical[0];
5745
+ return {
5746
+ kind: "PHYSICAL",
5747
+ sourceIndex: source.sourceIndex,
5748
+ fieldCode: parsed.fieldCode,
5749
+ runtimeKey: runtimeKey(source, parsed.fieldCode)
5750
+ };
5751
+ }
5752
+ if (parsed.qualifier !== null) return { kind: "UNKNOWN", name };
5753
+ const aliases = columns.flatMap(
5754
+ (column, columnIndex) => explicitAlias(column) === name ? [{ column, columnIndex }] : []
5755
+ );
5756
+ if (aliases.length > 1) return { kind: "ALIAS_REJECT", reason: "DUPLICATE" };
5757
+ if (aliases.length === 1) {
5758
+ const candidate = aliases[0];
5759
+ const classification = classifyPreGroupAlias(candidate.column);
5760
+ if (classification === "SAFE") {
5761
+ return { kind: "ALIAS_SAFE", columnIndex: candidate.columnIndex };
5762
+ }
5763
+ return {
5764
+ kind: "ALIAS_REJECT",
5765
+ reason: classification === "AGGREGATE_DEPENDENT" ? "AGGREGATE" : "POST_GROUP_ONLY"
5766
+ };
5767
+ }
5768
+ const aggregateSyntheticMatch = columns.some(
5769
+ (column) => column.type === "AGGREGATE" && column.alias === null && aggregateSyntheticName(column.func, column.distinct, column.arg) === name
5770
+ );
5771
+ if (aggregateSyntheticMatch) return { kind: "ALIAS_REJECT", reason: "AGGREGATE" };
5772
+ return { kind: "UNKNOWN", name };
5773
+ }
5774
+ function planPlainGroupByResolution(groupBy, columns, schemas) {
5775
+ return {
5776
+ items: groupBy.map(
5777
+ (key) => key.type === "FIELD_NAME" ? resolveFieldName(key.name, columns, schemas) : { kind: "EXPRESSION" }
5778
+ )
5779
+ };
5780
+ }
5781
+
5782
+ // src/core/aggregateDependencyValidation.ts
5783
+ var NON_GROUPED_DEPENDENCY_REASON = "B65_NON_GROUPED_DEPENDENCY";
5784
+ var WRAPPER_EXPR = /* @__PURE__ */ new Map([
5785
+ ["ARITH_COL", "expr"],
5786
+ ["ARITH_AGG_COL", "expr"],
5787
+ ["STRFUNC_COL", "expr"],
5788
+ ["SCALAR_VALUE_COL", "expr"],
5789
+ ["CASE_COL", "expr"],
5790
+ ["ARITH_KEY", "expr"],
5791
+ ["FUNC_KEY", "expr"],
5792
+ ["FUNC_FIELD", "expr"],
5793
+ ["ARITH_FIELD", "expr"],
5794
+ ["CASE_FIELD", "expr"],
5795
+ ["ARITH_VALUE", "expr"],
5796
+ ["CASE_VALUE", "expr"],
5797
+ ["AGG_FIELD", "expr"]
5798
+ ]);
5799
+ function refFromName(name) {
5800
+ if (name.startsWith("_p.")) return { type: "FIELD", tableAlias: null, field: name };
5801
+ const dot = name.indexOf(".");
5802
+ return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
5803
+ }
5804
+ function fieldRefFromNode(value) {
5805
+ const type = value["type"];
5806
+ if (type === "FIELD_REF" && typeof value["field"] === "string") {
5807
+ return refFromName(value["field"]);
5808
+ }
5809
+ if (type === "AGG_GROUP_KEY" && typeof value["field"] === "string") {
5810
+ return {
5811
+ type: "FIELD",
5812
+ tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
5813
+ field: value["field"]
5814
+ };
5815
+ }
5816
+ if (type === "FIELD" && typeof value["field"] === "string") {
5817
+ if (value["aggregateRef"] !== void 0) return null;
5818
+ const tableAlias = typeof value["tableAlias"] === "string" ? value["tableAlias"] : null;
5819
+ return tableAlias === null ? refFromName(value["field"]) : {
5820
+ type: "FIELD",
5821
+ tableAlias,
5822
+ field: value["field"]
5823
+ };
5824
+ }
5825
+ return null;
5826
+ }
5827
+ function isQueryBoundary(value) {
5828
+ return value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY" || value["type"] === "SCALAR_SUBQUERY_COL" || value["type"] === "SUBQUERY_IN_LIST" || value["type"] === "EXISTS";
5829
+ }
5830
+ function isAggregateBoundary(value) {
5831
+ return value["type"] === "AGGREGATE" || value["type"] === "AGG_REF";
5832
+ }
5833
+ function isWindowBoundary(value) {
5834
+ return value["type"] === "WINDOW_COL";
5835
+ }
5836
+ function numberMeaning(value) {
5837
+ const number = value["value"];
5838
+ if (typeof number !== "number") return "?";
5839
+ if (Object.is(number, -0)) return "0";
5840
+ return String(number);
5841
+ }
5842
+ function canonicalExpression(node, resolveField2) {
5843
+ if (node === null) return "null";
5844
+ if (typeof node === "string" || typeof node === "boolean") return JSON.stringify(node);
5845
+ if (typeof node === "number") return String(node);
5846
+ if (Array.isArray(node)) {
5847
+ const items = node.map((item) => canonicalExpression(item, resolveField2));
5848
+ return items.some((item) => item === null) ? null : `[${items.join(",")}]`;
5849
+ }
5850
+ if (typeof node !== "object") return null;
5851
+ const value = node;
5852
+ const type = value["type"];
5853
+ if (type === "VARIABLE" || type === "VARIABLE_COL" || isQueryBoundary(value)) return null;
5854
+ if (type === "GROUP" && value["expr"] !== void 0) {
5855
+ return canonicalExpression(value["expr"], resolveField2);
5856
+ }
5857
+ const wrapper = typeof type === "string" ? WRAPPER_EXPR.get(type) : void 0;
5858
+ if (wrapper !== void 0) return canonicalExpression(value[wrapper], resolveField2);
5859
+ if (type === "LITERAL_COL") return `STRING:${JSON.stringify(value["value"] ?? "")}`;
5860
+ if (type === "STRING") return `STRING:${JSON.stringify(value["value"] ?? "")}`;
5861
+ if (type === "NUMBER") return `NUMBER:${numberMeaning(value)}`;
5862
+ if (type === "BOOLEAN") return `BOOLEAN:${String(value["value"])}`;
5863
+ const ref = fieldRefFromNode(value);
5864
+ if (ref !== null) {
5865
+ try {
5866
+ return `FIELD:${resolveField2(ref)}`;
5867
+ } catch {
5868
+ return null;
5869
+ }
5870
+ }
5871
+ if (type === "FIELD" && value["aggregateRef"] !== void 0) return null;
5872
+ const ignored = /* @__PURE__ */ new Set([
5873
+ "alias",
5874
+ "aliasDisplay",
5875
+ "raw",
5876
+ "separator",
5877
+ "distinct",
5878
+ "source"
5879
+ ]);
5880
+ const parts = [];
5881
+ for (const key of Object.keys(value)) {
5882
+ if (key === "type" || ignored.has(key)) continue;
5883
+ const child = canonicalExpression(value[key], resolveField2);
5884
+ if (child === null) return null;
5885
+ parts.push(`${key}=${child}`);
5886
+ }
5887
+ const semanticType = type === "ARITH" || type === "SCALAR_ARITH" ? "ARITH" : String(type ?? "OBJECT");
5888
+ return `${semanticType}(${parts.join(",")})`;
5889
+ }
5890
+ function explicitAlias2(column) {
5891
+ return "alias" in column && typeof column.alias === "string" ? column.alias : null;
5892
+ }
5893
+ function aliasesByName(columns) {
5894
+ const result = /* @__PURE__ */ new Map();
5895
+ for (const column of columns) {
5896
+ const alias = explicitAlias2(column);
5897
+ if (alias === null) continue;
5898
+ result.set(alias, [...result.get(alias) ?? [], column]);
5899
+ }
5900
+ return result;
5901
+ }
5902
+ function displayField(ref) {
5903
+ return ref.tableAlias === null ? ref.field : `${ref.tableAlias}.${ref.field}`;
5904
+ }
5905
+ var AGGREGATE_SYNTHETIC_REFERENCE = /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/;
5906
+ function displayExpression(node) {
5907
+ if (node && typeof node === "object") {
5908
+ const value = node;
5909
+ const ref = fieldRefFromNode(value);
5910
+ if (ref !== null) return displayField(ref);
5911
+ if (value["type"] === "FIELD_NAME" && typeof value["name"] === "string") return value["name"];
5912
+ if (value["type"] === "WILDCARD") return "*";
5913
+ if (value["type"] === "PARENT_WILDCARD") return "_p.*";
5914
+ const alias = value["alias"];
5915
+ if (typeof alias === "string" && alias.length > 0) return alias;
5916
+ const wrapper = typeof value["type"] === "string" ? WRAPPER_EXPR.get(value["type"]) : void 0;
5917
+ if (wrapper !== void 0) {
5918
+ const inner = displayExpression(value[wrapper]);
5919
+ if (inner !== "\u5F0F") return inner;
5920
+ }
5921
+ const func = value["func"];
5922
+ if (typeof func === "string" && func.length > 0) return `${func}(...)`;
5923
+ }
5924
+ return "\u5F0F";
5925
+ }
5926
+ function dependencyError(clause, expression, dependency, policy) {
5927
+ const dependencyLabel = dependency === "WILDCARD" ? "wildcard" : displayField(dependency);
5928
+ const expressionLabel = dependency === "WILDCARD" ? displayExpression(expression) : displayExpression(expression);
5929
+ const groupText = policy.groupingLabel === null ? "GROUP BY \u304C\u306A\u3044\u305F\u3081\u5165\u529B\u5168\u4F53\u304C1\u30B0\u30EB\u30FC\u30D7\u306B\u306A\u308A" : `${policy.groupingLabel} \u306E\u5404\u30B0\u30EB\u30FC\u30D7\u3067\u306F`;
5930
+ const migration = dependency === "WILDCARD" ? "\u5FC5\u8981\u306A grouping \u5217\u3092\u660E\u793A\u3057\u3066 SELECT \u3057\u3066\u304F\u3060\u3055\u3044\u3002" : `\u300C${dependencyLabel}\u300D\u3092 MIN() \u306A\u3069\u306E\u96C6\u8A08\u95A2\u6570\u3067\u5305\u3080\u304B\u3001GROUP BY \u3078\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002`;
5931
+ const concreteMigration = dependency !== "WILDCARD" && dependency.tableAlias === null && expressionLabel === dependencyLabel && policy.migrationSourceSql !== void 0 ? policy.migrationGroupingFields && policy.migrationGroupingFields.length > 0 ? ` \u5B9F\u884C\u53EF\u80FD\u306A\u66F8\u304D\u63DB\u3048\u4F8B: \u300CSELECT ${policy.migrationGroupingFields.join(", ")}, MIN(${dependencyLabel}) FROM ${policy.migrationSourceSql} GROUP BY ${policy.migrationGroupingFields.join(", ")}\u300D\u3002` : ` \u5B9F\u884C\u53EF\u80FD\u306A\u66F8\u304D\u63DB\u3048\u4F8B: \u300CSELECT MIN(${dependencyLabel}) FROM ${policy.migrationSourceSql}\u300D\u3002` : "";
5932
+ return new Error(
5933
+ `ArgumentError: ${clause} \u5F0F\u300C${expressionLabel}\u300D\u306F\u96C6\u8A08\u3082\u30B0\u30EB\u30FC\u30D7\u5316\u3082\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF08${policy.sourceLabel}\u3001\u975E\u30B0\u30EB\u30FC\u30D7\u5316\u4F9D\u5B58: ${dependencyLabel}\uFF09\u3002${groupText}\u3001\u3069\u306E\u884C\u306E\u5024\u3092\u8FD4\u3059\u304B\u6C7A\u307E\u308A\u307E\u305B\u3093\u3002${migration}${concreteMigration} (reason=${NON_GROUPED_DEPENDENCY_REASON})`
5934
+ );
5935
+ }
5936
+ function walkDependency(node, context) {
5937
+ if (node === null || typeof node !== "object") return;
5938
+ if (Array.isArray(node)) {
5939
+ for (const child of node) walkDependency(child, context);
5940
+ return;
5941
+ }
5942
+ const value = node;
5943
+ if (isQueryBoundary(value) || isAggregateBoundary(value) || isWindowBoundary(value)) return;
5944
+ if (value["type"] === "GROUPING_REF" || value["type"] === "GROUPING_FIELD" || value["type"] === "GROUPING_COL" || value["type"] === "GROUPING_KEY") return;
5945
+ if (value["type"] === "WILDCARD" || value["type"] === "PARENT_WILDCARD") {
5946
+ throw dependencyError(context.clause, context.expression, "WILDCARD", context.policy);
5947
+ }
5948
+ const ref = fieldRefFromNode(value);
5949
+ if (ref !== null) {
5950
+ if (context.clause !== "SELECT" && ref.tableAlias === null && AGGREGATE_SYNTHETIC_REFERENCE.test(ref.field)) return;
5951
+ if (context.clause !== "SELECT" && ref.tableAlias === null) {
5952
+ const targets = context.aliases.get(ref.field) ?? [];
5953
+ if (targets.length === 1 && !context.resolvingAliases.has(ref.field)) {
5954
+ const resolvingAliases = new Set(context.resolvingAliases);
5955
+ resolvingAliases.add(ref.field);
5956
+ walkDependency(targets[0], { ...context, resolvingAliases });
5957
+ return;
5958
+ }
5959
+ }
5960
+ const canonical2 = canonicalExpression(value, context.policy.resolveField);
5961
+ if (canonical2 !== null && context.policy.identities.has(canonical2)) return;
5962
+ const identity = `FIELD:${context.policy.resolveField(ref)}`;
5963
+ if (!context.policy.identities.has(identity)) {
5964
+ throw dependencyError(context.clause, context.expression, ref, context.policy);
5965
+ }
5966
+ return;
5967
+ }
5968
+ const canonical = canonicalExpression(value, context.policy.resolveField);
5969
+ if (canonical !== null && context.policy.identities.has(canonical)) return;
5970
+ const wrapper = typeof value["type"] === "string" ? WRAPPER_EXPR.get(value["type"]) : void 0;
5971
+ if (wrapper !== void 0) {
5972
+ walkDependency(value[wrapper], context);
5973
+ return;
5974
+ }
5975
+ for (const key of Object.keys(value)) {
5976
+ if (key === "type" || key === "alias" || key === "aliasDisplay" || key === "raw") continue;
5977
+ walkDependency(value[key], context);
5978
+ }
5979
+ }
5980
+ function validateAggregateDependencies(stmt, policy) {
5981
+ const aliases = aliasesByName(stmt.columns);
5982
+ for (const column of stmt.columns) {
5983
+ if (column.type === "WINDOW_COL") continue;
5984
+ walkDependency(column, {
5985
+ clause: "SELECT",
5986
+ expression: column,
5987
+ policy,
5988
+ aliases,
5989
+ resolvingAliases: /* @__PURE__ */ new Set()
5990
+ });
5991
+ }
5992
+ if (stmt.having !== null) {
5993
+ walkDependency(stmt.having, {
5994
+ clause: "HAVING",
5995
+ expression: stmt.having,
5996
+ policy,
5997
+ aliases,
5998
+ resolvingAliases: /* @__PURE__ */ new Set()
5999
+ });
6000
+ }
6001
+ for (const order of stmt.orderBy) {
6002
+ const key = order.key.type === "FIELD_NAME" ? refFromName(order.key.name) : order.key;
6003
+ walkDependency(key, {
6004
+ clause: "ORDER BY",
6005
+ expression: key,
6006
+ policy,
6007
+ aliases,
6008
+ resolvingAliases: /* @__PURE__ */ new Set()
6009
+ });
6010
+ }
6011
+ }
6012
+ function hasAggregateNode(node) {
6013
+ if (node === null || typeof node !== "object") return false;
6014
+ if (Array.isArray(node)) return node.some(hasAggregateNode);
6015
+ const value = node;
6016
+ if (isQueryBoundary(value) || isWindowBoundary(value)) return false;
6017
+ if (isAggregateBoundary(value) || value["type"] === "ARITH_AGG_COL") return true;
6018
+ return Object.values(value).some(hasAggregateNode);
6019
+ }
6020
+ function isAggregateQueryBlock(stmt) {
6021
+ return normalizeGroupingSpec(stmt).type !== "NONE" || stmt.columns.some((column) => column.type !== "WINDOW_COL" && hasAggregateNode(column));
6022
+ }
6023
+ function groupByKeyNode(key) {
6024
+ if (key.type === "FIELD_NAME") return refFromName(key.name);
6025
+ return key.expr;
6026
+ }
6027
+ function buildOrdinaryDependencyPolicy(stmt, plan, schemas) {
6028
+ const normalized = normalizeGroupingSpec(stmt);
6029
+ if (normalized.type !== "PLAIN") {
6030
+ throw new Error("InternalError: ordinary dependency policy requires plain GROUP BY.");
6031
+ }
6032
+ const groupBy = normalized.allItems;
6033
+ const resolveField2 = (ref) => {
6034
+ const resolution = resolvePlainFieldReference(ref, schemas);
6035
+ if (resolution.kind === "AMBIGUOUS") {
6036
+ throw new Error(`ArgumentError: field ${resolution.name} is ambiguous across multiple sources.`);
6037
+ }
6038
+ if (resolution.kind === "UNKNOWN") return `unknown:${resolution.name}`;
6039
+ return `source:${resolution.sourceIndex}:${resolution.fieldCode}`;
6040
+ };
6041
+ const identities = /* @__PURE__ */ new Set();
6042
+ plan.items.forEach((item, index) => {
6043
+ if (item.kind === "PHYSICAL") {
6044
+ identities.add(`FIELD:source:${item.sourceIndex}:${item.fieldCode}`);
6045
+ return;
6046
+ }
6047
+ if (item.kind === "ALIAS_SAFE") {
6048
+ const key = canonicalExpression(stmt.columns[item.columnIndex], resolveField2);
6049
+ if (key !== null) identities.add(key);
6050
+ return;
6051
+ }
6052
+ if (item.kind === "EXPRESSION") {
6053
+ const key = canonicalExpression(groupByKeyNode(groupBy[index]), resolveField2);
6054
+ if (key !== null) identities.add(key);
6055
+ }
6056
+ });
6057
+ const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
6058
+ const sourceSql = (source) => `APP${source.appId}${source.subtableCode != null ? `$${source.subtableCode}` : ""}`;
6059
+ const sourceLabel = sources.map((source) => source.cteName ?? sourceSql(source)).join(" / ");
6060
+ const groupingLabel = `GROUP BY ${groupBy.map(
6061
+ (key) => key.type === "FIELD_NAME" ? key.name : displayExpression(key)
6062
+ ).join(", ")}`;
6063
+ const directAppSource = sources.length === 1 && sources[0].cteName === null ? `${sourceSql(sources[0])}${sources[0].alias && sources[0].alias !== sourceSql(sources[0]) ? ` ${sources[0].alias}` : ""}` : void 0;
6064
+ const migrationGroupingFields = groupBy.every(
6065
+ (key, index) => key.type === "FIELD_NAME" && plan.items[index]?.kind === "PHYSICAL"
6066
+ ) ? groupBy.map((key) => key.name) : void 0;
6067
+ return {
6068
+ identities,
6069
+ resolveField: resolveField2,
6070
+ sourceLabel,
6071
+ groupingLabel,
6072
+ migrationSourceSql: directAppSource,
6073
+ migrationGroupingFields
6074
+ };
6075
+ }
6076
+ function validateAggregateDependenciesStatic(stmt) {
6077
+ if (normalizeGroupingSpec(stmt).type !== "NONE" || !isAggregateQueryBlock(stmt)) return;
6078
+ const policy = {
6079
+ identities: /* @__PURE__ */ new Set(),
6080
+ resolveField: (ref) => `ast:${displayField(ref)}`,
6081
+ sourceLabel: stmt.from.cteName ?? `APP${stmt.from.appId}`,
6082
+ groupingLabel: null,
6083
+ migrationSourceSql: stmt.from.cteName === null && stmt.joins.length === 0 ? `APP${stmt.from.appId}${stmt.from.alias && stmt.from.alias !== `APP${stmt.from.appId}` ? ` ${stmt.from.alias}` : ""}` : void 0
6084
+ };
6085
+ validateAggregateDependencies(stmt, policy);
6086
+ }
6087
+ function canonicalGroupingFieldIdentity(canonicalId) {
6088
+ return `FIELD:${canonicalId}`;
6089
+ }
6090
+
5625
6091
  // src/core/groupingValidation.ts
5626
6092
  var enforceGroupingPlanningCandidateLimits = (facts) => {
5627
6093
  if (facts.expandedSetCount > B65_MAX_GROUPING_SETS) {
5628
6094
  throw new Error(
5629
- `ArgumentError: B65 expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
6095
+ `ArgumentError: expanded grouping set count ${facts.expandedSetCount} exceeds limit ${B65_MAX_GROUPING_SETS} (reason=GROUPING_SET_LIMIT_EXCEEDED).`
5630
6096
  );
5631
6097
  }
5632
6098
  if (facts.canonicalItemCount > B65_MAX_GROUPING_ITEMS) {
5633
6099
  throw new Error(
5634
- `ArgumentError: B65 canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
6100
+ `ArgumentError: canonical grouping item count ${facts.canonicalItemCount} exceeds limit ${B65_MAX_GROUPING_ITEMS} (reason=GROUPING_ITEM_LIMIT_EXCEEDED).`
5635
6101
  );
5636
6102
  }
5637
6103
  };
5638
- function displayField(field) {
6104
+ function displayField2(field) {
5639
6105
  return field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
5640
6106
  }
5641
- function refFromName(name) {
5642
- const dot = name.indexOf(".");
5643
- return dot > 0 ? { type: "FIELD", tableAlias: name.slice(0, dot), field: name.slice(dot + 1) } : { type: "FIELD", tableAlias: null, field: name };
5644
- }
5645
6107
  function collectGroupingRefs(node, out) {
5646
6108
  if (node === null || typeof node !== "object") return;
5647
6109
  if (Array.isArray(node)) {
@@ -5670,30 +6132,6 @@ function collectAggregateArgumentGroupingRefs(node, out) {
5670
6132
  }
5671
6133
  Object.values(value).forEach((item) => collectAggregateArgumentGroupingRefs(item, out));
5672
6134
  }
5673
- function collectNonAggregateFieldRefs(node, out) {
5674
- if (node === null || typeof node !== "object") return;
5675
- if (Array.isArray(node)) {
5676
- node.forEach((item) => collectNonAggregateFieldRefs(item, out));
5677
- return;
5678
- }
5679
- const value = node;
5680
- const type = value["type"];
5681
- if (type === "SELECT" || type === "SCALAR_SUBQUERY" || type === "GROUPING_REF" || type === "AGG_REF" || type === "AGG_ARITH") return;
5682
- if (type === "FIELD" && value["aggregateRef"] !== void 0) return;
5683
- if (type === "FIELD" && typeof value["field"] === "string") {
5684
- out.push({
5685
- type: "FIELD",
5686
- tableAlias: typeof value["tableAlias"] === "string" ? value["tableAlias"] : null,
5687
- field: value["field"]
5688
- });
5689
- return;
5690
- }
5691
- if (type === "FIELD_REF" && typeof value["field"] === "string") {
5692
- out.push(refFromName(value["field"]));
5693
- return;
5694
- }
5695
- Object.values(value).forEach((item) => collectNonAggregateFieldRefs(item, out));
5696
- }
5697
6135
  function containsAggregate2(node) {
5698
6136
  if (node === null || typeof node !== "object") return false;
5699
6137
  if (Array.isArray(node)) return node.some(containsAggregate2);
@@ -5710,41 +6148,18 @@ function isAggregateMaterializedAlias(column) {
5710
6148
  }
5711
6149
  return false;
5712
6150
  }
5713
- function outputAliases(columns) {
5714
- return new Set(columns.flatMap(
5715
- (column) => "alias" in column && typeof column.alias === "string" ? [column.alias] : []
5716
- ));
5717
- }
5718
- function isAggregateSyntheticReference(ref) {
5719
- return ref.tableAlias === null && /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/.test(ref.field);
5720
- }
5721
6151
  function validateGroupingRefMembership(ref, resolve2, canonicalItems) {
5722
6152
  const resolved = resolve2(ref.field);
5723
6153
  if (!resolved.physical) {
5724
- throw new Error(`ArgumentError: B65 grouping reference ${displayField(ref.field)} must resolve to a physical APP field.`);
6154
+ throw new Error(`ArgumentError: grouping reference ${displayField2(ref.field)} must resolve to a physical APP field.`);
5725
6155
  }
5726
6156
  if (!canonicalItems.has(resolved.canonicalId)) {
5727
6157
  throw new Error(
5728
- `ArgumentError: B65 GROUPING argument ${displayField(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
6158
+ `ArgumentError: GROUPING argument ${displayField2(ref.field)} is not present in grouping allItems (reason=B65_GROUPING_ARG_NOT_ITEM).`
5729
6159
  );
5730
6160
  }
5731
6161
  bindGroupingRefCanonicalId(ref, resolved.canonicalId);
5732
6162
  }
5733
- function validateDependency(ref, resolve2, canonicalItems, context) {
5734
- const resolved = resolve2(ref);
5735
- if (!resolved.physical || !canonicalItems.has(resolved.canonicalId)) {
5736
- throw new Error(
5737
- `ArgumentError: B65 non-aggregate field ${displayField(ref)} in ${context} is not a grouping item (reason=B65_NON_GROUPED_DEPENDENCY).`
5738
- );
5739
- }
5740
- }
5741
- function keyDependencies(key) {
5742
- if (key.type === "GROUPING_KEY") return [];
5743
- if (key.type === "FIELD_NAME") return [refFromName(key.name)];
5744
- const refs = [];
5745
- collectNonAggregateFieldRefs(key, refs);
5746
- return refs;
5747
- }
5748
6163
  function validateGroupingStatic(stmt) {
5749
6164
  const normalized = normalizeGroupingSpec(stmt);
5750
6165
  const groupingRefs = [];
@@ -5763,25 +6178,28 @@ function validateGroupingStatic(stmt) {
5763
6178
  }
5764
6179
  if (forbiddenGroupingRefs.length > 0) {
5765
6180
  throw new Error(
5766
- "ArgumentError: B65 GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
6181
+ "ArgumentError: GROUPING() is not allowed in WHERE, JOIN, window, aggregate arguments, or DML expressions."
5767
6182
  );
5768
6183
  }
5769
6184
  if (normalized.type !== "GROUPING_SETS") {
5770
6185
  if (groupingRefs.length > 0) {
5771
- throw new Error("ArgumentError: B65 GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
6186
+ throw new Error("ArgumentError: GROUPING() requires GROUP BY ROLLUP or GROUPING SETS.");
5772
6187
  }
6188
+ validateAggregateDependenciesStatic(stmt);
5773
6189
  return;
5774
6190
  }
5775
6191
  if (stmt.orderMode === "KINTONE_NATIVE") {
5776
- throw new Error("ArgumentError: B65 KORDER BY is not supported in Phase1.");
6192
+ throw new Error("ArgumentError: KORDER BY is not supported with extended grouping.");
5777
6193
  }
5778
6194
  if (stmt.columns.some((column) => column.type === "WINDOW_COL")) {
5779
- throw new Error("ArgumentError: B65 window functions are not supported in Phase1.");
6195
+ throw new Error("ArgumentError: window functions are not supported with extended grouping.");
5780
6196
  }
5781
6197
  if (stmt.columns.some(
5782
6198
  (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
5783
6199
  )) {
5784
- throw new Error("ArgumentError: B65 wildcard projection is not supported in Phase1.");
6200
+ throw new Error(
6201
+ "ArgumentError: SELECT wildcard \u306F\u96C6\u8A08 query \u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u5FC5\u8981\u306A grouping \u5217\u3092\u660E\u793A\u3057\u3066\u304F\u3060\u3055\u3044 (reason=B65_NON_GROUPED_DEPENDENCY)."
6202
+ );
5785
6203
  }
5786
6204
  }
5787
6205
  function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void 0) {
@@ -5802,7 +6220,7 @@ function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void
5802
6220
  for (const item of resolvedSpec.allItems) {
5803
6221
  const resolved = item;
5804
6222
  if (!resolved.physical) {
5805
- throw new Error(`ArgumentError: B65 grouping item ${displayField(item.field)} must resolve to a physical APP field.`);
6223
+ throw new Error(`ArgumentError: grouping item ${displayField2(item.field)} must resolve to a physical APP field.`);
5806
6224
  }
5807
6225
  if (!canonicalItems.has(resolved.canonicalId)) {
5808
6226
  canonicalItems.add(resolved.canonicalId);
@@ -5816,28 +6234,12 @@ function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void
5816
6234
  for (const ref of groupingRefs) {
5817
6235
  validateGroupingRefMembership(ref, resolve2, canonicalItems);
5818
6236
  }
5819
- const aliases = outputAliases(stmt.columns);
5820
- for (const column of stmt.columns) {
5821
- 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;
5822
- const refs = [];
5823
- if (column.type === "FIELD") refs.push(refFromName(column.field));
5824
- else collectNonAggregateFieldRefs(column, refs);
5825
- for (const ref of refs) validateDependency(ref, resolve2, canonicalItems, "SELECT");
5826
- }
5827
- if (stmt.having) {
5828
- const refs = [];
5829
- collectNonAggregateFieldRefs(stmt.having, refs);
5830
- for (const ref of refs) {
5831
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5832
- validateDependency(ref, resolve2, canonicalItems, "HAVING");
5833
- }
5834
- }
5835
- for (const order of stmt.orderBy) {
5836
- for (const ref of keyDependencies(order.key)) {
5837
- if (ref.tableAlias === null && aliases.has(ref.field) || isAggregateSyntheticReference(ref)) continue;
5838
- validateDependency(ref, resolve2, canonicalItems, "ORDER BY");
5839
- }
5840
- }
6237
+ validateAggregateDependencies(stmt, {
6238
+ identities: new Set([...canonicalItems].map(canonicalGroupingFieldIdentity)),
6239
+ resolveField: (ref) => resolve2(ref).canonicalId,
6240
+ sourceLabel: stmt.from.cteName ?? `APP${stmt.from.appId}`,
6241
+ groupingLabel: `GROUP BY ${normalized.source}`
6242
+ });
5841
6243
  const collisionKeys = /* @__PURE__ */ new Set();
5842
6244
  for (const item of resolvedItems) {
5843
6245
  collisionKeys.add(item.directKey);
@@ -5849,7 +6251,7 @@ function validateGroupingPlanning(stmt, resolve2, planningGuardHook = () => void
5849
6251
  if (alias === null) continue;
5850
6252
  if (collisionKeys.has(alias)) {
5851
6253
  throw new Error(
5852
- `ArgumentError: B65 aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
6254
+ `ArgumentError: aggregate alias ${alias} collides with a grouping runtime key (reason=B65_AGGREGATE_ALIAS_COLLISION).`
5853
6255
  );
5854
6256
  }
5855
6257
  }
@@ -13077,148 +13479,6 @@ function buildKorderCursorQuery(stmt) {
13077
13479
  return parts.join(" ");
13078
13480
  }
13079
13481
 
13080
- // src/core/systemFields.ts
13081
- var APP_SYSTEM_FIELD_CODES = [
13082
- "$id",
13083
- "$revision",
13084
- "\u30EC\u30B3\u30FC\u30C9\u756A\u53F7",
13085
- "\u4F5C\u6210\u8005",
13086
- "\u4F5C\u6210\u65E5\u6642",
13087
- "\u66F4\u65B0\u8005",
13088
- "\u66F4\u65B0\u65E5\u6642",
13089
- "\u30B9\u30C6\u30FC\u30BF\u30B9",
13090
- "\u4F5C\u696D\u8005"
13091
- ];
13092
- function isSystemLikeFieldCode(code) {
13093
- return code.startsWith("_") || code.startsWith("$");
13094
- }
13095
-
13096
- // src/core/optimization/plainGroupByPlan.ts
13097
- var AGGREGATE_REFERENCE_PREFIX = /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT|STDDEV_POP|STDDEV_SAMP|VAR_POP|VAR_SAMP|MEDIAN|MODE)\(/;
13098
- function containsAggregateColumnNode(node) {
13099
- if (node === null || typeof node !== "object") return false;
13100
- if (Array.isArray(node)) return node.some(containsAggregateColumnNode);
13101
- const value = node;
13102
- if (value["type"] === "AGGREGATE" || value["type"] === "ARITH_AGG_COL") return true;
13103
- if (value["type"] === "SELECT" || value["type"] === "SCALAR_SUBQUERY") return false;
13104
- if (value["type"] === "FIELD" && typeof value["field"] === "string") {
13105
- return AGGREGATE_REFERENCE_PREFIX.test(value["field"]);
13106
- }
13107
- return Object.values(value).some(containsAggregateColumnNode);
13108
- }
13109
- function classifyPreGroupAlias(column) {
13110
- switch (column.type) {
13111
- case "AGGREGATE":
13112
- case "ARITH_AGG_COL":
13113
- return "AGGREGATE_DEPENDENT";
13114
- case "GROUPING_COL":
13115
- case "WINDOW_COL":
13116
- return "POST_GROUP_ONLY";
13117
- case "VARIABLE_COL":
13118
- throw new Error("InternalError: unresolved VARIABLE_COL reached GROUP BY alias planning.");
13119
- case "WILDCARD":
13120
- case "PARENT_WILDCARD":
13121
- case "FIELD":
13122
- case "LITERAL_COL":
13123
- case "ARITH_COL":
13124
- case "CASE_COL":
13125
- case "STRFUNC_COL":
13126
- case "SCALAR_VALUE_COL":
13127
- case "SCALAR_SUBQUERY_COL":
13128
- return containsAggregate2(column) || containsAggregateColumnNode(column) ? "AGGREGATE_DEPENDENT" : "SAFE";
13129
- }
13130
- }
13131
- var SUBTABLE_SYSTEM_COLUMNS = ["_pid", "_rid", "_idx"];
13132
- function unique(values) {
13133
- return [...new Set(values)];
13134
- }
13135
- function sourceColumns(input) {
13136
- switch (input.kind) {
13137
- case "APP":
13138
- return unique([
13139
- ...input.fieldCodes,
13140
- ...APP_SYSTEM_FIELD_CODES
13141
- ]);
13142
- case "SUBTABLE":
13143
- return unique([
13144
- ...input.childFieldCodes,
13145
- ...SUBTABLE_SYSTEM_COLUMNS,
13146
- ...input.parentFieldCodes.map((field) => `_p.${field}`)
13147
- ]);
13148
- case "MATERIALIZED":
13149
- return unique(input.columns);
13150
- }
13151
- }
13152
- function resolvePlainGroupBySourceSchemas(stmt, lookup) {
13153
- const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
13154
- return sources.map((source, sourceIndex) => ({
13155
- sourceIndex,
13156
- qualifier: source.alias ?? source.cteName,
13157
- columns: sourceColumns(lookup(source, sourceIndex))
13158
- }));
13159
- }
13160
- function parseGroupName(name) {
13161
- if (name.startsWith("_p.")) return { qualifier: null, fieldCode: name };
13162
- const dot = name.indexOf(".");
13163
- if (dot <= 0 || dot === name.length - 1) {
13164
- return { qualifier: null, fieldCode: name };
13165
- }
13166
- return { qualifier: name.slice(0, dot), fieldCode: name.slice(dot + 1) };
13167
- }
13168
- function runtimeKey(source, fieldCode) {
13169
- return source.qualifier === null ? fieldCode : `${source.qualifier}.${fieldCode}`;
13170
- }
13171
- function explicitAlias(column) {
13172
- return "alias" in column && typeof column.alias === "string" ? column.alias : null;
13173
- }
13174
- function resolveFieldName(name, columns, schemas) {
13175
- const parsed = parseGroupName(name);
13176
- const candidateSources = parsed.qualifier === null ? schemas : schemas.filter((source) => source.qualifier === parsed.qualifier);
13177
- const physical = candidateSources.filter((source) => source.columns.includes(parsed.fieldCode));
13178
- if (physical.length > 1) {
13179
- throw new Error(
13180
- `ArgumentError: GROUP BY field ${name} is ambiguous across multiple sources (reason=GROUP_BY_FIELD_AMBIGUOUS).`
13181
- );
13182
- }
13183
- if (physical.length === 1) {
13184
- const source = physical[0];
13185
- return {
13186
- kind: "PHYSICAL",
13187
- sourceIndex: source.sourceIndex,
13188
- fieldCode: parsed.fieldCode,
13189
- runtimeKey: runtimeKey(source, parsed.fieldCode)
13190
- };
13191
- }
13192
- if (parsed.qualifier !== null) return { kind: "UNKNOWN", name };
13193
- const aliases = columns.flatMap(
13194
- (column, columnIndex) => explicitAlias(column) === name ? [{ column, columnIndex }] : []
13195
- );
13196
- if (aliases.length > 1) return { kind: "ALIAS_REJECT", reason: "DUPLICATE" };
13197
- if (aliases.length === 1) {
13198
- const candidate = aliases[0];
13199
- const classification = classifyPreGroupAlias(candidate.column);
13200
- if (classification === "SAFE") {
13201
- return { kind: "ALIAS_SAFE", columnIndex: candidate.columnIndex };
13202
- }
13203
- return {
13204
- kind: "ALIAS_REJECT",
13205
- reason: classification === "AGGREGATE_DEPENDENT" ? "AGGREGATE" : "POST_GROUP_ONLY"
13206
- };
13207
- }
13208
- const aggregateSyntheticMatch = columns.some(
13209
- (column) => column.type === "AGGREGATE" && column.alias === null && aggregateSyntheticName(column.func, column.distinct, column.arg) === name
13210
- );
13211
- if (aggregateSyntheticMatch) return { kind: "ALIAS_REJECT", reason: "AGGREGATE" };
13212
- return { kind: "UNKNOWN", name };
13213
- }
13214
- function planPlainGroupByResolution(groupBy, columns, schemas) {
13215
- return {
13216
- items: groupBy.map(
13217
- (key) => key.type === "FIELD_NAME" ? resolveFieldName(key.name, columns, schemas) : { kind: "EXPRESSION" }
13218
- )
13219
- };
13220
- }
13221
-
13222
13482
  // src/core/emptyWildcardSchema.ts
13223
13483
  var EMPTY_WILDCARD_FIELD_TYPE_POLICY = {
13224
13484
  CALC: "RECORD",
@@ -17189,7 +17449,13 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
17189
17449
  return { tempTable: stmt.name };
17190
17450
  }
17191
17451
  if (stmt.type === "EXPLAIN") {
17192
- return { result: await executeParsedStatement(resolvedStmt, client, options, cacheContext) };
17452
+ const explainStmt = resolvedStmt;
17453
+ explainMaterializedTables.set(explainStmt, tempTables);
17454
+ try {
17455
+ return { result: await executeParsedStatement(explainStmt, client, options, cacheContext) };
17456
+ } finally {
17457
+ explainMaterializedTables.delete(explainStmt);
17458
+ }
17193
17459
  }
17194
17460
  if (resolvedStmt.type === "ASSERT") {
17195
17461
  await executeAssert(resolvedStmt, client, options, cacheContext, tempTables);
@@ -17998,7 +18264,12 @@ function dedupeSubtableOwners(owners) {
17998
18264
  return result;
17999
18265
  }
18000
18266
  async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, materializedTables) {
18001
- if (stmt.groupBy.length === 0) return void 0;
18267
+ const normalized = normalizeGroupingSpec(stmt);
18268
+ if (!isAggregateQueryBlock(stmt) || normalized.type === "GROUPING_SETS") {
18269
+ return void 0;
18270
+ }
18271
+ if (normalized.type === "NONE") return void 0;
18272
+ const groupBy = normalized.allItems;
18002
18273
  const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
18003
18274
  const subtableOwners = /* @__PURE__ */ new Map();
18004
18275
  const inputs = await Promise.all(sources.map(async (source) => {
@@ -18036,9 +18307,9 @@ async function buildRuntimePlainGroupByPlan(stmt, client, cacheContext, material
18036
18307
  stmt,
18037
18308
  (_source, sourceIndex) => inputs[sourceIndex]
18038
18309
  );
18039
- const groupBy = stmt.groupBy;
18040
18310
  const plan = planPlainGroupByResolution(groupBy, stmt.columns, schemas);
18041
18311
  assertRuntimePlainGroupByPlan(stmt, groupBy, plan, subtableOwners);
18312
+ validateAggregateDependencies(stmt, buildOrdinaryDependencyPolicy(stmt, plan, schemas));
18042
18313
  return plan;
18043
18314
  }
18044
18315
  function assertRuntimePlainGroupByPlan(stmt, groupBy, plan, subtableOwners) {
@@ -18095,7 +18366,9 @@ async function validateStatementGroupingPlanning(statement, client, cacheContext
18095
18366
  }
18096
18367
  const value = node;
18097
18368
  if (value["type"] === "SELECT") {
18369
+ for (const child of Object.values(value)) await visit(child);
18098
18370
  await validateSelectGroupingPlanning(node, client, cacheContext);
18371
+ return;
18099
18372
  }
18100
18373
  for (const child of Object.values(value)) await visit(child);
18101
18374
  };
@@ -18143,12 +18416,12 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
18143
18416
  if (field.tableAlias !== null) {
18144
18417
  const tableIndex = tables.findIndex((table2) => effectiveTableAlias(table2) === field.tableAlias);
18145
18418
  if (tableIndex < 0) {
18146
- throw new Error(`ArgumentError: B65 field ${field.tableAlias}.${field.field} has an unknown table alias.`);
18419
+ throw new Error(`ArgumentError: field ${field.tableAlias}.${field.field} has an unknown table alias.`);
18147
18420
  }
18148
18421
  const table = tables[tableIndex];
18149
18422
  if (table.cteName !== null) {
18150
18423
  throw new Error(
18151
- `ArgumentError: B65 field ${field.tableAlias}.${field.field} resolves to materialized source ${table.cteName}; physical APP fields are required.`
18424
+ `ArgumentError: field ${field.tableAlias}.${field.field} resolves to materialized source ${table.cteName}; physical APP fields are required.`
18152
18425
  );
18153
18426
  }
18154
18427
  const code = physicalMatch(table, field.field);
@@ -18157,7 +18430,7 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
18157
18430
  if (owner !== null && owner !== "") {
18158
18431
  throw new Error(subtableGroupingAdvice(field.field, [{ appId: table.appId, owner }]));
18159
18432
  }
18160
- throw new Error(`ArgumentError: B65 field ${field.tableAlias}.${field.field} does not exist in APP${table.appId}.`);
18433
+ throw new Error(`ArgumentError: field ${field.tableAlias}.${field.field} does not exist in APP${table.appId}.`);
18161
18434
  }
18162
18435
  return resolved(table, tableIndex, field, code);
18163
18436
  }
@@ -18168,7 +18441,7 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
18168
18441
  });
18169
18442
  const materializedMatches = tables.filter((table) => materializedHas(table, field.field));
18170
18443
  if (physicalMatches.length + materializedMatches.length > 1) {
18171
- throw new Error(`ArgumentError: B65 field ${field.field} is ambiguous across multiple sources.`);
18444
+ throw new Error(`ArgumentError: field ${field.field} is ambiguous across multiple sources.`);
18172
18445
  }
18173
18446
  if (physicalMatches.length === 1 && materializedMatches.length === 0) {
18174
18447
  const match = physicalMatches[0];
@@ -18176,7 +18449,7 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
18176
18449
  }
18177
18450
  if (materializedMatches.length === 1) {
18178
18451
  throw new Error(
18179
- `ArgumentError: B65 field ${field.field} resolves to a materialized CTE/temp column; physical APP fields are required.`
18452
+ `ArgumentError: field ${field.field} resolves to a materialized CTE/temp column; physical APP fields are required.`
18180
18453
  );
18181
18454
  }
18182
18455
  const owners = tables.flatMap((table) => {
@@ -18188,21 +18461,34 @@ async function buildGroupingFieldResolver(stmt, client, cacheContext, materializ
18188
18461
  if (uniqueOwners.length > 0) {
18189
18462
  throw new Error(subtableGroupingAdvice(field.field, uniqueOwners));
18190
18463
  }
18191
- throw new Error(`ArgumentError: B65 field ${field.field} does not exist in a physical APP source.`);
18464
+ throw new Error(`ArgumentError: field ${field.field} does not exist in a physical APP source.`);
18192
18465
  };
18193
18466
  }
18194
18467
  async function validateSelectGroupingPlanning(stmt, client, cacheContext, materializedTables) {
18195
18468
  resolvedGroupingSpecs.delete(stmt);
18196
18469
  const normalized = normalizeGroupingSpec(stmt);
18197
18470
  const hasGroupingNodes = JSON.stringify(stmt.columns).includes('"GROUPING_') || JSON.stringify(stmt.orderBy).includes('"GROUPING_');
18198
- if (normalized.type === "NONE" && !hasGroupingNodes) return;
18199
- const resolver = await buildGroupingFieldResolver(stmt, client, cacheContext, materializedTables);
18200
- const resolvedSpec = validateGroupingPlanning(
18201
- stmt,
18202
- resolver,
18203
- enforceGroupingPlanningCandidateLimits
18471
+ if (normalized.type === "GROUPING_SETS" || hasGroupingNodes) {
18472
+ const resolver = await buildGroupingFieldResolver(stmt, client, cacheContext, materializedTables);
18473
+ const resolvedSpec = validateGroupingPlanning(
18474
+ stmt,
18475
+ resolver,
18476
+ enforceGroupingPlanningCandidateLimits
18477
+ );
18478
+ if (resolvedSpec) resolvedGroupingSpecs.set(stmt, resolvedSpec);
18479
+ return;
18480
+ }
18481
+ if (!isAggregateQueryBlock(stmt)) return;
18482
+ if (normalized.type === "NONE") {
18483
+ validateAggregateDependenciesStatic(stmt);
18484
+ return;
18485
+ }
18486
+ const sources = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
18487
+ const hasUnavailableMaterializedSource = sources.some(
18488
+ (source) => source.cteName !== null && !materializedTables?.has(source.cteName)
18204
18489
  );
18205
- if (resolvedSpec) resolvedGroupingSpecs.set(stmt, resolvedSpec);
18490
+ if (hasUnavailableMaterializedSource) return;
18491
+ await buildRuntimePlainGroupByPlan(stmt, client, cacheContext, materializedTables);
18206
18492
  }
18207
18493
  function completeInputErrorPrefix(reasons) {
18208
18494
  const reasonList = [...reasons].join(", ");
@@ -19316,7 +19602,7 @@ function mergeUnionColumnMeta(left, right) {
19316
19602
  function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
19317
19603
  const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
19318
19604
  const physicalTables = tables.filter((table) => table.cteName === null);
19319
- const outputAliases2 = new Set(
19605
+ const outputAliases = new Set(
19320
19606
  stmt.columns.map((column) => "alias" in column ? column.alias : null).filter((alias) => alias !== null)
19321
19607
  );
19322
19608
  const row = (field) => {
@@ -19340,7 +19626,7 @@ function buildSelectFieldTypeResolvers(stmt, fieldTypesByApp) {
19340
19626
  return matches.length === 1 ? matches[0] : void 0;
19341
19627
  };
19342
19628
  const having = (field) => {
19343
- if (field.tableAlias === null && outputAliases2.has(field.field)) return void 0;
19629
+ if (field.tableAlias === null && outputAliases.has(field.field)) return void 0;
19344
19630
  return row(field);
19345
19631
  };
19346
19632
  return { row, having };
@@ -23359,7 +23645,7 @@ var explainJoinPushdownPlans = /* @__PURE__ */ new WeakMap();
23359
23645
  var explainChoiceEqualityRewrites = /* @__PURE__ */ new WeakMap();
23360
23646
  var validateExplainInfo = /* @__PURE__ */ new WeakMap();
23361
23647
  var applyParentExplainPlan = /* @__PURE__ */ new WeakMap();
23362
- async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords = 1e4, relativeDatePlan) {
23648
+ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords = 1e4, relativeDatePlan, initialRelations) {
23363
23649
  const fieldApps = /* @__PURE__ */ new Set();
23364
23650
  const processStatusApps = /* @__PURE__ */ new Set();
23365
23651
  const numberPrecisionApps = /* @__PURE__ */ new Set();
@@ -23386,6 +23672,119 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
23386
23672
  const relativeNodeFor = (source) => sharedRelativeDatePlan.nodes.find(
23387
23673
  (node) => node.source === source || JSON.stringify(node.source) === JSON.stringify(source)
23388
23674
  );
23675
+ const explainRelations = new Map(initialRelations ?? []);
23676
+ const explainSourceColumns = async (select) => {
23677
+ const tables = [select.from, ...select.joins.map((join2) => join2.table)];
23678
+ if (tables.length > 1 && select.columns.some(
23679
+ (column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD"
23680
+ )) {
23681
+ throw new Error(
23682
+ "ArgumentError: EXPLAIN could not determine the relation output schema for a multi-source wildcard SELECT."
23683
+ );
23684
+ }
23685
+ const columns = [];
23686
+ for (const table of tables) {
23687
+ if (table.cteName !== null) {
23688
+ if (table.cteName === NO_FROM_CTE_NAME) continue;
23689
+ const relation = explainRelations.get(table.cteName);
23690
+ if (!relation) {
23691
+ throw new Error(
23692
+ `ArgumentError: EXPLAIN could not determine the relation output schema for ${table.cteName}.`
23693
+ );
23694
+ }
23695
+ columns.push(...relation.columns);
23696
+ continue;
23697
+ }
23698
+ const fields = await getFieldsCached(table.appId, tracedClient, cacheContext);
23699
+ if (table.subtableCode) {
23700
+ columns.push(...fields.filter(
23701
+ (field) => field.inSubtable && (field.subtableCode === table.subtableCode || field.subtableCode === void 0)
23702
+ ).map((field) => field.code));
23703
+ columns.push("_pid", "_rid", "_idx");
23704
+ columns.push(...fields.filter((field) => !field.inSubtable).map((field) => `_p.${field.code}`));
23705
+ } else {
23706
+ columns.push(...fields.filter((field) => !field.inSubtable).map((field) => field.code));
23707
+ columns.push(...APP_SYSTEM_FIELD_CODES);
23708
+ }
23709
+ }
23710
+ return [...new Set(columns)];
23711
+ };
23712
+ const inferExplainRelationColumns = async (node) => {
23713
+ if (node === null || typeof node !== "object") {
23714
+ throw new Error("ArgumentError: EXPLAIN could not determine the relation output schema.");
23715
+ }
23716
+ const typed = node;
23717
+ if (typed["type"] === "SELECT") {
23718
+ const select = node;
23719
+ const sourceColumns2 = await explainSourceColumns(select);
23720
+ if (select.columns.length === 1 && select.columns[0].type === "WILDCARD") {
23721
+ return sourceColumns2;
23722
+ }
23723
+ const output = [];
23724
+ for (const column of select.columns) {
23725
+ if (column.type === "WILDCARD") output.push(...sourceColumns2);
23726
+ else if (column.type === "PARENT_WILDCARD") {
23727
+ output.push(...sourceColumns2.filter((name) => name.startsWith("_p.")));
23728
+ } else {
23729
+ output.push(...project([], [column]).columns);
23730
+ }
23731
+ }
23732
+ return output;
23733
+ }
23734
+ if (typed["type"] === "UNION") {
23735
+ return inferExplainRelationColumns(typed["left"]);
23736
+ }
23737
+ if (typed["type"] === "SHOW_APPS") return [...SHOW_APPS_COLUMNS];
23738
+ if (typed["type"] === "DESCRIBE") return [...DESCRIBE_COLUMNS];
23739
+ throw new Error("ArgumentError: EXPLAIN could not determine the relation output schema.");
23740
+ };
23741
+ const preflightExplainRelations = async (node) => {
23742
+ if (node === null || typeof node !== "object") return;
23743
+ if (Array.isArray(node)) {
23744
+ for (const child of node) await preflightExplainRelations(child);
23745
+ return;
23746
+ }
23747
+ const typed = node;
23748
+ if (typed["type"] === "WITH") {
23749
+ const withStatement = node;
23750
+ for (const cte of withStatement.ctes) {
23751
+ await preflightExplainRelations(cte.query);
23752
+ const columns = await inferExplainRelationColumns(cte.query);
23753
+ explainRelations.set(cte.name, { rows: [], columns });
23754
+ }
23755
+ await preflightExplainRelations(withStatement.query);
23756
+ return;
23757
+ }
23758
+ if (typed["type"] === "UNION") {
23759
+ await preflightExplainRelations(typed["left"]);
23760
+ await preflightExplainRelations(typed["right"]);
23761
+ return;
23762
+ }
23763
+ if (typed["type"] === "SELECT") {
23764
+ const select = node;
23765
+ for (const column of select.columns) {
23766
+ if (column.type === "SCALAR_SUBQUERY_COL") await preflightExplainRelations(column.query);
23767
+ }
23768
+ await preflightExplainRelations(select.where);
23769
+ await preflightExplainRelations(select.having);
23770
+ await validateSelectGroupingPlanning(
23771
+ select,
23772
+ tracedClient,
23773
+ cacheContext,
23774
+ explainRelations
23775
+ );
23776
+ const plainPlan = await buildRuntimePlainGroupByPlan(
23777
+ select,
23778
+ tracedClient,
23779
+ cacheContext,
23780
+ explainRelations
23781
+ );
23782
+ if (plainPlan) plainGroupByPlans.set(select, plainPlan);
23783
+ return;
23784
+ }
23785
+ for (const child of Object.values(typed)) await preflightExplainRelations(child);
23786
+ };
23787
+ await preflightExplainRelations(query);
23389
23788
  const visit = async (node) => {
23390
23789
  if (node === null || typeof node !== "object") return;
23391
23790
  if (seen.has(node)) return;
@@ -24057,6 +24456,7 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector
24057
24456
  lines.push(" note: \u4E00\u6642\u30C6\u30FC\u30D6\u30EB\u3078\u306E WHERE \u30D7\u30C3\u30B7\u30E5\u30C0\u30A6\u30F3\u306F\u884C\u308F\u308C\u306A\u3044");
24058
24457
  return lines;
24059
24458
  }
24459
+ var explainMaterializedTables = /* @__PURE__ */ new WeakMap();
24060
24460
  async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan) {
24061
24461
  const sharedPlan = relativeDatePlan ?? await resolveRelativeDateExecutionPlan(stmt.query, client, cacheContext);
24062
24462
  const analysis = await buildExplainWhereAnalysis(
@@ -24064,7 +24464,8 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
24064
24464
  client,
24065
24465
  cacheContext,
24066
24466
  maxRecords,
24067
- sharedPlan
24467
+ sharedPlan,
24468
+ explainMaterializedTables.get(stmt)
24068
24469
  );
24069
24470
  const fetchCollector = { sources: [] };
24070
24471
  const relativeLines = relativeDateExplainLines(sharedPlan);
@@ -24358,6 +24759,12 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
24358
24759
  lines.push(
24359
24760
  ` group key ${key.name}: PHYSICAL (source=${item.sourceIndex}, field=${item.fieldCode})`
24360
24761
  );
24762
+ } else if (item.kind === "ALIAS_SAFE") {
24763
+ lines.push(
24764
+ ` group key ${key.name}: ALIAS_SAFE (column=${item.columnIndex})`
24765
+ );
24766
+ } else if (item.kind === "EXPRESSION") {
24767
+ lines.push(` group key ${key.name}: EXPRESSION`);
24361
24768
  }
24362
24769
  });
24363
24770
  } else if ([stmt.from, ...stmt.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)) {