@rex0220/kintone-sql-tools 3.65.0 → 3.66.1
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 +906 -108
- package/dist-engine/index.cjs +14 -14
- package/dist-engine/index.mjs +14 -14
- package/dist-engine/ksql-engine.umd.js +14 -14
- package/dist-engine/meta/bundle-baseline.json +10 -10
- package/dist-engine/meta/cjs.json +25 -12
- package/dist-engine/meta/esm.json +25 -12
- package/dist-engine/meta/umd.json +25 -12
- package/dist-engine/publicTypes.d.ts +6 -0
- package/dist-mcp/ksql-mcp.js +919 -120
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/cli/index.ts
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
|
+
CLI_HELP_TEXT: () => CLI_HELP_TEXT,
|
|
24
25
|
CLI_IMPORT_SOURCE_REQUIRED_MESSAGE: () => CLI_IMPORT_SOURCE_REQUIRED_MESSAGE,
|
|
25
26
|
HELP_TEXT: () => HELP_TEXT,
|
|
26
27
|
buildBatchDmlConfirmMessage: () => buildBatchDmlConfirmMessage,
|
|
@@ -1085,6 +1086,12 @@ var Parser = class {
|
|
|
1085
1086
|
this.tempTableRefs = [];
|
|
1086
1087
|
/** GROUP BY を読む前に作る B124 候補 leaf の診断位置。AST 公開型へ位置情報を足さない。 */
|
|
1087
1088
|
this.aggregateGroupKeyTokens = /* @__PURE__ */ new WeakMap();
|
|
1089
|
+
// ----------------------------------------------------------
|
|
1090
|
+
// WITH 句(CTE)
|
|
1091
|
+
// ----------------------------------------------------------
|
|
1092
|
+
/** B53 parser-private state. Kept here so earlier diagnostic source locations remain stable. */
|
|
1093
|
+
this.activeCteDefinition = null;
|
|
1094
|
+
this.provisionalRecursiveCte = null;
|
|
1088
1095
|
this.allowSelectArithVariable = false;
|
|
1089
1096
|
}
|
|
1090
1097
|
// ----------------------------------------------------------
|
|
@@ -1919,34 +1926,172 @@ var Parser = class {
|
|
|
1919
1926
|
offset
|
|
1920
1927
|
};
|
|
1921
1928
|
}
|
|
1922
|
-
// ----------------------------------------------------------
|
|
1923
|
-
// WITH 句(CTE)
|
|
1924
|
-
// ----------------------------------------------------------
|
|
1925
1929
|
parseWith() {
|
|
1926
1930
|
this.expect("WITH" /* WITH */);
|
|
1931
|
+
const recursive = this.isSoftKeyword("RECURSIVE") && this.peekAt(1).kind !== "AS" /* AS */ && this.peekAt(1).kind !== "(" /* LPAREN */;
|
|
1932
|
+
if (recursive) this.advance();
|
|
1927
1933
|
const ctes = [];
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1934
|
+
let recursiveCount = 0;
|
|
1935
|
+
try {
|
|
1936
|
+
do {
|
|
1937
|
+
const name = this.parseIdentifier();
|
|
1938
|
+
const columnAliases = this.parseOptionalCteColumnAliases();
|
|
1939
|
+
this.expect("AS" /* AS */);
|
|
1940
|
+
this.expect("(" /* LPAREN */);
|
|
1941
|
+
this.activeCteDefinition = { name, recursiveWith: recursive, phase: "SEED" };
|
|
1942
|
+
let query2;
|
|
1943
|
+
let recursiveSpec;
|
|
1944
|
+
const inner = this.peek().kind;
|
|
1945
|
+
if (inner === "SHOW" /* SHOW */) {
|
|
1946
|
+
query2 = this.parseShow();
|
|
1947
|
+
} else if (inner === "DESCRIBE" /* DESCRIBE */ || inner === "DESC" /* DESC */) {
|
|
1948
|
+
query2 = this.parseDescribe();
|
|
1949
|
+
} else if (inner === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "GENERATE_SERIES") {
|
|
1950
|
+
query2 = this.parseGenerateSeries();
|
|
1951
|
+
} else if (recursive) {
|
|
1952
|
+
const parsed = this.parseRecursiveCteCandidate(name);
|
|
1953
|
+
query2 = parsed.query;
|
|
1954
|
+
recursiveSpec = parsed.recursiveSpec;
|
|
1955
|
+
} else {
|
|
1956
|
+
query2 = this.tryParseUnionChain(this.parseSelect());
|
|
1957
|
+
}
|
|
1958
|
+
this.expect(")" /* RPAREN */);
|
|
1959
|
+
const cycle = recursive && this.isSoftKeyword("CYCLE") ? this.parseRecursiveCycleClause() : null;
|
|
1960
|
+
if (cycle && !recursiveSpec) {
|
|
1961
|
+
throw new ParseError("CYCLE \u53E5\u306F\u81EA\u5DF1\u53C2\u7167\u3059\u308B\u518D\u5E30 CTE \u306B\u3060\u3051\u6307\u5B9A\u3067\u304D\u307E\u3059", this.prev());
|
|
1962
|
+
}
|
|
1963
|
+
if (recursiveSpec) {
|
|
1964
|
+
recursiveSpec = { ...recursiveSpec, cycle };
|
|
1965
|
+
this.validateRecursiveCte(name, columnAliases, recursiveSpec);
|
|
1966
|
+
recursiveCount++;
|
|
1967
|
+
if (recursiveCount > 1) {
|
|
1968
|
+
throw new ParseError("WITH RECURSIVE \u3067\u5B9A\u7FA9\u3067\u304D\u308B\u518D\u5E30 CTE \u306F1\u500B\u307E\u3067\u3067\u3059", this.prev());
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (columnAliases && !recursiveSpec) {
|
|
1972
|
+
throw new ParseError("CTE \u306E\u5217\u540D\u30EA\u30B9\u30C8\u306F WITH RECURSIVE \u306E\u518D\u5E30 CTE \u306B\u3060\u3051\u6307\u5B9A\u3067\u304D\u307E\u3059", this.prev());
|
|
1973
|
+
}
|
|
1974
|
+
const definition = { name, query: query2 };
|
|
1975
|
+
if (columnAliases) definition.columnAliases = columnAliases;
|
|
1976
|
+
if (recursiveSpec) definition.recursiveSpec = recursiveSpec;
|
|
1977
|
+
ctes.push(definition);
|
|
1978
|
+
this.activeCteDefinition = null;
|
|
1979
|
+
this.provisionalRecursiveCte = null;
|
|
1980
|
+
this.cteNames.add(name);
|
|
1981
|
+
} while (this.consume("," /* COMMA */));
|
|
1982
|
+
const query = this.tryParseUnionChain(this.parseSelect());
|
|
1983
|
+
return recursive ? { type: "WITH", ctes, query, recursive: true } : { type: "WITH", ctes, query };
|
|
1984
|
+
} finally {
|
|
1985
|
+
this.activeCteDefinition = null;
|
|
1986
|
+
this.provisionalRecursiveCte = null;
|
|
1987
|
+
this.cteNames.clear();
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
parseOptionalCteColumnAliases() {
|
|
1991
|
+
if (!this.consume("(" /* LPAREN */)) return void 0;
|
|
1992
|
+
const aliases = [];
|
|
1993
|
+
if (this.peek().kind === ")" /* RPAREN */) {
|
|
1994
|
+
throw new ParseError("CTE \u306E\u5217\u540D\u30EA\u30B9\u30C8\u306B\u306F1\u500B\u4EE5\u4E0A\u306E\u5217\u540D\u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
1995
|
+
}
|
|
1996
|
+
do
|
|
1997
|
+
aliases.push(this.parseIdentifier());
|
|
1998
|
+
while (this.consume("," /* COMMA */));
|
|
1999
|
+
this.expect(")" /* RPAREN */);
|
|
2000
|
+
if (new Set(aliases).size !== aliases.length) {
|
|
2001
|
+
throw new ParseError("CTE \u306E\u5217\u540D\u30EA\u30B9\u30C8\u306B\u540C\u3058\u5217\u540D\u3092\u91CD\u8907\u3057\u3066\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093", this.prev());
|
|
2002
|
+
}
|
|
2003
|
+
return aliases;
|
|
2004
|
+
}
|
|
2005
|
+
parseRecursiveCteCandidate(name) {
|
|
2006
|
+
const seed = this.parseSelect();
|
|
2007
|
+
if (this.peek().kind !== "UNION" /* UNION */) return { query: seed };
|
|
2008
|
+
this.advance();
|
|
2009
|
+
const all = this.consume("ALL" /* ALL */);
|
|
2010
|
+
this.activeCteDefinition = { name, recursiveWith: true, phase: "RECURSIVE_TERM" };
|
|
2011
|
+
this.provisionalRecursiveCte = { name, references: 0 };
|
|
2012
|
+
const recursiveTerm = this.parseSelect();
|
|
2013
|
+
const references = this.provisionalRecursiveCte.references;
|
|
2014
|
+
this.provisionalRecursiveCte = null;
|
|
2015
|
+
let query = { type: "UNION", all, left: seed, right: recursiveTerm };
|
|
2016
|
+
query = this.tryParseUnionChain(query);
|
|
2017
|
+
this.activeCteDefinition = { name, recursiveWith: true, phase: "SEED" };
|
|
2018
|
+
if (references === 0) return { query };
|
|
2019
|
+
if (!all || query.type !== "UNION" || query.left !== seed || query.right !== recursiveTerm) {
|
|
2020
|
+
throw new ParseError("\u518D\u5E30 CTE \u306F seed SELECT UNION ALL recursive SELECT \u306E2\u5206\u5C90\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", this.prev());
|
|
2021
|
+
}
|
|
2022
|
+
if (references !== 1) {
|
|
2023
|
+
throw new ParseError("\u518D\u5E30\u9805\u304B\u3089\u306E\u81EA\u5DF1\u53C2\u7167\u306F\u3061\u3087\u3046\u30691\u56DE\u306B\u3057\u3066\u304F\u3060\u3055\u3044", this.prev());
|
|
2024
|
+
}
|
|
2025
|
+
return {
|
|
2026
|
+
query,
|
|
2027
|
+
recursiveSpec: { seed, recursiveTerm, unionAll: true, cycle: null }
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
parseRecursiveCycleClause() {
|
|
2031
|
+
this.advance();
|
|
2032
|
+
const column = this.parseIdentifier();
|
|
2033
|
+
this.expect("SET" /* SET */, "CYCLE \u306E\u5217\u540D\u306E\u5F8C\u306B\u306F SET \u304C\u5FC5\u8981\u3067\u3059");
|
|
2034
|
+
const markColumn = this.parseIdentifier();
|
|
2035
|
+
if (!this.isSoftKeyword("TO")) throw new ParseError("CYCLE \u306E mark \u5217\u306E\u5F8C\u306B\u306F TO \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2036
|
+
this.advance();
|
|
2037
|
+
const mark = this.expect("STRING" /* STRING */, "CYCLE TO \u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
2038
|
+
if (!this.isSoftKeyword("DEFAULT")) throw new ParseError("CYCLE TO \u306E\u5024\u306E\u5F8C\u306B\u306F DEFAULT \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2039
|
+
this.advance();
|
|
2040
|
+
const normal = this.expect("STRING" /* STRING */, "CYCLE DEFAULT \u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
2041
|
+
if (mark.value === normal.value) {
|
|
2042
|
+
throw new ParseError("CYCLE \u306E TO \u3068 DEFAULT \u306B\u306F\u7570\u306A\u308B\u6587\u5B57\u5217\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044", normal);
|
|
2043
|
+
}
|
|
2044
|
+
return { column, markColumn, markValue: mark.value, defaultValue: normal.value, exposePath: false };
|
|
2045
|
+
}
|
|
2046
|
+
validateRecursiveCte(name, columnAliases, spec) {
|
|
2047
|
+
const token = this.prev();
|
|
2048
|
+
const seed = spec.seed;
|
|
2049
|
+
const term = spec.recursiveTerm;
|
|
2050
|
+
const { groupBy } = term;
|
|
2051
|
+
if (seed.columns.length !== term.columns.length) {
|
|
2052
|
+
throw new ParseError("\u518D\u5E30 CTE \u306E seed \u3068\u518D\u5E30\u9805\u306E\u5217\u6570\u3092\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044", token);
|
|
2053
|
+
}
|
|
2054
|
+
if (columnAliases && columnAliases.length !== seed.columns.length) {
|
|
2055
|
+
throw new ParseError("CTE \u306E\u5217\u540D\u30EA\u30B9\u30C8\u3068 SELECT \u306E\u5217\u6570\u3092\u4E00\u81F4\u3055\u305B\u3066\u304F\u3060\u3055\u3044", token);
|
|
2056
|
+
}
|
|
2057
|
+
if (seed.columns.some((column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD") || term.columns.some((column) => column.type === "WILDCARD" || column.type === "PARENT_WILDCARD")) {
|
|
2058
|
+
throw new ParseError("\u518D\u5E30 CTE \u306E seed \u3068\u518D\u5E30\u9805\u3067\u306F\u5217\u3092\u660E\u793A\u7684\u306B\u5C04\u5F71\u3057\u3066\u304F\u3060\u3055\u3044", token);
|
|
2059
|
+
}
|
|
2060
|
+
if (term.distinct || groupBy.length > 0 || term.grouping !== void 0 || term.having !== null || term.orderBy.length > 0 || term.orderMode !== "CANONICAL" || term.limit !== null || term.offset !== null) {
|
|
2061
|
+
throw new ParseError("\u518D\u5E30\u9805\u3067\u306F DISTINCT\u3001\u96C6\u8A08\u3001window\u3001GROUP BY\u3001HAVING\u3001ORDER BY\u3001LIMIT\u3001OFFSET \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", token);
|
|
2062
|
+
}
|
|
2063
|
+
if (term.joins.length !== 1 || term.joins[0].type !== "INNER") {
|
|
2064
|
+
throw new ParseError("\u518D\u5E30\u9805\u306F\u81EA\u5DF1\u53C2\u7167\u3068\u7269\u7406 source \u307E\u305F\u306F\u5148\u884C CTE \u306E INNER JOIN 1\u500B\u3067\u69CB\u6210\u3057\u3066\u304F\u3060\u3055\u3044", token);
|
|
2065
|
+
}
|
|
2066
|
+
const relationNames = [term.from.cteName, term.joins[0].table.cteName];
|
|
2067
|
+
if (relationNames.filter((value) => value === name).length !== 1) {
|
|
2068
|
+
throw new ParseError("\u518D\u5E30\u9805\u306E INNER JOIN \u306B\u306F\u81EA\u5DF1\u53C2\u7167\u3092\u3061\u3087\u3046\u30691\u56DE\u542B\u3081\u3066\u304F\u3060\u3055\u3044", token);
|
|
2069
|
+
}
|
|
2070
|
+
if (this.containsRecursiveForbiddenNode(term.columns) || this.containsRecursiveForbiddenNode(term.where)) {
|
|
2071
|
+
throw new ParseError("\u518D\u5E30\u9805\u3067\u306F\u96C6\u8A08\u3001window\u3001DISTINCT\u3001subquery \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", token);
|
|
2072
|
+
}
|
|
2073
|
+
const outputNames = columnAliases ?? seed.columns.map((column) => this.selectColumnOutputName(column));
|
|
2074
|
+
if (spec.cycle) {
|
|
2075
|
+
const cycleMatches = outputNames.filter((value) => value === spec.cycle.column).length;
|
|
2076
|
+
if (cycleMatches !== 1) {
|
|
2077
|
+
throw new ParseError("CYCLE \u5217\u306F\u518D\u5E30 CTE \u306E\u51FA\u529B\u52171\u500B\u3078\u4E00\u610F\u306B\u89E3\u6C7A\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059", token);
|
|
1942
2078
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2079
|
+
if (outputNames.includes(spec.cycle.markColumn)) {
|
|
2080
|
+
throw new ParseError("CYCLE \u306E mark \u5217\u306F\u518D\u5E30 CTE \u306E\u65E2\u5B58\u51FA\u529B\u5217\u3068\u540C\u540D\u306B\u3067\u304D\u307E\u305B\u3093", token);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
containsRecursiveForbiddenNode(value) {
|
|
2085
|
+
if (Array.isArray(value)) return value.some((item) => this.containsRecursiveForbiddenNode(item));
|
|
2086
|
+
if (value === null || typeof value !== "object") return false;
|
|
2087
|
+
const node = value;
|
|
2088
|
+
if (node.type === "AGGREGATE" || node.type === "AGG_REF" || node.type === "ARITH_AGG_COL" || node.type === "WINDOW_COL" || node.type === "SCALAR_SUBQUERY" || node.type === "SCALAR_SUBQUERY_COL" || node.type === "SUBQUERY_IN_LIST" || node.type === "EXISTS") return true;
|
|
2089
|
+
return Object.values(node).some((item) => this.containsRecursiveForbiddenNode(item));
|
|
2090
|
+
}
|
|
2091
|
+
selectColumnOutputName(column) {
|
|
2092
|
+
if ("alias" in column && typeof column.alias === "string") return column.alias;
|
|
2093
|
+
if (column.type === "FIELD") return column.field;
|
|
2094
|
+
return null;
|
|
1950
2095
|
}
|
|
1951
2096
|
parseGenerateSeries() {
|
|
1952
2097
|
const name = this.advance();
|
|
@@ -2985,6 +3130,15 @@ var Parser = class {
|
|
|
2985
3130
|
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
2986
3131
|
return { appId: 0, alias: alias2, cteName: name };
|
|
2987
3132
|
}
|
|
3133
|
+
if (this.activeCteDefinition?.name === name) {
|
|
3134
|
+
if (this.activeCteDefinition.recursiveWith && this.activeCteDefinition.phase === "RECURSIVE_TERM" && this.provisionalRecursiveCte?.name === name) {
|
|
3135
|
+
this.provisionalRecursiveCte.references++;
|
|
3136
|
+
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
3137
|
+
return { appId: 0, alias: alias2, cteName: name };
|
|
3138
|
+
}
|
|
3139
|
+
const message = this.activeCteDefinition.recursiveWith ? this.activeCteDefinition.phase === "RECURSIVE_TERM" ? "\u518D\u5E30 CTE \u306F seed SELECT UNION ALL recursive SELECT \u306E2\u5206\u5C90\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044" : "\u518D\u5E30 CTE \u306E seed \u304B\u3089\u81EA\u5206\u81EA\u8EAB\u3092\u53C2\u7167\u3067\u304D\u307E\u305B\u3093" : "CTE \u306E\u5B9A\u7FA9\u5185\u304B\u3089\u81EA\u5206\u81EA\u8EAB\u3092\u53C2\u7167\u3057\u3066\u3044\u307E\u3059\u3002\u81EA\u5DF1\u53C2\u7167\u306B\u306F `WITH RECURSIVE` \u304C\u5FC5\u8981\u3067\u3059";
|
|
3140
|
+
throw new ParseError(message, nameTok);
|
|
3141
|
+
}
|
|
2988
3142
|
const { appId, subtableCode } = extractTableRef(name, this.prev());
|
|
2989
3143
|
if (subtableCode) {
|
|
2990
3144
|
const alias2 = this.consume("AS" /* AS */) ? this.parseTableAliasName() : this.tryParseImplicitAlias();
|
|
@@ -12804,6 +12958,71 @@ function isOuterJoinNonPreservedTable(statement, table, isMainTable) {
|
|
|
12804
12958
|
return false;
|
|
12805
12959
|
}
|
|
12806
12960
|
|
|
12961
|
+
// src/core/recursiveCte.ts
|
|
12962
|
+
var RECURSIVE_CTE_MAX_DEPTH = 100;
|
|
12963
|
+
var RECURSIVE_CTE_MAX_ROWS = 1e4;
|
|
12964
|
+
var RECURSIVE_CTE_MAX_EXPANSIONS = 1e5;
|
|
12965
|
+
function resolveRecursiveCteLimits(options) {
|
|
12966
|
+
const entries = [
|
|
12967
|
+
["recursiveCteMaxDepth", options.recursiveCteMaxDepth, RECURSIVE_CTE_MAX_DEPTH],
|
|
12968
|
+
["recursiveCteMaxRows", options.recursiveCteMaxRows, RECURSIVE_CTE_MAX_ROWS],
|
|
12969
|
+
["recursiveCteMaxExpansions", options.recursiveCteMaxExpansions, RECURSIVE_CTE_MAX_EXPANSIONS]
|
|
12970
|
+
];
|
|
12971
|
+
for (const [name, value] of entries) {
|
|
12972
|
+
if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) {
|
|
12973
|
+
throw new RangeError(`${name} must be a positive safe integer`);
|
|
12974
|
+
}
|
|
12975
|
+
}
|
|
12976
|
+
return {
|
|
12977
|
+
depth: options.recursiveCteMaxDepth ?? RECURSIVE_CTE_MAX_DEPTH,
|
|
12978
|
+
rows: options.recursiveCteMaxRows ?? RECURSIVE_CTE_MAX_ROWS,
|
|
12979
|
+
expansions: options.recursiveCteMaxExpansions ?? RECURSIVE_CTE_MAX_EXPANSIONS
|
|
12980
|
+
};
|
|
12981
|
+
}
|
|
12982
|
+
var RecursiveCteLimitError = class extends Error {
|
|
12983
|
+
constructor(kind, limit, detected, cteName) {
|
|
12984
|
+
const label = kind === "DEPTH" ? "\u6DF1\u3055" : kind === "ROWS" ? "\u7D50\u679C\u884C\u6570" : "\u4E2D\u9593\u5C55\u958B\u6570";
|
|
12985
|
+
const unit = kind === "DEPTH" ? "" : " \u4EF6";
|
|
12986
|
+
super(`\u518D\u5E30 CTE\u300C${cteName}\u300D\u306E${label}\u304C\u4E0A\u9650 ${limit}${unit}\u3092\u8D85\u3048\u307E\u3057\u305F\uFF08\u691C\u51FA\u5024: ${detected}${unit}\uFF09\u3002`);
|
|
12987
|
+
this.name = "RecursiveCteLimitError";
|
|
12988
|
+
this.kind = kind;
|
|
12989
|
+
this.limit = limit;
|
|
12990
|
+
this.detected = detected;
|
|
12991
|
+
this.cteName = cteName;
|
|
12992
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
12993
|
+
}
|
|
12994
|
+
};
|
|
12995
|
+
var RecursiveCteLimitCounter = class {
|
|
12996
|
+
constructor(cteName, limits = resolveRecursiveCteLimits({})) {
|
|
12997
|
+
this.cteName = cteName;
|
|
12998
|
+
this.limits = limits;
|
|
12999
|
+
this.rows = 0;
|
|
13000
|
+
this.expansions = 0;
|
|
13001
|
+
}
|
|
13002
|
+
observeDepth(detected) {
|
|
13003
|
+
if (detected > this.limits.depth) {
|
|
13004
|
+
throw new RecursiveCteLimitError("DEPTH", this.limits.depth, detected, this.cteName);
|
|
13005
|
+
}
|
|
13006
|
+
}
|
|
13007
|
+
addRow() {
|
|
13008
|
+
this.rows++;
|
|
13009
|
+
if (this.rows > this.limits.rows) {
|
|
13010
|
+
throw new RecursiveCteLimitError("ROWS", this.limits.rows, this.rows, this.cteName);
|
|
13011
|
+
}
|
|
13012
|
+
}
|
|
13013
|
+
addExpansion() {
|
|
13014
|
+
this.expansions++;
|
|
13015
|
+
if (this.expansions > this.limits.expansions) {
|
|
13016
|
+
throw new RecursiveCteLimitError(
|
|
13017
|
+
"EXPANSIONS",
|
|
13018
|
+
this.limits.expansions,
|
|
13019
|
+
this.expansions,
|
|
13020
|
+
this.cteName
|
|
13021
|
+
);
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
};
|
|
13025
|
+
|
|
12807
13026
|
// src/core/optimization/joinKeyPrefilter.ts
|
|
12808
13027
|
var JOIN_KEY_IN_CHUNK_SIZE = 50;
|
|
12809
13028
|
function buildJoinKeyPrefilterQueries(plan, field, quoteValue) {
|
|
@@ -14245,8 +14464,15 @@ function applyJoin(leftRows, rightRows, join2, columns = {}) {
|
|
|
14245
14464
|
return result2;
|
|
14246
14465
|
}
|
|
14247
14466
|
const { on, type: joinType } = join2;
|
|
14248
|
-
const
|
|
14249
|
-
|
|
14467
|
+
const normalizedOn = normalizeJoinConditionSides(
|
|
14468
|
+
on,
|
|
14469
|
+
leftRows,
|
|
14470
|
+
rightRows,
|
|
14471
|
+
columns.leftColumns,
|
|
14472
|
+
columns.rightColumns
|
|
14473
|
+
);
|
|
14474
|
+
const leftKey = joinFieldKey(normalizedOn.left);
|
|
14475
|
+
const rightKey = joinFieldKey(normalizedOn.right);
|
|
14250
14476
|
assertJoinKeyAvailable(leftRows, leftKey, columns.leftColumns);
|
|
14251
14477
|
assertJoinKeyAvailable(rightRows, rightKey, columns.rightColumns);
|
|
14252
14478
|
if (joinType === "RIGHT") {
|
|
@@ -14294,6 +14520,37 @@ function applyJoin(leftRows, rightRows, join2, columns = {}) {
|
|
|
14294
14520
|
}
|
|
14295
14521
|
return result;
|
|
14296
14522
|
}
|
|
14523
|
+
function joinFieldKey(ref) {
|
|
14524
|
+
return ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
14525
|
+
}
|
|
14526
|
+
function normalizeJoinConditionSides(on, leftRows, rightRows, leftColumns, rightColumns) {
|
|
14527
|
+
const leftSchema = leftColumns ?? Object.keys(leftRows[0] ?? {});
|
|
14528
|
+
const rightSchema = rightColumns ?? Object.keys(rightRows[0] ?? {});
|
|
14529
|
+
const leftAliases = qualifiedAliases(leftSchema);
|
|
14530
|
+
const rightAliases = qualifiedAliases(rightSchema);
|
|
14531
|
+
const sideFor = (ref) => {
|
|
14532
|
+
if (ref.tableAlias) {
|
|
14533
|
+
const inLeft2 = leftAliases.has(ref.tableAlias);
|
|
14534
|
+
const inRight2 = rightAliases.has(ref.tableAlias);
|
|
14535
|
+
if (inLeft2 !== inRight2) return inLeft2 ? "LEFT" : "RIGHT";
|
|
14536
|
+
}
|
|
14537
|
+
const key = joinFieldKey(ref);
|
|
14538
|
+
const inLeft = leftSchema.includes(key);
|
|
14539
|
+
const inRight = rightSchema.includes(key);
|
|
14540
|
+
return inLeft !== inRight ? inLeft ? "LEFT" : "RIGHT" : "UNKNOWN";
|
|
14541
|
+
};
|
|
14542
|
+
const leftSide = sideFor(on.left);
|
|
14543
|
+
const rightSide = sideFor(on.right);
|
|
14544
|
+
return leftSide === "RIGHT" && rightSide === "LEFT" ? { left: on.right, right: on.left } : on;
|
|
14545
|
+
}
|
|
14546
|
+
function qualifiedAliases(columns) {
|
|
14547
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
14548
|
+
for (const column of columns) {
|
|
14549
|
+
const separator = column.indexOf(".");
|
|
14550
|
+
if (separator > 0) aliases.add(column.slice(0, separator));
|
|
14551
|
+
}
|
|
14552
|
+
return aliases;
|
|
14553
|
+
}
|
|
14297
14554
|
function assertJoinKeyAvailable(rows, key, savedColumns) {
|
|
14298
14555
|
const missing = rows.length > 0 ? rows.some((row) => !Object.prototype.hasOwnProperty.call(row, key)) : savedColumns !== void 0 && !savedColumns.includes(key);
|
|
14299
14556
|
if (missing) {
|
|
@@ -17331,6 +17588,7 @@ function createInvocationCacheContext(cacheContext) {
|
|
|
17331
17588
|
return `${cacheContext}\0inv:${nextCacheInvocationId++}`;
|
|
17332
17589
|
}
|
|
17333
17590
|
async function execute(sql, client, options = {}) {
|
|
17591
|
+
resolveRecursiveCteLimits(options);
|
|
17334
17592
|
const startedAt = Date.now();
|
|
17335
17593
|
const cacheContext = createInvocationCacheContext(
|
|
17336
17594
|
resolveCacheContext(client, options.cacheContext)
|
|
@@ -17642,7 +17900,10 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
17642
17900
|
options.cursorMaxActive ?? 2,
|
|
17643
17901
|
stmt.query.type === "UPDATE" && stmt.query.applyBlocks?.length ? resolveApplyGuardLimit(options.dmlMaxRows, "dmlMaxRows", DEFAULT_APPLY_MAX_ROWS) : DEFAULT_APPLY_MAX_ROWS,
|
|
17644
17902
|
stmt.query.type === "UPDATE" && stmt.query.applyBlocks?.length ? resolveApplyGuardLimit(options.dmlMaxSubtableRows, "dmlMaxSubtableRows", DEFAULT_APPLY_MAX_SUBTABLE_ROWS) : DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
17645
|
-
relativeDatePlan
|
|
17903
|
+
relativeDatePlan,
|
|
17904
|
+
options.recursiveCteMaxDepth,
|
|
17905
|
+
options.recursiveCteMaxRows,
|
|
17906
|
+
options.recursiveCteMaxExpansions
|
|
17646
17907
|
);
|
|
17647
17908
|
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
17648
17909
|
case "CREATE_TEMP_TABLE":
|
|
@@ -17914,6 +18175,7 @@ var BatchTimeoutError = class extends Error {
|
|
|
17914
18175
|
}
|
|
17915
18176
|
};
|
|
17916
18177
|
async function executeBatch(sql, client, options = {}) {
|
|
18178
|
+
resolveRecursiveCteLimits(options);
|
|
17917
18179
|
const statements = parseSqlBatch(sql, options.enableImport === true);
|
|
17918
18180
|
const analysis = analyzeBatch(statements);
|
|
17919
18181
|
statements.forEach((statement) => assertApplyExecutionScope("phase15b", statement));
|
|
@@ -18740,7 +19002,7 @@ function canProveTotalWindowOrder(stmt, orderBy, resolveField2, context, generat
|
|
|
18740
19002
|
}
|
|
18741
19003
|
function tieBreakAdvice(context, kind) {
|
|
18742
19004
|
if (context !== "DIRECT") {
|
|
18743
|
-
return "\
|
|
19005
|
+
return "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u5404\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u5185\u3067\u3001ORDER BY \u306E\u5024\u306E\u7D44\u304C\u5165\u529B\u884C\u3092\u4E00\u610F\u306B\u8B58\u5225\u3059\u308B\u3068\u30AF\u30A8\u30EA\u69CB\u9020\u307E\u305F\u306F\u4FDD\u8A3C\u6E08\u307F\u306E\u30C7\u30FC\u30BF\u5236\u7D04\u304B\u3089\u78BA\u8A8D\u3067\u304D\u308B\u5834\u5408\u306B\u9650\u308A\u3001\u3053\u306E\u8B66\u544A\u306F\u7121\u8996\u3067\u304D\u307E\u3059\u3002\u5143\u306E\u96C6\u7D04\u30AD\u30FC\u3092\u3059\u3079\u3066 ORDER BY \u306B\u542B\u3080\u5F62\u3084\u3001JOIN \u5F8C\u3082\u540C\u3058\u7CFB\u5217\u5024\u304C\u5404\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u5185\u3067\u9AD8\u30051\u884C\u3068\u4FDD\u8A3C\u3067\u304D\u308B\u5F62\u304C\u8A72\u5F53\u3057\u307E\u3059\u3002\u751F\u6210\u5217\u3001\u518D\u5E30\u306E\u6DF1\u3055\u5217\u3001\u307E\u305F\u306F $id \u306B\u7531\u6765\u3059\u308B\u5217\u3067\u3042\u308B\u3068\u3044\u3046\u7406\u7531\u3060\u3051\u3067\u306F\u7121\u8996\u3067\u304D\u307E\u305B\u3093\u3002";
|
|
18744
19006
|
}
|
|
18745
19007
|
return kind === "RANGE" ? "ORDER BY \u306B\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u306A\u3069\u306E\u30BF\u30A4\u30D6\u30EC\u30FC\u30AF\u30AD\u30FC\u3092\u8DB3\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "\u30EC\u30B3\u30FC\u30C9\u756A\u53F7\u7B49\u3092 ORDER BY \u306B\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
|
|
18746
19008
|
}
|
|
@@ -20629,6 +20891,53 @@ function assertUnionColumnCount(leftColumns, rightColumns) {
|
|
|
20629
20891
|
UNION \u306F\u5217\u3092\u4F4D\u7F6E\u3067\u5BFE\u5FDC\u3055\u305B\u308B\u305F\u3081\u3001\u4E21\u8FBA\u306E\u5217\u6570\u3092\u63C3\u3048\u3066\u304F\u3060\u3055\u3044`
|
|
20630
20892
|
);
|
|
20631
20893
|
}
|
|
20894
|
+
function alignSelectResultByPosition(result, targetColumns, targetMeta) {
|
|
20895
|
+
assertUnionColumnCount(targetColumns, result.columns);
|
|
20896
|
+
const rows = result.rows.map((row) => {
|
|
20897
|
+
const mapped = {};
|
|
20898
|
+
targetColumns.forEach((column, index) => {
|
|
20899
|
+
mapped[column] = row[result.columns[index] ?? column] ?? "";
|
|
20900
|
+
});
|
|
20901
|
+
return mapped;
|
|
20902
|
+
});
|
|
20903
|
+
const aligned = {
|
|
20904
|
+
...result,
|
|
20905
|
+
rows,
|
|
20906
|
+
columns: [...targetColumns],
|
|
20907
|
+
rowCount: rows.length
|
|
20908
|
+
};
|
|
20909
|
+
const sourceMeta = materializedMetaBySelectResult.get(result);
|
|
20910
|
+
if (targetMeta || sourceMeta) {
|
|
20911
|
+
const meta = /* @__PURE__ */ new Map();
|
|
20912
|
+
targetColumns.forEach((column, index) => {
|
|
20913
|
+
const sourceColumn = result.columns[index];
|
|
20914
|
+
const inferred = targetMeta?.get(column) ?? (sourceColumn === void 0 ? void 0 : sourceMeta?.get(sourceColumn));
|
|
20915
|
+
if (inferred) meta.set(column, { ...inferred, displayName: column });
|
|
20916
|
+
});
|
|
20917
|
+
materializedMetaBySelectResult.set(aligned, meta);
|
|
20918
|
+
}
|
|
20919
|
+
return aligned;
|
|
20920
|
+
}
|
|
20921
|
+
function combineUnionResults(leftResult, rightResult, all, captureColumnMeta) {
|
|
20922
|
+
const alignedRight = alignSelectResultByPosition(rightResult, leftResult.columns);
|
|
20923
|
+
const combined = [...leftResult.rows, ...alignedRight.rows];
|
|
20924
|
+
const rows = all ? combined : deduplicateRows(combined, leftResult.columns);
|
|
20925
|
+
const warnings = [.../* @__PURE__ */ new Set([
|
|
20926
|
+
...leftResult.warnings ?? [],
|
|
20927
|
+
...rightResult.warnings ?? []
|
|
20928
|
+
])];
|
|
20929
|
+
const result = {
|
|
20930
|
+
type: "SELECT",
|
|
20931
|
+
rows,
|
|
20932
|
+
columns: [...leftResult.columns],
|
|
20933
|
+
rowCount: rows.length,
|
|
20934
|
+
warnings
|
|
20935
|
+
};
|
|
20936
|
+
if (captureColumnMeta) {
|
|
20937
|
+
materializedMetaBySelectResult.set(result, mergeUnionColumnMeta(leftResult, rightResult));
|
|
20938
|
+
}
|
|
20939
|
+
return result;
|
|
20940
|
+
}
|
|
20632
20941
|
async function executeUnion(stmt, client, options, cacheContext, captureColumnMeta = false, forLibraryCapture = false) {
|
|
20633
20942
|
const completePolicy = buildCompleteInputPolicy(stmt, options, null);
|
|
20634
20943
|
return withCompleteInputPolicy(completePolicy, async () => {
|
|
@@ -20662,33 +20971,7 @@ async function executeUnion(stmt, client, options, cacheContext, captureColumnMe
|
|
|
20662
20971
|
"DERIVED"
|
|
20663
20972
|
)
|
|
20664
20973
|
]);
|
|
20665
|
-
|
|
20666
|
-
const rightCols = rightResult.columns;
|
|
20667
|
-
assertUnionColumnCount(leftCols, rightCols);
|
|
20668
|
-
const remappedRight = rightResult.rows.map((row) => {
|
|
20669
|
-
const mapped = {};
|
|
20670
|
-
leftCols.forEach((col, i) => {
|
|
20671
|
-
mapped[col] = row[rightCols[i] ?? col] ?? "";
|
|
20672
|
-
});
|
|
20673
|
-
return mapped;
|
|
20674
|
-
});
|
|
20675
|
-
const combined = [...leftResult.rows, ...remappedRight];
|
|
20676
|
-
const rows = stmt.all ? combined : deduplicateRows(combined, leftCols);
|
|
20677
|
-
const warnings = [.../* @__PURE__ */ new Set([
|
|
20678
|
-
...leftResult.warnings ?? [],
|
|
20679
|
-
...rightResult.warnings ?? []
|
|
20680
|
-
])];
|
|
20681
|
-
const result = {
|
|
20682
|
-
type: "SELECT",
|
|
20683
|
-
rows,
|
|
20684
|
-
columns: leftCols,
|
|
20685
|
-
rowCount: rows.length,
|
|
20686
|
-
warnings
|
|
20687
|
-
};
|
|
20688
|
-
if (captureColumnMeta) {
|
|
20689
|
-
materializedMetaBySelectResult.set(result, mergeUnionColumnMeta(leftResult, rightResult));
|
|
20690
|
-
}
|
|
20691
|
-
return result;
|
|
20974
|
+
return combineUnionResults(leftResult, rightResult, stmt.all, captureColumnMeta);
|
|
20692
20975
|
});
|
|
20693
20976
|
}
|
|
20694
20977
|
function deduplicateRows(rows, columns) {
|
|
@@ -20700,6 +20983,442 @@ function deduplicateRows(rows, columns) {
|
|
|
20700
20983
|
return true;
|
|
20701
20984
|
});
|
|
20702
20985
|
}
|
|
20986
|
+
function recursiveSelectOutputName(column) {
|
|
20987
|
+
if ("alias" in column && typeof column.alias === "string") return column.alias;
|
|
20988
|
+
if (column.type === "FIELD") return column.field;
|
|
20989
|
+
return null;
|
|
20990
|
+
}
|
|
20991
|
+
function recursiveOutputColumns(cte) {
|
|
20992
|
+
const spec = cte.recursiveSpec;
|
|
20993
|
+
if (cte.columnAliases) return [...cte.columnAliases];
|
|
20994
|
+
const names = spec.seed.columns.map(recursiveSelectOutputName);
|
|
20995
|
+
if (names.some((name) => name === null)) {
|
|
20996
|
+
throw new Error(
|
|
20997
|
+
`PlanningError: \u518D\u5E30 CTE\u300C${cte.name}\u300D\u3067\u5217\u540D\u30EA\u30B9\u30C8\u3092\u7701\u7565\u3059\u308B\u5834\u5408\u3001seed \u306E\u5F0F\u306B\u306F AS \u5225\u540D\u304C\u5FC5\u8981\u3067\u3059`
|
|
20998
|
+
);
|
|
20999
|
+
}
|
|
21000
|
+
const columns = names;
|
|
21001
|
+
if (new Set(columns).size !== columns.length) {
|
|
21002
|
+
throw new Error(
|
|
21003
|
+
`PlanningError: \u518D\u5E30 CTE\u300C${cte.name}\u300D\u3067\u5217\u540D\u30EA\u30B9\u30C8\u3092\u7701\u7565\u3059\u308B\u5834\u5408\u3001seed \u306E\u51FA\u529B\u5217\u540D\u3092\u91CD\u8907\u3055\u305B\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093`
|
|
21004
|
+
);
|
|
21005
|
+
}
|
|
21006
|
+
return columns;
|
|
21007
|
+
}
|
|
21008
|
+
function recursivePlanningColumnNames(stmt) {
|
|
21009
|
+
return stmt.columns.map((column, index) => recursiveSelectOutputName(column) ?? `__b53_column_${index}`);
|
|
21010
|
+
}
|
|
21011
|
+
function recursiveMetaCompatible(left, right) {
|
|
21012
|
+
const a = left.semantics;
|
|
21013
|
+
const b = right.semantics;
|
|
21014
|
+
if (!a || !b || a.compareMode === "unsupported" || b.compareMode === "unsupported") return false;
|
|
21015
|
+
if (a.compareMode !== b.compareMode) return false;
|
|
21016
|
+
if (left.sortKind && right.sortKind && left.sortKind !== right.sortKind) return false;
|
|
21017
|
+
if (a.inSubtable !== b.inSubtable || a.requiresCollectionOperators !== b.requiresCollectionOperators) return false;
|
|
21018
|
+
const synthetic = (fieldType) => fieldType === void 0 || fieldType.startsWith("KSQL_");
|
|
21019
|
+
if (!synthetic(left.fieldType) && !synthetic(right.fieldType) && left.fieldType !== right.fieldType) return false;
|
|
21020
|
+
return true;
|
|
21021
|
+
}
|
|
21022
|
+
async function buildRecursiveFieldResolver(stmt, client, cacheContext, materializedTables) {
|
|
21023
|
+
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
21024
|
+
const physical = /* @__PURE__ */ new Map();
|
|
21025
|
+
await Promise.all(tables.filter((table) => table.cteName === null).map(async (table) => {
|
|
21026
|
+
if (physical.has(table.appId)) return;
|
|
21027
|
+
const infos = await getFieldsCached(table.appId, client, cacheContext);
|
|
21028
|
+
physical.set(table.appId, new Map(infos.map((info) => [info.code, info])));
|
|
21029
|
+
}));
|
|
21030
|
+
const resolveInTable = (table, field) => {
|
|
21031
|
+
if (table.cteName !== null) return materializedTables.get(table.cteName)?.columnMeta?.get(field);
|
|
21032
|
+
const info = physical.get(table.appId)?.get(fieldCodeForTypeLookup(table, field));
|
|
21033
|
+
return info ? materializedMetaFromFieldInfo(info, table.appId) : systemColumnMeta(field);
|
|
21034
|
+
};
|
|
21035
|
+
return (ref) => {
|
|
21036
|
+
if (ref.tableAlias !== null) {
|
|
21037
|
+
const table = tables.find((candidate) => effectiveTableAlias(candidate) === ref.tableAlias);
|
|
21038
|
+
return table ? resolveInTable(table, ref.field) : void 0;
|
|
21039
|
+
}
|
|
21040
|
+
if (tables.length === 1) return resolveInTable(tables[0], ref.field);
|
|
21041
|
+
const matches = tables.map((table) => resolveInTable(table, ref.field)).filter(
|
|
21042
|
+
(meta) => meta !== void 0
|
|
21043
|
+
);
|
|
21044
|
+
return matches.length === 1 ? matches[0] : void 0;
|
|
21045
|
+
};
|
|
21046
|
+
}
|
|
21047
|
+
function validateRecursiveProjectionNode(value, resolveField2, numeric = false) {
|
|
21048
|
+
if (value === null || typeof value !== "object") return;
|
|
21049
|
+
if (Array.isArray(value)) {
|
|
21050
|
+
value.forEach((item) => validateRecursiveProjectionNode(item, resolveField2, numeric));
|
|
21051
|
+
return;
|
|
21052
|
+
}
|
|
21053
|
+
const node = value;
|
|
21054
|
+
if (node.type === "FIELD") {
|
|
21055
|
+
const ref = typeof node.tableAlias === "string" || node.tableAlias === null ? node : aggregateFieldRef(String(node.field ?? ""));
|
|
21056
|
+
const meta = resolveField2(ref);
|
|
21057
|
+
if (!meta?.semantics || meta.semantics.compareMode === "unsupported") {
|
|
21058
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE \u306E\u5C04\u5F71\u5217 ${ref.tableAlias ? `${ref.tableAlias}.` : ""}${ref.field} \u306E\u578B\u3092\u8A3C\u660E\u3067\u304D\u307E\u305B\u3093`);
|
|
21059
|
+
}
|
|
21060
|
+
if (numeric && meta.semantics.compareMode !== "number" && meta.semantics.compareMode !== "recordNumber") {
|
|
21061
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE \u306E\u6570\u5024\u6F14\u7B97\u306B\u6570\u5024\u3067\u306A\u3044\u5217 ${ref.field} \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
|
|
21062
|
+
}
|
|
21063
|
+
return;
|
|
21064
|
+
}
|
|
21065
|
+
if (node.type === "FIELD_REF" && typeof node.field === "string") {
|
|
21066
|
+
const ref = aggregateFieldRef(node.field);
|
|
21067
|
+
const meta = resolveField2(ref);
|
|
21068
|
+
if (!meta?.semantics || meta.semantics.compareMode === "unsupported") {
|
|
21069
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE \u306E\u5C04\u5F71\u5217 ${node.field} \u306E\u578B\u3092\u8A3C\u660E\u3067\u304D\u307E\u305B\u3093`);
|
|
21070
|
+
}
|
|
21071
|
+
if (numeric && meta.semantics.compareMode !== "number" && meta.semantics.compareMode !== "recordNumber") {
|
|
21072
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE \u306E\u6570\u5024\u6F14\u7B97\u306B\u6570\u5024\u3067\u306A\u3044\u5217 ${node.field} \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
|
|
21073
|
+
}
|
|
21074
|
+
return;
|
|
21075
|
+
}
|
|
21076
|
+
if (node.type === "ARITH" || node.type === "SCALAR_ARITH") {
|
|
21077
|
+
validateRecursiveProjectionNode(node.left, resolveField2, true);
|
|
21078
|
+
validateRecursiveProjectionNode(node.right, resolveField2, true);
|
|
21079
|
+
return;
|
|
21080
|
+
}
|
|
21081
|
+
for (const child of Object.values(node)) validateRecursiveProjectionNode(child, resolveField2, numeric);
|
|
21082
|
+
}
|
|
21083
|
+
async function inferRecursiveProjectionMeta(stmt, outputColumns, client, cacheContext, materializedTables) {
|
|
21084
|
+
const resolveField2 = await buildRecursiveFieldResolver(stmt, client, cacheContext, materializedTables);
|
|
21085
|
+
stmt.columns.forEach((column) => validateRecursiveProjectionNode(column, resolveField2));
|
|
21086
|
+
const inferred = await inferSelectColumnMeta(
|
|
21087
|
+
stmt,
|
|
21088
|
+
recursivePlanningColumnNames(stmt),
|
|
21089
|
+
client,
|
|
21090
|
+
cacheContext,
|
|
21091
|
+
materializedTables
|
|
21092
|
+
);
|
|
21093
|
+
const sourceNames = recursivePlanningColumnNames(stmt);
|
|
21094
|
+
const aligned = /* @__PURE__ */ new Map();
|
|
21095
|
+
outputColumns.forEach((column, index) => {
|
|
21096
|
+
const meta = inferred.get(sourceNames[index]);
|
|
21097
|
+
if (!meta?.semantics || meta.semantics.fieldType === "KSQL_UNKNOWN" || meta.semantics.compareMode === "unsupported") {
|
|
21098
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE \u306E\u7B2C ${index + 1} \u5217\u306E\u578B\u3092\u9759\u7684\u306B\u8A3C\u660E\u3067\u304D\u307E\u305B\u3093`);
|
|
21099
|
+
}
|
|
21100
|
+
aligned.set(column, { ...meta, displayName: column });
|
|
21101
|
+
});
|
|
21102
|
+
return aligned;
|
|
21103
|
+
}
|
|
21104
|
+
function recursivePhysicalSourceKey(table) {
|
|
21105
|
+
return `${table.appId}:${table.subtableCode ?? ""}`;
|
|
21106
|
+
}
|
|
21107
|
+
function recursivePhysicalTables(...queries) {
|
|
21108
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
21109
|
+
for (const query of queries) {
|
|
21110
|
+
for (const table of [query.from, ...query.joins.map((join2) => join2.table)]) {
|
|
21111
|
+
if (table.cteName === null && !byKey.has(recursivePhysicalSourceKey(table))) {
|
|
21112
|
+
byKey.set(recursivePhysicalSourceKey(table), table);
|
|
21113
|
+
}
|
|
21114
|
+
}
|
|
21115
|
+
}
|
|
21116
|
+
return [...byKey.values()];
|
|
21117
|
+
}
|
|
21118
|
+
function splitRecursiveFieldRef(field) {
|
|
21119
|
+
const dot = field.indexOf(".");
|
|
21120
|
+
return dot < 0 ? { alias: null, field } : { alias: field.slice(0, dot), field: field.slice(dot + 1) };
|
|
21121
|
+
}
|
|
21122
|
+
function collectRecursivePhysicalSourceFields(queries) {
|
|
21123
|
+
const result = /* @__PURE__ */ new Map();
|
|
21124
|
+
const markAll = (tables) => {
|
|
21125
|
+
for (const table of tables) result.set(recursivePhysicalSourceKey(table), null);
|
|
21126
|
+
};
|
|
21127
|
+
for (const query of queries) {
|
|
21128
|
+
const physical = physicalSelectTables(query);
|
|
21129
|
+
for (const table of physical) {
|
|
21130
|
+
const key = recursivePhysicalSourceKey(table);
|
|
21131
|
+
if (!result.has(key)) result.set(key, /* @__PURE__ */ new Set());
|
|
21132
|
+
}
|
|
21133
|
+
const addRef = (rawAlias, field) => {
|
|
21134
|
+
const table = rawAlias === null ? physical.length === 1 ? physical[0] : void 0 : [query.from, ...query.joins.map((join2) => join2.table)].find((candidate) => effectiveTableAlias(candidate)?.toLowerCase() === rawAlias.toLowerCase());
|
|
21135
|
+
if (!table) {
|
|
21136
|
+
markAll(physical);
|
|
21137
|
+
return;
|
|
21138
|
+
}
|
|
21139
|
+
if (table.cteName !== null) return;
|
|
21140
|
+
const current = result.get(recursivePhysicalSourceKey(table));
|
|
21141
|
+
if (current !== null) current?.add(field);
|
|
21142
|
+
};
|
|
21143
|
+
const visit = (node) => {
|
|
21144
|
+
if (node === null || node === void 0 || typeof node !== "object") return;
|
|
21145
|
+
if (Array.isArray(node)) {
|
|
21146
|
+
node.forEach(visit);
|
|
21147
|
+
return;
|
|
21148
|
+
}
|
|
21149
|
+
const value = node;
|
|
21150
|
+
if (value.type === "WILDCARD" || value.type === "PARENT_WILDCARD") {
|
|
21151
|
+
markAll(physical);
|
|
21152
|
+
return;
|
|
21153
|
+
}
|
|
21154
|
+
if ((value.type === "FIELD" || value.type === "FIELD_REF") && typeof value.field === "string") {
|
|
21155
|
+
const encoded = splitRecursiveFieldRef(value.field);
|
|
21156
|
+
const alias = typeof value.tableAlias === "string" ? value.tableAlias : value.tableAlias === null ? null : encoded.alias;
|
|
21157
|
+
addRef(alias, encoded.field);
|
|
21158
|
+
return;
|
|
21159
|
+
}
|
|
21160
|
+
if ((value.type === "FIELD_NAME" || value.type === "GROUPING_REF") && typeof value.name === "string") {
|
|
21161
|
+
markAll(physical);
|
|
21162
|
+
return;
|
|
21163
|
+
}
|
|
21164
|
+
Object.values(value).forEach(visit);
|
|
21165
|
+
};
|
|
21166
|
+
visit(query.columns);
|
|
21167
|
+
visit(query.where);
|
|
21168
|
+
visit(normalizeGroupingSpec(query));
|
|
21169
|
+
visit(query.having);
|
|
21170
|
+
visit(query.orderBy);
|
|
21171
|
+
for (const join2 of query.joins) {
|
|
21172
|
+
if (join2.on === null) {
|
|
21173
|
+
markAll(physical);
|
|
21174
|
+
continue;
|
|
21175
|
+
}
|
|
21176
|
+
addRef(join2.on.left.tableAlias, join2.on.left.field);
|
|
21177
|
+
addRef(join2.on.right.tableAlias, join2.on.right.field);
|
|
21178
|
+
}
|
|
21179
|
+
}
|
|
21180
|
+
return result;
|
|
21181
|
+
}
|
|
21182
|
+
function recursiveSourceSelect(table, fields) {
|
|
21183
|
+
const columns = fields !== null && fields.size > 0 ? [...fields].map((field) => ({ type: "FIELD", field, alias: null })) : [{ type: "WILDCARD" }];
|
|
21184
|
+
return {
|
|
21185
|
+
type: "SELECT",
|
|
21186
|
+
distinct: false,
|
|
21187
|
+
columns,
|
|
21188
|
+
from: { ...table, alias: null },
|
|
21189
|
+
joins: [],
|
|
21190
|
+
where: null,
|
|
21191
|
+
groupBy: [],
|
|
21192
|
+
having: null,
|
|
21193
|
+
orderMode: "CANONICAL",
|
|
21194
|
+
orderBy: [],
|
|
21195
|
+
limit: null,
|
|
21196
|
+
offset: null
|
|
21197
|
+
};
|
|
21198
|
+
}
|
|
21199
|
+
async function materializeRecursivePhysicalSources(queries, client, options, cacheContext) {
|
|
21200
|
+
const fieldsBySource = collectRecursivePhysicalSourceFields(queries);
|
|
21201
|
+
const entries = await Promise.all(recursivePhysicalTables(...queries).map(async (table, index) => {
|
|
21202
|
+
const result = await executeSelect(
|
|
21203
|
+
recursiveSourceSelect(table, fieldsBySource.get(recursivePhysicalSourceKey(table)) ?? null),
|
|
21204
|
+
client,
|
|
21205
|
+
{ ...options, onLimitReached: "error" },
|
|
21206
|
+
cacheContext,
|
|
21207
|
+
void 0,
|
|
21208
|
+
true,
|
|
21209
|
+
false,
|
|
21210
|
+
"DERIVED"
|
|
21211
|
+
);
|
|
21212
|
+
const name = `__b53_source_${index}`;
|
|
21213
|
+
return [recursivePhysicalSourceKey(table), {
|
|
21214
|
+
name,
|
|
21215
|
+
warnings: result.warnings ?? [],
|
|
21216
|
+
table: {
|
|
21217
|
+
rows: result.rows,
|
|
21218
|
+
columns: result.columns,
|
|
21219
|
+
columnMeta: materializedMetaBySelectResult.get(result)
|
|
21220
|
+
}
|
|
21221
|
+
}];
|
|
21222
|
+
}));
|
|
21223
|
+
return new Map(entries);
|
|
21224
|
+
}
|
|
21225
|
+
function rewriteRecursivePhysicalSources(stmt, sources) {
|
|
21226
|
+
const rewrite = (table) => {
|
|
21227
|
+
if (table.cteName !== null) return table;
|
|
21228
|
+
const source = sources.get(recursivePhysicalSourceKey(table));
|
|
21229
|
+
if (!source) throw new Error("PlanningError: \u518D\u5E30 CTE \u306E\u5B8C\u5168\u5B9F\u4F53\u5316 source \u3092\u89E3\u6C7A\u3067\u304D\u307E\u305B\u3093");
|
|
21230
|
+
return { appId: 0, alias: table.alias, cteName: source.name, subtableCode: null };
|
|
21231
|
+
};
|
|
21232
|
+
return {
|
|
21233
|
+
...stmt,
|
|
21234
|
+
from: rewrite(stmt.from),
|
|
21235
|
+
joins: stmt.joins.map((join2) => ({ ...join2, table: rewrite(join2.table) }))
|
|
21236
|
+
};
|
|
21237
|
+
}
|
|
21238
|
+
function tableMetaForJoinKey(table, field, cache) {
|
|
21239
|
+
return table.cteName === null ? void 0 : cache.get(table.cteName)?.columnMeta?.get(field);
|
|
21240
|
+
}
|
|
21241
|
+
function recursiveJoinKey(value, semantics) {
|
|
21242
|
+
if (semantics.compareMode !== "number" && semantics.compareMode !== "recordNumber") return value;
|
|
21243
|
+
const decimal = parseExactDecimal(value);
|
|
21244
|
+
return decimal === null ? `invalid:${value}` : `${decimal.sign}:${decimal.coefficient}:${decimal.scale}`;
|
|
21245
|
+
}
|
|
21246
|
+
function recursiveJoinSides(cteName, term) {
|
|
21247
|
+
const join2 = term.joins[0];
|
|
21248
|
+
if (!join2 || join2.type !== "INNER") throw new Error("PlanningError: \u518D\u5E30\u9805\u306E INNER JOIN \u3092\u89E3\u6C7A\u3067\u304D\u307E\u305B\u3093");
|
|
21249
|
+
const self = term.from.cteName === cteName ? term.from : join2.table;
|
|
21250
|
+
const source = self === term.from ? join2.table : term.from;
|
|
21251
|
+
const selfAlias = effectiveTableAlias(self);
|
|
21252
|
+
const leftIsSelf = join2.on.left.tableAlias === selfAlias;
|
|
21253
|
+
const rightIsSelf = join2.on.right.tableAlias === selfAlias;
|
|
21254
|
+
if (leftIsSelf === rightIsSelf) throw new Error("PlanningError: \u518D\u5E30\u9805\u306E\u81EA\u5DF1\u53C2\u7167 JOIN \u30AD\u30FC\u3092\u4E00\u610F\u306B\u89E3\u6C7A\u3067\u304D\u307E\u305B\u3093");
|
|
21255
|
+
return {
|
|
21256
|
+
self,
|
|
21257
|
+
source,
|
|
21258
|
+
selfField: leftIsSelf ? join2.on.left.field : join2.on.right.field,
|
|
21259
|
+
sourceField: leftIsSelf ? join2.on.right.field : join2.on.left.field
|
|
21260
|
+
};
|
|
21261
|
+
}
|
|
21262
|
+
async function executeRecursiveCte(cte, client, options, cteCache, cacheContext) {
|
|
21263
|
+
const spec = cte.recursiveSpec;
|
|
21264
|
+
const outputColumns = recursiveOutputColumns(cte);
|
|
21265
|
+
const seedMeta = await inferRecursiveProjectionMeta(
|
|
21266
|
+
spec.seed,
|
|
21267
|
+
outputColumns,
|
|
21268
|
+
client,
|
|
21269
|
+
cacheContext,
|
|
21270
|
+
cteCache
|
|
21271
|
+
);
|
|
21272
|
+
const planningCache = new Map(cteCache);
|
|
21273
|
+
planningCache.set(cte.name, { rows: [], columns: outputColumns, columnMeta: seedMeta });
|
|
21274
|
+
const termMeta = await inferRecursiveProjectionMeta(
|
|
21275
|
+
spec.recursiveTerm,
|
|
21276
|
+
outputColumns,
|
|
21277
|
+
client,
|
|
21278
|
+
cacheContext,
|
|
21279
|
+
planningCache
|
|
21280
|
+
);
|
|
21281
|
+
outputColumns.forEach((column, index) => {
|
|
21282
|
+
const left = seedMeta.get(column);
|
|
21283
|
+
const right = termMeta.get(column);
|
|
21284
|
+
if (!left || !right || !recursiveMetaCompatible(left, right)) {
|
|
21285
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE\u300C${cte.name}\u300D\u306E\u7B2C ${index + 1} \u5217\u3067 seed \u3068\u518D\u5E30\u9805\u306E\u578B\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093`);
|
|
21286
|
+
}
|
|
21287
|
+
});
|
|
21288
|
+
const planningSides = recursiveJoinSides(cte.name, spec.recursiveTerm);
|
|
21289
|
+
const termFieldResolver = await buildRecursiveFieldResolver(
|
|
21290
|
+
spec.recursiveTerm,
|
|
21291
|
+
client,
|
|
21292
|
+
cacheContext,
|
|
21293
|
+
planningCache
|
|
21294
|
+
);
|
|
21295
|
+
const selfJoinMeta = termFieldResolver({
|
|
21296
|
+
type: "FIELD",
|
|
21297
|
+
tableAlias: effectiveTableAlias(planningSides.self),
|
|
21298
|
+
field: planningSides.selfField
|
|
21299
|
+
});
|
|
21300
|
+
const sourceJoinMeta = termFieldResolver({
|
|
21301
|
+
type: "FIELD",
|
|
21302
|
+
tableAlias: effectiveTableAlias(planningSides.source),
|
|
21303
|
+
field: planningSides.sourceField
|
|
21304
|
+
});
|
|
21305
|
+
if (!selfJoinMeta || !sourceJoinMeta || !recursiveMetaCompatible(selfJoinMeta, sourceJoinMeta)) {
|
|
21306
|
+
throw new Error(`PlanningError: \u518D\u5E30 CTE\u300C${cte.name}\u300D\u306E\u81EA\u5DF1\u53C2\u7167 JOIN \u30AD\u30FC\u306E\u578B\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093`);
|
|
21307
|
+
}
|
|
21308
|
+
const sources = await materializeRecursivePhysicalSources(
|
|
21309
|
+
[spec.seed, spec.recursiveTerm],
|
|
21310
|
+
client,
|
|
21311
|
+
options,
|
|
21312
|
+
cacheContext
|
|
21313
|
+
);
|
|
21314
|
+
const runtimeCache = new Map(cteCache);
|
|
21315
|
+
for (const source of sources.values()) runtimeCache.set(source.name, source.table);
|
|
21316
|
+
const seedQuery = rewriteRecursivePhysicalSources(spec.seed, sources);
|
|
21317
|
+
const termQuery = rewriteRecursivePhysicalSources(spec.recursiveTerm, sources);
|
|
21318
|
+
const rawSeed = await executeQueryWithCte(seedQuery, client, options, runtimeCache, cacheContext, true, true);
|
|
21319
|
+
const seed = alignSelectResultByPosition(rawSeed, outputColumns, seedMeta);
|
|
21320
|
+
const cycle = spec.cycle;
|
|
21321
|
+
const cycleMeta = cycle ? seedMeta.get(cycle.column) : void 0;
|
|
21322
|
+
const resultMeta = new Map(seedMeta);
|
|
21323
|
+
if (cycle) resultMeta.set(cycle.markColumn, { ...syntheticColumnMeta("string"), displayName: cycle.markColumn });
|
|
21324
|
+
const resultColumns = cycle ? [...outputColumns, cycle.markColumn] : [...outputColumns];
|
|
21325
|
+
const rows = [];
|
|
21326
|
+
let frontier = [];
|
|
21327
|
+
const warnings = /* @__PURE__ */ new Set([
|
|
21328
|
+
...seed.warnings ?? [],
|
|
21329
|
+
...[...sources.values()].flatMap((source) => source.warnings)
|
|
21330
|
+
]);
|
|
21331
|
+
const limits = new RecursiveCteLimitCounter(cte.name, resolveRecursiveCteLimits(options));
|
|
21332
|
+
const append = (row) => {
|
|
21333
|
+
limits.addRow();
|
|
21334
|
+
rows.push(row);
|
|
21335
|
+
};
|
|
21336
|
+
for (const row of seed.rows) {
|
|
21337
|
+
const value = cycle ? String(row[cycle.column] ?? "") : "";
|
|
21338
|
+
const emitted = cycle ? { ...row, [cycle.markColumn]: cycle.defaultValue } : row;
|
|
21339
|
+
append(emitted);
|
|
21340
|
+
frontier.push({ row, path: cycle ? [value] : [] });
|
|
21341
|
+
}
|
|
21342
|
+
const sides = recursiveJoinSides(cte.name, termQuery);
|
|
21343
|
+
const sourceTable = sides.source.cteName === null ? void 0 : runtimeCache.get(sides.source.cteName);
|
|
21344
|
+
if (!sourceTable) throw new Error("PlanningError: \u518D\u5E30\u9805\u306E\u5B8C\u5168\u5B9F\u4F53\u5316 source \u304C\u3042\u308A\u307E\u305B\u3093");
|
|
21345
|
+
const joinMeta = tableMetaForJoinKey(sides.self, sides.selfField, planningCache) ?? tableMetaForJoinKey(sides.source, sides.sourceField, runtimeCache);
|
|
21346
|
+
if (!joinMeta?.semantics || joinMeta.semantics.compareMode === "unsupported") {
|
|
21347
|
+
throw new Error(`PlanningError: \u518D\u5E30\u9805\u306E JOIN \u30AD\u30FC ${sides.selfField} \u306E\u578B\u3092\u8A3C\u660E\u3067\u304D\u307E\u305B\u3093`);
|
|
21348
|
+
}
|
|
21349
|
+
const sourceRowsByKey = /* @__PURE__ */ new Map();
|
|
21350
|
+
for (const sourceRow of sourceTable.rows) {
|
|
21351
|
+
const value = String(sourceRow[sides.sourceField] ?? "");
|
|
21352
|
+
const key = recursiveJoinKey(value, joinMeta.semantics);
|
|
21353
|
+
const bucket = sourceRowsByKey.get(key);
|
|
21354
|
+
if (bucket) bucket.push(sourceRow);
|
|
21355
|
+
else sourceRowsByKey.set(key, [sourceRow]);
|
|
21356
|
+
}
|
|
21357
|
+
const sourceHasEmptyKey = sourceRowsByKey.has(recursiveJoinKey("", joinMeta.semantics));
|
|
21358
|
+
let depth = 0;
|
|
21359
|
+
let emptyKeyWarned = false;
|
|
21360
|
+
while (frontier.length > 0) {
|
|
21361
|
+
depth++;
|
|
21362
|
+
const next = [];
|
|
21363
|
+
for (const parent of frontier) {
|
|
21364
|
+
const parentKey = String(parent.row[sides.selfField] ?? "");
|
|
21365
|
+
if (!emptyKeyWarned && parentKey === "" && sourceHasEmptyKey) {
|
|
21366
|
+
warnings.add(
|
|
21367
|
+
`\u518D\u5E30 CTE\u300C${cte.name}\u300D\u306E JOIN ${sides.selfField} = ${sides.sourceField} \u3067\u7B2C ${depth} \u53CD\u5FA9\u306B\u4E21\u5074\u306E\u7A7A\u30AD\u30FC\u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002\u7A7A\u30AD\u30FC\u3069\u3046\u3057\u306F\u4E00\u81F4\u3057\u3001\u30EB\u30FC\u30C8\u7FA4\u3092\u518D\u5C55\u958B\u3057\u5F97\u307E\u3059\u3002`
|
|
21368
|
+
);
|
|
21369
|
+
emptyKeyWarned = true;
|
|
21370
|
+
}
|
|
21371
|
+
const matchingSourceRows = sourceRowsByKey.get(recursiveJoinKey(parentKey, joinMeta.semantics)) ?? [];
|
|
21372
|
+
for (const sourceRow of matchingSourceRows) {
|
|
21373
|
+
const sourceKey = String(sourceRow[sides.sourceField] ?? "");
|
|
21374
|
+
if (!compareScalarValues("=", parentKey, sourceKey, joinMeta.semantics)) continue;
|
|
21375
|
+
limits.addExpansion();
|
|
21376
|
+
}
|
|
21377
|
+
if (matchingSourceRows.length === 0) continue;
|
|
21378
|
+
const iterationCache = new Map(runtimeCache);
|
|
21379
|
+
iterationCache.set(cte.name, {
|
|
21380
|
+
rows: [parent.row],
|
|
21381
|
+
columns: outputColumns,
|
|
21382
|
+
columnMeta: seedMeta
|
|
21383
|
+
});
|
|
21384
|
+
const rawCandidates = await executeQueryWithCte(
|
|
21385
|
+
termQuery,
|
|
21386
|
+
client,
|
|
21387
|
+
options,
|
|
21388
|
+
iterationCache,
|
|
21389
|
+
cacheContext,
|
|
21390
|
+
true,
|
|
21391
|
+
true
|
|
21392
|
+
);
|
|
21393
|
+
for (const warning of rawCandidates.warnings ?? []) warnings.add(warning);
|
|
21394
|
+
const candidates = alignSelectResultByPosition(rawCandidates, outputColumns, seedMeta);
|
|
21395
|
+
if (candidates.rows.length > 0) limits.observeDepth(depth);
|
|
21396
|
+
for (const candidate of candidates.rows) {
|
|
21397
|
+
if (!cycle) {
|
|
21398
|
+
append(candidate);
|
|
21399
|
+
next.push({ row: candidate, path: [] });
|
|
21400
|
+
continue;
|
|
21401
|
+
}
|
|
21402
|
+
const value = String(candidate[cycle.column] ?? "");
|
|
21403
|
+
const isCycle = parent.path.some(
|
|
21404
|
+
(seen) => compareScalarValues("=", seen, value, cycleMeta.semantics)
|
|
21405
|
+
);
|
|
21406
|
+
append({ ...candidate, [cycle.markColumn]: isCycle ? cycle.markValue : cycle.defaultValue });
|
|
21407
|
+
if (!isCycle) next.push({ row: candidate, path: [...parent.path, value] });
|
|
21408
|
+
}
|
|
21409
|
+
}
|
|
21410
|
+
frontier = next;
|
|
21411
|
+
}
|
|
21412
|
+
const result = {
|
|
21413
|
+
type: "SELECT",
|
|
21414
|
+
rows,
|
|
21415
|
+
columns: resultColumns,
|
|
21416
|
+
rowCount: rows.length,
|
|
21417
|
+
warnings: [...warnings]
|
|
21418
|
+
};
|
|
21419
|
+
materializedMetaBySelectResult.set(result, resultMeta);
|
|
21420
|
+
return result;
|
|
21421
|
+
}
|
|
20703
21422
|
async function executeWith(stmt, client, options, cacheContext, seed, captureColumnMeta = false) {
|
|
20704
21423
|
if ((seed == null || seed.size === 0) && canInlineSingleCte(stmt)) {
|
|
20705
21424
|
return executeSelect(
|
|
@@ -20717,7 +21436,9 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
|
|
|
20717
21436
|
const warnings = /* @__PURE__ */ new Set();
|
|
20718
21437
|
for (const cte of stmt.ctes) {
|
|
20719
21438
|
let result2;
|
|
20720
|
-
if (cte.
|
|
21439
|
+
if (cte.recursiveSpec) {
|
|
21440
|
+
result2 = await executeRecursiveCte(cte, client, options, cteCache, cacheContext);
|
|
21441
|
+
} else if (cte.query.type === "SHOW_APPS") {
|
|
20721
21442
|
result2 = await executeShowApps(client);
|
|
20722
21443
|
} else if (cte.query.type === "DESCRIBE") {
|
|
20723
21444
|
result2 = await executeDescribe(cte.query, client, cacheContext);
|
|
@@ -20774,33 +21495,7 @@ async function executeQueryWithCte(query, client, options, cteCache, cacheContex
|
|
|
20774
21495
|
executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta, true),
|
|
20775
21496
|
executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta, true)
|
|
20776
21497
|
]);
|
|
20777
|
-
|
|
20778
|
-
const rightCols = rightResult.columns;
|
|
20779
|
-
assertUnionColumnCount(leftCols, rightCols);
|
|
20780
|
-
const remapped = rightResult.rows.map((row) => {
|
|
20781
|
-
const mapped = {};
|
|
20782
|
-
leftCols.forEach((col, i) => {
|
|
20783
|
-
mapped[col] = row[rightCols[i] ?? col] ?? "";
|
|
20784
|
-
});
|
|
20785
|
-
return mapped;
|
|
20786
|
-
});
|
|
20787
|
-
const combined = [...leftResult.rows, ...remapped];
|
|
20788
|
-
const rows = query.all ? combined : deduplicateRows(combined, leftCols);
|
|
20789
|
-
const warnings = [.../* @__PURE__ */ new Set([
|
|
20790
|
-
...leftResult.warnings ?? [],
|
|
20791
|
-
...rightResult.warnings ?? []
|
|
20792
|
-
])];
|
|
20793
|
-
const result2 = {
|
|
20794
|
-
type: "SELECT",
|
|
20795
|
-
rows,
|
|
20796
|
-
columns: leftCols,
|
|
20797
|
-
rowCount: rows.length,
|
|
20798
|
-
warnings
|
|
20799
|
-
};
|
|
20800
|
-
if (captureColumnMeta) {
|
|
20801
|
-
materializedMetaBySelectResult.set(result2, mergeUnionColumnMeta(leftResult, rightResult));
|
|
20802
|
-
}
|
|
20803
|
-
return result2;
|
|
21498
|
+
return combineUnionResults(leftResult, rightResult, query.all, captureColumnMeta);
|
|
20804
21499
|
}
|
|
20805
21500
|
const hasCteRef = query.from.cteName != null && query.from.cteName !== NO_FROM_CTE_NAME || query.joins.some((j) => j.table.cteName != null);
|
|
20806
21501
|
if (!hasCteRef) {
|
|
@@ -24766,9 +25461,13 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24766
25461
|
const joinField = leftAlias === joinAlias ? join2.on.left.field : join2.on.right.field;
|
|
24767
25462
|
if (!sourceAlias) continue;
|
|
24768
25463
|
const sourceTable = [select.from, ...select.joins.map((candidate) => candidate.table)].find((table) => effectiveTableAlias(table) === sourceAlias);
|
|
24769
|
-
|
|
24770
|
-
|
|
24771
|
-
|
|
25464
|
+
let targetMeta;
|
|
25465
|
+
if (join2.table.cteName !== null) {
|
|
25466
|
+
targetMeta = explainRelations.get(join2.table.cteName)?.columnMeta?.get(joinField);
|
|
25467
|
+
} else {
|
|
25468
|
+
const targetInfo = (await getFieldsCached(join2.table.appId, tracedClient, cacheContext)).find((info) => info.code === fieldCodeForTypeLookup(join2.table, joinField));
|
|
25469
|
+
targetMeta = targetInfo ? materializedMetaFromFieldInfo(targetInfo, join2.table.appId) : systemColumnMeta(joinField);
|
|
25470
|
+
}
|
|
24772
25471
|
let sourceMeta;
|
|
24773
25472
|
let values;
|
|
24774
25473
|
let sourceRowCount;
|
|
@@ -25337,7 +26036,12 @@ var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
|
|
|
25337
26036
|
function setExplainFetchPlan(result, plan) {
|
|
25338
26037
|
result[EXPLAIN_FETCH_PLAN] = plan;
|
|
25339
26038
|
}
|
|
25340
|
-
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true) {
|
|
26039
|
+
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions) {
|
|
26040
|
+
const recursiveLimits = resolveRecursiveCteLimits({
|
|
26041
|
+
recursiveCteMaxDepth,
|
|
26042
|
+
recursiveCteMaxRows,
|
|
26043
|
+
recursiveCteMaxExpansions
|
|
26044
|
+
});
|
|
25341
26045
|
const invocationCacheContext = createInvocationCacheContext(cacheContext);
|
|
25342
26046
|
try {
|
|
25343
26047
|
const statements = parseSqlBatch(sql, enableImport);
|
|
@@ -25416,7 +26120,8 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25416
26120
|
dmlMaxSubtableRows,
|
|
25417
26121
|
fetchCollector,
|
|
25418
26122
|
tempSchemaLedger,
|
|
25419
|
-
createdSchema
|
|
26123
|
+
createdSchema,
|
|
26124
|
+
{ maxRecords, recursiveLimits }
|
|
25420
26125
|
), cursorMaxActive)
|
|
25421
26126
|
];
|
|
25422
26127
|
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
@@ -25448,7 +26153,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
25448
26153
|
releaseMetadataCacheScope(invocationCacheContext);
|
|
25449
26154
|
}
|
|
25450
26155
|
}
|
|
25451
|
-
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGroupByPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }, tempSchemaLedger = /* @__PURE__ */ new Map(), createdSchema) {
|
|
26156
|
+
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGroupByPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }, tempSchemaLedger = /* @__PURE__ */ new Map(), createdSchema, explainContext = defaultRecursiveExplainContext()) {
|
|
25452
26157
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
25453
26158
|
return [
|
|
25454
26159
|
`CREATE TEMP TABLE ${stmt.name}`,
|
|
@@ -25469,7 +26174,8 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGrou
|
|
|
25469
26174
|
plainGroupByPlans,
|
|
25470
26175
|
collector,
|
|
25471
26176
|
"main",
|
|
25472
|
-
tempSchemaLedger
|
|
26177
|
+
tempSchemaLedger,
|
|
26178
|
+
explainContext
|
|
25473
26179
|
).map((l) => ` ${l}`)
|
|
25474
26180
|
];
|
|
25475
26181
|
}
|
|
@@ -25494,7 +26200,8 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGrou
|
|
|
25494
26200
|
plainGroupByPlans,
|
|
25495
26201
|
collector,
|
|
25496
26202
|
"main",
|
|
25497
|
-
tempSchemaLedger
|
|
26203
|
+
tempSchemaLedger,
|
|
26204
|
+
explainContext
|
|
25498
26205
|
).map((l) => ` ${l}`)
|
|
25499
26206
|
];
|
|
25500
26207
|
}
|
|
@@ -25526,7 +26233,8 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGrou
|
|
|
25526
26233
|
plainGroupByPlans,
|
|
25527
26234
|
collector,
|
|
25528
26235
|
"main",
|
|
25529
|
-
tempSchemaLedger
|
|
26236
|
+
tempSchemaLedger,
|
|
26237
|
+
explainContext
|
|
25530
26238
|
);
|
|
25531
26239
|
}
|
|
25532
26240
|
if (stmt.type === "ASSERT") {
|
|
@@ -25548,7 +26256,8 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGrou
|
|
|
25548
26256
|
plainGroupByPlans,
|
|
25549
26257
|
collector,
|
|
25550
26258
|
"main",
|
|
25551
|
-
tempSchemaLedger
|
|
26259
|
+
tempSchemaLedger,
|
|
26260
|
+
explainContext
|
|
25552
26261
|
).map((l) => ` ${l}`));
|
|
25553
26262
|
});
|
|
25554
26263
|
return lines;
|
|
@@ -25573,7 +26282,8 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGrou
|
|
|
25573
26282
|
plainGroupByPlans,
|
|
25574
26283
|
collector,
|
|
25575
26284
|
"main",
|
|
25576
|
-
tempSchemaLedger
|
|
26285
|
+
tempSchemaLedger,
|
|
26286
|
+
explainContext
|
|
25577
26287
|
);
|
|
25578
26288
|
}
|
|
25579
26289
|
function hasTempTableRef(node) {
|
|
@@ -25586,7 +26296,7 @@ function hasTempTableRef(node) {
|
|
|
25586
26296
|
}
|
|
25587
26297
|
return false;
|
|
25588
26298
|
}
|
|
25589
|
-
function buildPlanForBatchQuery(query, info, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }, sourceRole = "main", tempSchemaLedger = /* @__PURE__ */ new Map()) {
|
|
26299
|
+
function buildPlanForBatchQuery(query, info, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }, sourceRole = "main", tempSchemaLedger = /* @__PURE__ */ new Map(), explainContext = defaultRecursiveExplainContext()) {
|
|
25590
26300
|
if (info.tempTablesReferenced.length === 0) {
|
|
25591
26301
|
return buildExplainPlan(
|
|
25592
26302
|
query,
|
|
@@ -25595,11 +26305,12 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, plainGrou
|
|
|
25595
26305
|
orderPlans,
|
|
25596
26306
|
100,
|
|
25597
26307
|
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
25598
|
-
|
|
26308
|
+
explainContext.maxRecords,
|
|
25599
26309
|
plainGroupByPlans,
|
|
25600
26310
|
true,
|
|
25601
26311
|
collector,
|
|
25602
|
-
sourceRole
|
|
26312
|
+
sourceRole,
|
|
26313
|
+
explainContext.recursiveLimits
|
|
25603
26314
|
);
|
|
25604
26315
|
}
|
|
25605
26316
|
const lines = [];
|
|
@@ -25646,7 +26357,15 @@ function buildPlanForBatchQuery(query, info, capabilities, orderPlans, plainGrou
|
|
|
25646
26357
|
return lines;
|
|
25647
26358
|
}
|
|
25648
26359
|
var explainMaterializedTables = /* @__PURE__ */ new WeakMap();
|
|
25649
|
-
|
|
26360
|
+
function defaultRecursiveExplainContext() {
|
|
26361
|
+
return { maxRecords: 1e4, recursiveLimits: resolveRecursiveCteLimits({}) };
|
|
26362
|
+
}
|
|
26363
|
+
async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions) {
|
|
26364
|
+
const recursiveLimits = resolveRecursiveCteLimits({
|
|
26365
|
+
recursiveCteMaxDepth,
|
|
26366
|
+
recursiveCteMaxRows,
|
|
26367
|
+
recursiveCteMaxExpansions
|
|
26368
|
+
});
|
|
25650
26369
|
const sharedPlan = relativeDatePlan ?? await resolveRelativeDateExecutionPlan(stmt.query, client, cacheContext);
|
|
25651
26370
|
const analysis = await buildExplainWhereAnalysis(
|
|
25652
26371
|
stmt.query,
|
|
@@ -25672,7 +26391,9 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
|
|
|
25672
26391
|
maxRecords,
|
|
25673
26392
|
analysis.plainGroupByPlans,
|
|
25674
26393
|
true,
|
|
25675
|
-
fetchCollector
|
|
26394
|
+
fetchCollector,
|
|
26395
|
+
"main",
|
|
26396
|
+
recursiveLimits
|
|
25676
26397
|
),
|
|
25677
26398
|
cursorMaxActive
|
|
25678
26399
|
)
|
|
@@ -25704,7 +26425,7 @@ function addCursorConcurrency(lines, cursorMaxActive) {
|
|
|
25704
26425
|
}
|
|
25705
26426
|
return result;
|
|
25706
26427
|
}
|
|
25707
|
-
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans, includeFetchSummary = true, collector, sourceRole = "main") {
|
|
26428
|
+
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans, includeFetchSummary = true, collector, sourceRole = "main", recursiveLimits = resolveRecursiveCteLimits({})) {
|
|
25708
26429
|
const fetchCollector = collector ?? { sources: [] };
|
|
25709
26430
|
if (query.type === "UNION") {
|
|
25710
26431
|
const lines2 = buildUnionPlan(
|
|
@@ -25722,7 +26443,9 @@ function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 1
|
|
|
25722
26443
|
capabilities,
|
|
25723
26444
|
orderPlans,
|
|
25724
26445
|
plainGroupByPlans,
|
|
25725
|
-
fetchCollector
|
|
26446
|
+
fetchCollector,
|
|
26447
|
+
maxRecords,
|
|
26448
|
+
recursiveLimits
|
|
25726
26449
|
);
|
|
25727
26450
|
return includeFetchSummary ? addFetchSummary(lines2, fetchCollector.sources) : lines2;
|
|
25728
26451
|
}
|
|
@@ -26319,11 +27042,30 @@ function populateWithCrossJoinExplain(stmt) {
|
|
|
26319
27042
|
}
|
|
26320
27043
|
analyzeQuery(stmt.query);
|
|
26321
27044
|
}
|
|
26322
|
-
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
|
|
27045
|
+
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }, maxRecords = 1e4, recursiveLimits = resolveRecursiveCteLimits({})) {
|
|
26323
27046
|
populateWithCrossJoinExplain(stmt);
|
|
26324
27047
|
const lines = [];
|
|
26325
27048
|
for (const cte of stmt.ctes) {
|
|
26326
|
-
if (cte.
|
|
27049
|
+
if (cte.recursiveSpec) {
|
|
27050
|
+
const cycle = cte.recursiveSpec.cycle;
|
|
27051
|
+
lines.push(
|
|
27052
|
+
`recursive cte: ${cte.name}`,
|
|
27053
|
+
" strategy: B (materialize each source once, iterate in memory)",
|
|
27054
|
+
" union: UNION ALL",
|
|
27055
|
+
" self reference: once",
|
|
27056
|
+
cycle ? ` cycle: path-scoped on ${cycle.column}, mark ${cycle.markColumn} ('${cycle.markValue}'/'${cycle.defaultValue}'), cycle row emitted, expansion stopped` : " cycle: none (absolute limits still enforced)",
|
|
27057
|
+
` limits: depth=${recursiveLimits.depth}, rows=${recursiveLimits.rows}, expansions=${recursiveLimits.expansions} (always fail-closed)`,
|
|
27058
|
+
" complete input: required (onLimit=truncate disabled)",
|
|
27059
|
+
" empty-key recursive join: runtime checked"
|
|
27060
|
+
);
|
|
27061
|
+
for (const source of recursivePhysicalTables(cte.recursiveSpec.seed, cte.recursiveSpec.recursiveTerm)) {
|
|
27062
|
+
const sourceName = `APP${source.appId}${source.subtableCode ? `$${source.subtableCode}` : ""}`;
|
|
27063
|
+
lines.push(
|
|
27064
|
+
` source ${sourceName}: R unknown, pageSize=500, estimated calls=ceil(R/500), maxRecords=${maxRecords}`
|
|
27065
|
+
);
|
|
27066
|
+
}
|
|
27067
|
+
lines.push(" iteration rows: unknown until execution", " records API: none", "");
|
|
27068
|
+
} else if (cte.query.type === "SELECT") {
|
|
26327
27069
|
lines.push(...buildSelectPlan(
|
|
26328
27070
|
cte.query,
|
|
26329
27071
|
`[cte: ${cte.name}]`,
|
|
@@ -26389,10 +27131,12 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collec
|
|
|
26389
27131
|
orderPlans,
|
|
26390
27132
|
100,
|
|
26391
27133
|
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
26392
|
-
|
|
27134
|
+
maxRecords,
|
|
26393
27135
|
plainGroupByPlans,
|
|
26394
27136
|
false,
|
|
26395
|
-
collector
|
|
27137
|
+
collector,
|
|
27138
|
+
"main",
|
|
27139
|
+
recursiveLimits
|
|
26396
27140
|
));
|
|
26397
27141
|
}
|
|
26398
27142
|
if (canInlineSingleCte(stmt)) {
|
|
@@ -28744,6 +29488,16 @@ Options:
|
|
|
28744
29488
|
-h, --help Show help
|
|
28745
29489
|
-v, --version Show version
|
|
28746
29490
|
`;
|
|
29491
|
+
var RECURSIVE_CTE_HELP_LINES = [
|
|
29492
|
+
" --recursive-cte-max-depth <n> Max recursive CTE depth (default: 100)",
|
|
29493
|
+
" --recursive-cte-max-rows <n> Max accumulated recursive CTE rows (default: 10000)",
|
|
29494
|
+
" --recursive-cte-max-expansions <n> Max recursive CTE candidate expansions (default: 100000)"
|
|
29495
|
+
].join("\n");
|
|
29496
|
+
var CLI_HELP_TEXT = HELP_TEXT.replace(
|
|
29497
|
+
" --max-records <n> Max records to fetch (default: 500)",
|
|
29498
|
+
` --max-records <n> Max records to fetch (default: 500)
|
|
29499
|
+
${RECURSIVE_CTE_HELP_LINES}`
|
|
29500
|
+
);
|
|
28747
29501
|
var CLI_IMPORT_SOURCE_REQUIRED_MESSAGE = "IMPORT \u306B\u306F\u30BD\u30FC\u30B9\u304C\u5FC5\u8981\u3067\u3059\u3002--import-csv <name=path> \u307E\u305F\u306F --import-json <name=path> \u3067\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
|
|
28748
29502
|
function toCliImportError(error, importEnabled) {
|
|
28749
29503
|
if (importEnabled || !isImportCapabilityGateError(error)) return error;
|
|
@@ -28763,6 +29517,9 @@ function parseArgs(argv) {
|
|
|
28763
29517
|
dryRun: false,
|
|
28764
29518
|
format: null,
|
|
28765
29519
|
maxRecords: null,
|
|
29520
|
+
recursiveCteMaxDepth: null,
|
|
29521
|
+
recursiveCteMaxRows: null,
|
|
29522
|
+
recursiveCteMaxExpansions: null,
|
|
28766
29523
|
fetchParallel: null,
|
|
28767
29524
|
onLimit: null,
|
|
28768
29525
|
tempTableMaxRows: null,
|
|
@@ -29029,6 +29786,17 @@ function parseArgs(argv) {
|
|
|
29029
29786
|
i++;
|
|
29030
29787
|
continue;
|
|
29031
29788
|
}
|
|
29789
|
+
if (a === "--recursive-cte-max-depth" || a === "--recursive-cte-max-rows" || a === "--recursive-cte-max-expansions") {
|
|
29790
|
+
const n = Number(v);
|
|
29791
|
+
if (!Number.isSafeInteger(n) || n <= 0) {
|
|
29792
|
+
throw new Error(`ArgumentError: ${a} must be a positive safe integer.`);
|
|
29793
|
+
}
|
|
29794
|
+
if (a === "--recursive-cte-max-depth") out.recursiveCteMaxDepth = n;
|
|
29795
|
+
else if (a === "--recursive-cte-max-rows") out.recursiveCteMaxRows = n;
|
|
29796
|
+
else out.recursiveCteMaxExpansions = n;
|
|
29797
|
+
i++;
|
|
29798
|
+
continue;
|
|
29799
|
+
}
|
|
29032
29800
|
if (a === "--temp-table-max-rows") {
|
|
29033
29801
|
const n = Number(v);
|
|
29034
29802
|
if (!Number.isInteger(n) || n <= 0) throw new Error("ArgumentError: --temp-table-max-rows must be a positive integer.");
|
|
@@ -29657,6 +30425,9 @@ function buildReplExecArgv(base, sql, dryRun, format) {
|
|
|
29657
30425
|
pushOpt(argv, "--token-file", base.tokenFile);
|
|
29658
30426
|
pushOpt(argv, "--app", base.app);
|
|
29659
30427
|
pushOpt(argv, "--max-records", base.maxRecords);
|
|
30428
|
+
pushOpt(argv, "--recursive-cte-max-depth", base.recursiveCteMaxDepth);
|
|
30429
|
+
pushOpt(argv, "--recursive-cte-max-rows", base.recursiveCteMaxRows);
|
|
30430
|
+
pushOpt(argv, "--recursive-cte-max-expansions", base.recursiveCteMaxExpansions);
|
|
29660
30431
|
pushOpt(argv, "--fetch-parallel", base.fetchParallel);
|
|
29661
30432
|
pushOpt(argv, "--on-limit", base.onLimit);
|
|
29662
30433
|
pushOpt(argv, "--temp-table-max-rows", base.tempTableMaxRows);
|
|
@@ -30137,7 +30908,7 @@ async function run() {
|
|
|
30137
30908
|
return 2;
|
|
30138
30909
|
}
|
|
30139
30910
|
if (args.help) {
|
|
30140
|
-
process.stdout.write(`${
|
|
30911
|
+
process.stdout.write(`${CLI_HELP_TEXT}
|
|
30141
30912
|
`);
|
|
30142
30913
|
return 0;
|
|
30143
30914
|
}
|
|
@@ -30255,6 +31026,20 @@ async function run() {
|
|
|
30255
31026
|
}
|
|
30256
31027
|
}
|
|
30257
31028
|
const maxRecords = args.maxRecords ?? envInt2("KSQL_MAX_RECORDS") ?? profile.query?.maxRecords ?? 500;
|
|
31029
|
+
const recursiveCteMaxDepth = args.recursiveCteMaxDepth ?? envInt2("KSQL_RECURSIVE_CTE_MAX_DEPTH") ?? profile.query?.recursiveCteMaxDepth ?? 100;
|
|
31030
|
+
const recursiveCteMaxRows = args.recursiveCteMaxRows ?? envInt2("KSQL_RECURSIVE_CTE_MAX_ROWS") ?? profile.query?.recursiveCteMaxRows ?? 1e4;
|
|
31031
|
+
const recursiveCteMaxExpansions = args.recursiveCteMaxExpansions ?? envInt2("KSQL_RECURSIVE_CTE_MAX_EXPANSIONS") ?? profile.query?.recursiveCteMaxExpansions ?? 1e5;
|
|
31032
|
+
for (const [name, value] of [
|
|
31033
|
+
["recursiveCteMaxDepth", recursiveCteMaxDepth],
|
|
31034
|
+
["recursiveCteMaxRows", recursiveCteMaxRows],
|
|
31035
|
+
["recursiveCteMaxExpansions", recursiveCteMaxExpansions]
|
|
31036
|
+
]) {
|
|
31037
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
31038
|
+
process.stderr.write(`ArgumentError: ${name} must be a positive safe integer.
|
|
31039
|
+
`);
|
|
31040
|
+
return 2;
|
|
31041
|
+
}
|
|
31042
|
+
}
|
|
30258
31043
|
const fetchParallel = args.fetchParallel ?? envInt2("KSQL_FETCH_PARALLEL") ?? profile.query?.fetchParallel ?? 3;
|
|
30259
31044
|
const onLimit = args.onLimit ?? envOnLimit2("KSQL_ON_LIMIT") ?? profile.query?.onLimit ?? "error";
|
|
30260
31045
|
const timeout = args.timeout ?? envInt2("KSQL_TIMEOUT") ?? profile.query?.timeout ?? 3e4;
|
|
@@ -30611,7 +31396,10 @@ async function run() {
|
|
|
30611
31396
|
Object.keys(args.importCsv).length > 0 || Object.keys(args.importJson).length > 0,
|
|
30612
31397
|
dmlMaxRows,
|
|
30613
31398
|
dmlMaxSubtableRows,
|
|
30614
|
-
!dryRunUsesStaticTypedPlan
|
|
31399
|
+
!dryRunUsesStaticTypedPlan,
|
|
31400
|
+
recursiveCteMaxDepth,
|
|
31401
|
+
recursiveCteMaxRows,
|
|
31402
|
+
recursiveCteMaxExpansions
|
|
30615
31403
|
);
|
|
30616
31404
|
const out = [];
|
|
30617
31405
|
const restoredStatements = sqlDiagnosticContext ? restoreSqlDiagnosticValue(plans.statements, sqlDiagnosticContext.appBindingByMappedApp) : plans.statements;
|
|
@@ -30701,6 +31489,9 @@ query=${label}`);
|
|
|
30701
31489
|
tempTableMaxRows,
|
|
30702
31490
|
timeoutMs: timeout,
|
|
30703
31491
|
cursorMaxActive,
|
|
31492
|
+
recursiveCteMaxDepth,
|
|
31493
|
+
recursiveCteMaxRows,
|
|
31494
|
+
recursiveCteMaxExpansions,
|
|
30704
31495
|
variables: args.variables,
|
|
30705
31496
|
enableImport: importEnabled,
|
|
30706
31497
|
importSource,
|
|
@@ -30752,7 +31543,10 @@ query=${label}`);
|
|
|
30752
31543
|
enableImport: importEnabled,
|
|
30753
31544
|
importSource,
|
|
30754
31545
|
dmlMaxRows,
|
|
30755
|
-
dmlMaxSubtableRows
|
|
31546
|
+
dmlMaxSubtableRows,
|
|
31547
|
+
recursiveCteMaxDepth,
|
|
31548
|
+
recursiveCteMaxRows,
|
|
31549
|
+
recursiveCteMaxExpansions
|
|
30756
31550
|
}) : await execute(sql, client, {
|
|
30757
31551
|
maxRecords,
|
|
30758
31552
|
fetchParallel,
|
|
@@ -30760,6 +31554,9 @@ query=${label}`);
|
|
|
30760
31554
|
confirm: isDmlStatement ? confirm : void 0,
|
|
30761
31555
|
cacheContext,
|
|
30762
31556
|
cursorMaxActive,
|
|
31557
|
+
recursiveCteMaxDepth,
|
|
31558
|
+
recursiveCteMaxRows,
|
|
31559
|
+
recursiveCteMaxExpansions,
|
|
30763
31560
|
enableImport: importEnabled,
|
|
30764
31561
|
importSource,
|
|
30765
31562
|
supportsImportConfirmDetail: true,
|
|
@@ -30843,6 +31640,7 @@ if (isDirectCliRun()) {
|
|
|
30843
31640
|
}
|
|
30844
31641
|
// Annotate the CommonJS export names for ESM import in node:
|
|
30845
31642
|
0 && (module.exports = {
|
|
31643
|
+
CLI_HELP_TEXT,
|
|
30846
31644
|
CLI_IMPORT_SOURCE_REQUIRED_MESSAGE,
|
|
30847
31645
|
HELP_TEXT,
|
|
30848
31646
|
buildBatchDmlConfirmMessage,
|