@rex0220/kintone-sql-tools 3.62.0 → 3.63.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 +354 -31
- package/dist-engine/index.cjs +12 -12
- package/dist-engine/index.mjs +12 -12
- package/dist-engine/ksql-engine.umd.js +12 -12
- package/dist-engine/meta/bundle-baseline.json +10 -10
- package/dist-engine/meta/cjs.json +52 -28
- package/dist-engine/meta/esm.json +52 -28
- package/dist-engine/meta/umd.json +52 -28
- package/dist-mcp/ksql-mcp.js +339 -39
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -76,6 +76,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
76
76
|
["INNER", "INNER" /* INNER */],
|
|
77
77
|
["LEFT", "LEFT" /* LEFT */],
|
|
78
78
|
["RIGHT", "RIGHT" /* RIGHT */],
|
|
79
|
+
["CROSS", "CROSS" /* CROSS */],
|
|
79
80
|
["JOIN", "JOIN" /* JOIN */],
|
|
80
81
|
["ON", "ON" /* ON */],
|
|
81
82
|
["GROUP", "GROUP" /* GROUP */],
|
|
@@ -3016,6 +3017,13 @@ var Parser = class {
|
|
|
3016
3017
|
const joinType = this.tryJoinType();
|
|
3017
3018
|
if (joinType === null) break;
|
|
3018
3019
|
const table = this.parseTableRef();
|
|
3020
|
+
if (joinType === "CROSS") {
|
|
3021
|
+
if (this.peek().kind === "ON" /* ON */) {
|
|
3022
|
+
throw new ParseError("CROSS JOIN \u306B ON \u53E5\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002", this.peek());
|
|
3023
|
+
}
|
|
3024
|
+
joins.push({ type: "CROSS", table, on: null });
|
|
3025
|
+
continue;
|
|
3026
|
+
}
|
|
3019
3027
|
this.expect("ON" /* ON */);
|
|
3020
3028
|
const on = this.parseJoinCondition();
|
|
3021
3029
|
joins.push({ type: joinType, table, on });
|
|
@@ -3024,17 +3032,30 @@ var Parser = class {
|
|
|
3024
3032
|
}
|
|
3025
3033
|
tryJoinType() {
|
|
3026
3034
|
if (this.consume("INNER" /* INNER */)) {
|
|
3035
|
+
if (this.peek().kind === "CROSS" /* CROSS */) {
|
|
3036
|
+
throw new ParseError("CROSS JOIN \u306B INNER \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002", this.peek());
|
|
3037
|
+
}
|
|
3027
3038
|
this.expect("JOIN" /* JOIN */);
|
|
3028
3039
|
return "INNER";
|
|
3029
3040
|
}
|
|
3030
3041
|
if (this.consume("LEFT" /* LEFT */)) {
|
|
3042
|
+
if (this.peek().kind === "CROSS" /* CROSS */) {
|
|
3043
|
+
throw new ParseError("CROSS JOIN \u306B LEFT / RIGHT \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002", this.peek());
|
|
3044
|
+
}
|
|
3031
3045
|
this.expect("JOIN" /* JOIN */);
|
|
3032
3046
|
return "LEFT";
|
|
3033
3047
|
}
|
|
3034
3048
|
if (this.consume("RIGHT" /* RIGHT */)) {
|
|
3049
|
+
if (this.peek().kind === "CROSS" /* CROSS */) {
|
|
3050
|
+
throw new ParseError("CROSS JOIN \u306B LEFT / RIGHT \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002", this.peek());
|
|
3051
|
+
}
|
|
3035
3052
|
this.expect("JOIN" /* JOIN */);
|
|
3036
3053
|
return "RIGHT";
|
|
3037
3054
|
}
|
|
3055
|
+
if (this.consume("CROSS" /* CROSS */)) {
|
|
3056
|
+
this.expect("JOIN" /* JOIN */);
|
|
3057
|
+
return "CROSS";
|
|
3058
|
+
}
|
|
3038
3059
|
if (this.consume("JOIN" /* JOIN */)) {
|
|
3039
3060
|
return "INNER";
|
|
3040
3061
|
}
|
|
@@ -4584,6 +4605,8 @@ var Parser = class {
|
|
|
4584
4605
|
this.advance();
|
|
4585
4606
|
return tok.value;
|
|
4586
4607
|
}
|
|
4608
|
+
const digitPrefixed = this.tryParseDigitPrefixedIdentifier();
|
|
4609
|
+
if (digitPrefixed !== null) return digitPrefixed;
|
|
4587
4610
|
throw new ParseError(
|
|
4588
4611
|
"\u30D5\u30A3\u30FC\u30EB\u30C9\u540D\u307E\u305F\u306F\u30C6\u30FC\u30D6\u30EB\u540D\u304C\u5FC5\u8981\u3067\u3059",
|
|
4589
4612
|
tok
|
|
@@ -4597,11 +4620,24 @@ var Parser = class {
|
|
|
4597
4620
|
this.advance();
|
|
4598
4621
|
return tok.value;
|
|
4599
4622
|
}
|
|
4623
|
+
const digitPrefixed = this.tryParseDigitPrefixedIdentifier();
|
|
4624
|
+
if (digitPrefixed !== null) return digitPrefixed;
|
|
4600
4625
|
throw new ParseError(
|
|
4601
4626
|
"\u30D5\u30A3\u30FC\u30EB\u30C9\u540D\u307E\u305F\u306F\u30C6\u30FC\u30D6\u30EB\u540D\u304C\u5FC5\u8981\u3067\u3059",
|
|
4602
4627
|
tok
|
|
4603
4628
|
);
|
|
4604
4629
|
}
|
|
4630
|
+
/** `0埋め` のように数字から始まる日本語識別子を、空白なしの場合だけ読む。 */
|
|
4631
|
+
tryParseDigitPrefixedIdentifier() {
|
|
4632
|
+
const first = this.peek();
|
|
4633
|
+
const second = this.peekAt(1);
|
|
4634
|
+
if (first.kind !== "NUMBER" /* NUMBER */ || !/^\d+$/.test(first.value) || second.kind !== "IDENT" /* IDENT */ || second.pos !== first.pos + first.value.length) {
|
|
4635
|
+
return null;
|
|
4636
|
+
}
|
|
4637
|
+
this.advance();
|
|
4638
|
+
this.advance();
|
|
4639
|
+
return first.value + second.value;
|
|
4640
|
+
}
|
|
4605
4641
|
// DML の対象テーブル位置に一時テーブルが指定されていたら拒否する
|
|
4606
4642
|
rejectTempTableDml() {
|
|
4607
4643
|
const tok = this.peek();
|
|
@@ -4781,6 +4817,7 @@ function unionCompleteInputReasons(stmt) {
|
|
|
4781
4817
|
}
|
|
4782
4818
|
function selectCompleteInputReasons(stmt) {
|
|
4783
4819
|
const reasons = /* @__PURE__ */ new Set();
|
|
4820
|
+
if (stmt.joins.some((join2) => join2.type === "CROSS")) reasons.add("CROSS_JOIN");
|
|
4784
4821
|
const grouping = normalizeGroupingSpec(stmt);
|
|
4785
4822
|
if (grouping.type === "GROUPING_SETS") reasons.add("GROUPING_SETS");
|
|
4786
4823
|
if (grouping.type === "PLAIN") reasons.add("GROUP_BY");
|
|
@@ -6887,6 +6924,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
|
6887
6924
|
}
|
|
6888
6925
|
}
|
|
6889
6926
|
for (const join2 of stmt.joins) {
|
|
6927
|
+
if (join2.type === "CROSS") continue;
|
|
6890
6928
|
addFieldRef(join2.on.left.field, join2.on.left.tableAlias, "where");
|
|
6891
6929
|
addFieldRef(join2.on.right.field, join2.on.right.tableAlias, "where");
|
|
6892
6930
|
}
|
|
@@ -7831,7 +7869,9 @@ function buildSingleTableKlikePushdownPlan(where, options = {}) {
|
|
|
7831
7869
|
return { condition, relation, appliedKlikes, allKlikes: [...allKlikes] };
|
|
7832
7870
|
}
|
|
7833
7871
|
function buildKlikePushdownPlan(stmt, options = {}) {
|
|
7834
|
-
const joinsAreSafeForKlike = stmt.joins.every(
|
|
7872
|
+
const joinsAreSafeForKlike = stmt.joins.every(
|
|
7873
|
+
(join2) => join2.type === "INNER" || join2.type === "CROSS"
|
|
7874
|
+
);
|
|
7835
7875
|
const common = {
|
|
7836
7876
|
allowKlike: joinsAreSafeForKlike,
|
|
7837
7877
|
allowUnresolvedKlikeVariables: options.allowUnresolvedVariables
|
|
@@ -7851,7 +7891,7 @@ function buildKlikePushdownPlan(stmt, options = {}) {
|
|
|
7851
7891
|
const joinRelations = /* @__PURE__ */ new Map();
|
|
7852
7892
|
if (stmt.where !== null) {
|
|
7853
7893
|
for (const join2 of stmt.joins) {
|
|
7854
|
-
if (join2.type !== "INNER" || !join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
|
|
7894
|
+
if (join2.type !== "INNER" && join2.type !== "CROSS" || !join2.table.alias || join2.table.subtableCode || join2.table.cteName !== null) continue;
|
|
7855
7895
|
const extracted = extractSafePushdownPlan(stmt.where, {
|
|
7856
7896
|
...common,
|
|
7857
7897
|
tableAlias: join2.table.alias,
|
|
@@ -8198,7 +8238,7 @@ function validateSelect(stmt) {
|
|
|
8198
8238
|
validateNestedSelects(stmt);
|
|
8199
8239
|
}
|
|
8200
8240
|
function canDeferJoinWholeWhereKlikeValidation(stmt) {
|
|
8201
|
-
return stmt.where !== null && serverOnlyFunctionOccurrencesInWhere(stmt.where).length > 0 && stmt.joins.length > 0 && stmt.joins.every((join2) => join2.type === "INNER") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
|
|
8241
|
+
return stmt.where !== null && serverOnlyFunctionOccurrencesInWhere(stmt.where).length > 0 && stmt.joins.length > 0 && stmt.joins.every((join2) => join2.type === "INNER" || join2.type === "CROSS") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
|
|
8202
8242
|
(table) => table.alias !== null && table.cteName === null && !table.subtableCode
|
|
8203
8243
|
);
|
|
8204
8244
|
}
|
|
@@ -8417,7 +8457,8 @@ function assertStringFunctionArity(func, args) {
|
|
|
8417
8457
|
}
|
|
8418
8458
|
|
|
8419
8459
|
// src/core/generateSeries.ts
|
|
8420
|
-
var
|
|
8460
|
+
var GENERATED_ROW_MAX_ROWS = 1e4;
|
|
8461
|
+
var GENERATE_SERIES_MAX_ROWS = GENERATED_ROW_MAX_ROWS;
|
|
8421
8462
|
var argumentError = (message) => new Error(`ArgumentError: ${message}`);
|
|
8422
8463
|
var isVariable = (arg) => arg.type === "VARIABLE";
|
|
8423
8464
|
var isResolvedVariable = (arg) => arg?.type === "STRING" && arg.fromVariable === true;
|
|
@@ -8453,19 +8494,26 @@ function dateFromOrdinal(ordinal) {
|
|
|
8453
8494
|
}
|
|
8454
8495
|
function parseDateStep(value) {
|
|
8455
8496
|
const trimmed = value.trim();
|
|
8456
|
-
const match = /^([+-]?\d+)\s+(day|days)$/i.exec(trimmed);
|
|
8497
|
+
const match = /^([+-]?\d+)\s+(day|days|month|months|year|years)$/i.exec(trimmed);
|
|
8457
8498
|
if (!match) {
|
|
8499
|
+
if (/^\S+\s+(?:day|days|month|months|year|years)$/i.test(trimmed)) {
|
|
8500
|
+
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306E\u4FC2\u6570\u306B\u306F\u5B89\u5168\u306A\u6574\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8501
|
+
}
|
|
8458
8502
|
if (/^[+-]?\d+\s+\S+$/i.test(trimmed)) {
|
|
8459
|
-
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306F day
|
|
8503
|
+
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306F day\u3001days\u3001month\u3001months\u3001year\u3001years \u306E\u307F\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u3059\u3002");
|
|
8460
8504
|
}
|
|
8461
|
-
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8505
|
+
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day\u3001month\u3001year \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8462
8506
|
}
|
|
8463
|
-
const
|
|
8464
|
-
if (!Number.isSafeInteger(
|
|
8465
|
-
throw argumentError("GENERATE_SERIES \u306E\
|
|
8507
|
+
const coefficient = Number(match[1]);
|
|
8508
|
+
if (!Number.isSafeInteger(coefficient)) {
|
|
8509
|
+
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306E\u4FC2\u6570\u306B\u306F\u5B89\u5168\u306A\u6574\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8466
8510
|
}
|
|
8467
|
-
|
|
8468
|
-
|
|
8511
|
+
const rawUnit = match[2].toLowerCase();
|
|
8512
|
+
const unit = rawUnit.startsWith("month") ? "MONTH" : rawUnit.startsWith("year") ? "YEAR" : "DAY";
|
|
8513
|
+
if (coefficient === 0) {
|
|
8514
|
+
throw argumentError(`GENERATE_SERIES \u306E\u65E5\u4ED8 step \u306B 0 ${unit.toLowerCase()} \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002`);
|
|
8515
|
+
}
|
|
8516
|
+
return { coefficient, unit };
|
|
8469
8517
|
}
|
|
8470
8518
|
function integerValue(value) {
|
|
8471
8519
|
if (typeof value === "number") return Number.isSafeInteger(value) ? value : null;
|
|
@@ -8493,6 +8541,46 @@ function countRows(start, stop, step) {
|
|
|
8493
8541
|
const distance = step > 0 ? BigInt(stop) - BigInt(start) : BigInt(start) - BigInt(stop);
|
|
8494
8542
|
return Number(distance / BigInt(Math.abs(step)) + 1n);
|
|
8495
8543
|
}
|
|
8544
|
+
function monthIndex(parts) {
|
|
8545
|
+
return parts.year * 12 + parts.month - 1;
|
|
8546
|
+
}
|
|
8547
|
+
function validateDateAnchor(start, unit) {
|
|
8548
|
+
if (unit === "MONTH" && start.day !== 1) {
|
|
8549
|
+
throw argumentError("GENERATE_SERIES \u306E month step \u3067\u306F start \u306B\u6708\u521D\uFF08YYYY-MM-01\uFF09\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8550
|
+
}
|
|
8551
|
+
if (unit === "YEAR" && (start.month !== 1 || start.day !== 1)) {
|
|
8552
|
+
throw argumentError("GENERATE_SERIES \u306E year step \u3067\u306F start \u306B\u5E74\u521D\uFF08YYYY-01-01\uFF09\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8555
|
+
function countDateRows(start, stop, step) {
|
|
8556
|
+
const startOrdinal = dateOrdinal(
|
|
8557
|
+
`${String(start.year).padStart(4, "0")}-${String(start.month).padStart(2, "0")}-${String(start.day).padStart(2, "0")}`
|
|
8558
|
+
);
|
|
8559
|
+
const stopOrdinal = dateOrdinal(
|
|
8560
|
+
`${String(stop.year).padStart(4, "0")}-${String(stop.month).padStart(2, "0")}-${String(stop.day).padStart(2, "0")}`
|
|
8561
|
+
);
|
|
8562
|
+
if (step.unit === "DAY") return countRows(startOrdinal, stopOrdinal, step.coefficient);
|
|
8563
|
+
if (startOrdinal === stopOrdinal) return 1;
|
|
8564
|
+
if (startOrdinal < stopOrdinal && step.coefficient < 0 || startOrdinal > stopOrdinal && step.coefficient > 0) return 0;
|
|
8565
|
+
if (step.unit === "MONTH") {
|
|
8566
|
+
const boundary2 = monthIndex(stop) + (step.coefficient < 0 && stop.day !== 1 ? 1 : 0);
|
|
8567
|
+
return countRows(monthIndex(start), boundary2, step.coefficient);
|
|
8568
|
+
}
|
|
8569
|
+
const stopIsYearStart = stop.month === 1 && stop.day === 1;
|
|
8570
|
+
const boundary = stop.year + (step.coefficient < 0 && !stopIsYearStart ? 1 : 0);
|
|
8571
|
+
return countRows(start.year, boundary, step.coefficient);
|
|
8572
|
+
}
|
|
8573
|
+
function dateFromParts(year, month, day) {
|
|
8574
|
+
if (year < 1 || year > 9999) {
|
|
8575
|
+
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8\u5F15\u6570\u306B\u306F\u5B9F\u5728\u3059\u308B YYYY-MM-DD \u5F62\u5F0F\u306E DATE \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8576
|
+
}
|
|
8577
|
+
return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
8578
|
+
}
|
|
8579
|
+
function dateFromMonthIndex(index) {
|
|
8580
|
+
const year = Math.floor(index / 12);
|
|
8581
|
+
const month = index - year * 12 + 1;
|
|
8582
|
+
return dateFromParts(year, month, 1);
|
|
8583
|
+
}
|
|
8496
8584
|
function planResolved(stmt) {
|
|
8497
8585
|
if (stmt.args.length < 2 || stmt.args.length > 3) {
|
|
8498
8586
|
throw argumentError("GENERATE_SERIES \u306F start\u3001stop \u3068\u7701\u7565\u53EF\u80FD\u306A step \u306E2\u500B\u307E\u305F\u306F3\u500B\u306E\u5F15\u6570\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
|
|
@@ -8518,12 +8606,20 @@ function planResolved(stmt) {
|
|
|
8518
8606
|
throw argumentError("GENERATE_SERIES \u306E\u65E5\u4ED8\u5F15\u6570\u306B\u306F\u5B9F\u5728\u3059\u308B YYYY-MM-DD \u5F62\u5F0F\u306E DATE \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8519
8607
|
}
|
|
8520
8608
|
if (stepRaw !== void 0 && typeof stepRaw !== "string") {
|
|
8521
|
-
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8609
|
+
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day\u3001month\u3001year \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8522
8610
|
}
|
|
8523
|
-
const
|
|
8611
|
+
const dateStep = stepRaw === void 0 ? { coefficient: 1, unit: "DAY" } : parseDateStep(stepRaw);
|
|
8612
|
+
validateDateAnchor(startDate, dateStep.unit);
|
|
8524
8613
|
const start2 = startRaw;
|
|
8525
8614
|
const stop2 = stopRaw;
|
|
8526
|
-
return {
|
|
8615
|
+
return {
|
|
8616
|
+
kind: "DATE",
|
|
8617
|
+
start: start2,
|
|
8618
|
+
stop: stop2,
|
|
8619
|
+
step: dateStep.coefficient,
|
|
8620
|
+
dateUnit: dateStep.unit,
|
|
8621
|
+
rowCount: countDateRows(startDate, stopDate, dateStep)
|
|
8622
|
+
};
|
|
8527
8623
|
}
|
|
8528
8624
|
const startInteger = startArg.type === "NUMBER" ? integerNumberLiteral(startArg) : isResolvedVariable(startArg) ? integerValue(startRaw) : null;
|
|
8529
8625
|
const stopInteger = stopArg.type === "NUMBER" ? integerNumberLiteral(stopArg) : isResolvedVariable(stopArg) ? integerValue(stopRaw) : null;
|
|
@@ -8538,7 +8634,7 @@ function planResolved(stmt) {
|
|
|
8538
8634
|
if (stepArg?.type === "NUMBER" || isResolvedVariable(stepArg)) {
|
|
8539
8635
|
throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
|
|
8540
8636
|
}
|
|
8541
|
-
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8637
|
+
throw argumentError("GENERATE_SERIES \u306E step \u304C\u7CFB\u5217\u306E\u578B\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6574\u6570\u7CFB\u5217\u306B\u306F\u6574\u6570\u3001DATE \u7CFB\u5217\u306B\u306F day\u3001month\u3001year \u5358\u4F4D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
8542
8638
|
}
|
|
8543
8639
|
const start = startInteger;
|
|
8544
8640
|
const stop = stopInteger;
|
|
@@ -8574,7 +8670,12 @@ function validateGenerateSeriesStatement(stmt) {
|
|
|
8574
8670
|
if (value === null) throw argumentError("GENERATE_SERIES \u306E\u6570\u5024\u7CFB\u5217\u306F\u6574\u6570\u306E start\u3001stop\u3001step \u306E\u307F\u3092\u53D7\u3051\u4ED8\u3051\u307E\u3059\u3002");
|
|
8575
8671
|
if (value === 0) throw argumentError("GENERATE_SERIES \u306E step \u306B 0 \u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002");
|
|
8576
8672
|
} else if (step?.type === "STRING") {
|
|
8577
|
-
parseDateStep(step.value);
|
|
8673
|
+
const dateStep = parseDateStep(step.value);
|
|
8674
|
+
const start = stmt.args[0];
|
|
8675
|
+
if (start?.type === "STRING") {
|
|
8676
|
+
const parts = dateParts(start.value);
|
|
8677
|
+
if (parts) validateDateAnchor(parts, dateStep.unit);
|
|
8678
|
+
}
|
|
8578
8679
|
}
|
|
8579
8680
|
return null;
|
|
8580
8681
|
}
|
|
@@ -8629,8 +8730,22 @@ function resolveGenerateSeries(stmt) {
|
|
|
8629
8730
|
}
|
|
8630
8731
|
}
|
|
8631
8732
|
} else {
|
|
8632
|
-
const
|
|
8633
|
-
|
|
8733
|
+
const start = dateParts(plan.start);
|
|
8734
|
+
if (plan.dateUnit === "MONTH") {
|
|
8735
|
+
const anchor = monthIndex(start);
|
|
8736
|
+
for (let index = 0; index < plan.rowCount; index++) {
|
|
8737
|
+
values.push(dateFromMonthIndex(anchor + index * plan.step));
|
|
8738
|
+
}
|
|
8739
|
+
} else if (plan.dateUnit === "YEAR") {
|
|
8740
|
+
for (let index = 0; index < plan.rowCount; index++) {
|
|
8741
|
+
values.push(dateFromParts(start.year + index * plan.step, 1, 1));
|
|
8742
|
+
}
|
|
8743
|
+
} else {
|
|
8744
|
+
const startOrdinal = dateOrdinal(plan.start);
|
|
8745
|
+
for (let index = 0; index < plan.rowCount; index++) {
|
|
8746
|
+
values.push(dateFromOrdinal(startOrdinal + index * plan.step));
|
|
8747
|
+
}
|
|
8748
|
+
}
|
|
8634
8749
|
}
|
|
8635
8750
|
return { ...plan, values };
|
|
8636
8751
|
}
|
|
@@ -12774,6 +12889,19 @@ function planJoinKeyPrefilter(input) {
|
|
|
12774
12889
|
return { kind: "RANGE", min, max, relation: "superset" };
|
|
12775
12890
|
}
|
|
12776
12891
|
|
|
12892
|
+
// src/core/optimization/crossJoinRowPlan.ts
|
|
12893
|
+
var CROSS_JOIN_MAX_ROWS = GENERATED_ROW_MAX_ROWS;
|
|
12894
|
+
function planCrossJoinRows(leftRows, rightRows, limit = CROSS_JOIN_MAX_ROWS) {
|
|
12895
|
+
const outputRows = leftRows === 0 || rightRows === 0 ? 0 : leftRows * rightRows;
|
|
12896
|
+
return {
|
|
12897
|
+
leftRows,
|
|
12898
|
+
rightRows,
|
|
12899
|
+
outputRows,
|
|
12900
|
+
limit,
|
|
12901
|
+
allowed: outputRows <= limit
|
|
12902
|
+
};
|
|
12903
|
+
}
|
|
12904
|
+
|
|
12777
12905
|
// src/core/explainMetadata.ts
|
|
12778
12906
|
function buildGroupingExplainMetadata(statement, canonicalItemCount) {
|
|
12779
12907
|
const grouping = normalizeGroupingSpec(statement);
|
|
@@ -12814,11 +12942,30 @@ function valueNeedsFieldMetadata(value) {
|
|
|
12814
12942
|
}
|
|
12815
12943
|
function selectNeedsOwnMetadata(statement) {
|
|
12816
12944
|
return whereNeedsFieldMetadata(statement.where) || statement.groupBy.length > 0 || normalizeGroupingSpec(statement).type === "GROUPING_SETS" || statement.orderBy.length > 0 || statement.joins.some(
|
|
12817
|
-
(join2) => join2.table.appId > 0 && join2.table.cteName === null && (join2.on.left.field !== "$id" || join2.on.right.field !== "$id")
|
|
12945
|
+
(join2) => join2.type !== "CROSS" && join2.table.appId > 0 && join2.table.cteName === null && (join2.on.left.field !== "$id" || join2.on.right.field !== "$id")
|
|
12818
12946
|
) || statement.columns.some(
|
|
12819
12947
|
(column) => column.type === "WINDOW_COL" && column.orderBy.length > 0
|
|
12820
12948
|
);
|
|
12821
12949
|
}
|
|
12950
|
+
function cteQueriesContainPhysicalSelect(ctes) {
|
|
12951
|
+
if (!Array.isArray(ctes)) return false;
|
|
12952
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12953
|
+
const visit = (node) => {
|
|
12954
|
+
if (node === null || typeof node !== "object") return false;
|
|
12955
|
+
if (seen.has(node)) return false;
|
|
12956
|
+
seen.add(node);
|
|
12957
|
+
if (Array.isArray(node)) return node.some(visit);
|
|
12958
|
+
const item = node;
|
|
12959
|
+
if (item["type"] === "SELECT") {
|
|
12960
|
+
const select = node;
|
|
12961
|
+
if ([select.from, ...select.joins.map((join2) => join2.table)].some((table) => table.appId > 0 && table.cteName === null)) {
|
|
12962
|
+
return true;
|
|
12963
|
+
}
|
|
12964
|
+
}
|
|
12965
|
+
return Object.values(item).some(visit);
|
|
12966
|
+
};
|
|
12967
|
+
return ctes.some((cte) => visit(cte?.query));
|
|
12968
|
+
}
|
|
12822
12969
|
function explainNeedsAppMetadata(statement) {
|
|
12823
12970
|
const seen = /* @__PURE__ */ new Set();
|
|
12824
12971
|
const visit = (node) => {
|
|
@@ -12828,6 +12975,9 @@ function explainNeedsAppMetadata(statement) {
|
|
|
12828
12975
|
if (Array.isArray(node)) return node.some(visit);
|
|
12829
12976
|
const item = node;
|
|
12830
12977
|
if (item["type"] === "VALIDATE") return true;
|
|
12978
|
+
if (item["type"] === "WITH" && cteQueriesContainPhysicalSelect(item["ctes"])) {
|
|
12979
|
+
return true;
|
|
12980
|
+
}
|
|
12831
12981
|
if (item["type"] === "SELECT" && selectNeedsOwnMetadata(node)) {
|
|
12832
12982
|
return true;
|
|
12833
12983
|
}
|
|
@@ -14051,6 +14201,19 @@ function flatten(record, alias) {
|
|
|
14051
14201
|
return row;
|
|
14052
14202
|
}
|
|
14053
14203
|
function applyJoin(leftRows, rightRows, join2, columns = {}) {
|
|
14204
|
+
if (join2.type === "CROSS") {
|
|
14205
|
+
const plan = planCrossJoinRows(leftRows.length, rightRows.length);
|
|
14206
|
+
if (!plan.allowed) {
|
|
14207
|
+
throw new Error(
|
|
14208
|
+
`ArgumentError: CROSS JOIN \u306E\u751F\u6210\u4EF6\u6570 ${plan.outputRows} \u884C\uFF08\u5DE6 ${plan.leftRows} \u884C \xD7 \u53F3 ${plan.rightRows} \u884C\uFF09\u304C\u4E0A\u9650 ${plan.limit} \u884C\u3092\u8D85\u3048\u3066\u3044\u307E\u3059\u3002`
|
|
14209
|
+
);
|
|
14210
|
+
}
|
|
14211
|
+
const result2 = [];
|
|
14212
|
+
for (const lRow of leftRows) {
|
|
14213
|
+
for (const rRow of rightRows) result2.push({ ...lRow, ...rRow });
|
|
14214
|
+
}
|
|
14215
|
+
return result2;
|
|
14216
|
+
}
|
|
14054
14217
|
const { on, type: joinType } = join2;
|
|
14055
14218
|
const leftKey = on.left.tableAlias ? `${on.left.tableAlias}.${on.left.field}` : on.left.field;
|
|
14056
14219
|
const rightKey = on.right.tableAlias ? `${on.right.tableAlias}.${on.right.field}` : on.right.field;
|
|
@@ -15741,7 +15904,7 @@ function allowRelativeDatePrefilterPlan(select, decomposition) {
|
|
|
15741
15904
|
return decomposition.eligible === true && resolveSelectMode(select) === "FULL_SCAN" && select.orderMode !== "KINTONE_NATIVE" && select.from.cteName === null && !select.from.subtableCode && select.joins.length === 0;
|
|
15742
15905
|
}
|
|
15743
15906
|
function allowJoinServerFunctionPlan(select, plan) {
|
|
15744
|
-
return select.where !== null && select.joins.length > 0 && select.joins.every((join2) => join2.type === "INNER") && [select.from, ...select.joins.map((join2) => join2.table)].every(
|
|
15907
|
+
return select.where !== null && select.joins.length > 0 && select.joins.every((join2) => join2.type === "INNER" || join2.type === "CROSS") && [select.from, ...select.joins.map((join2) => join2.table)].every(
|
|
15745
15908
|
(table) => table.alias !== null && table.cteName === null && !table.subtableCode
|
|
15746
15909
|
) && isJoinServerFunctionFetchPlan(plan);
|
|
15747
15910
|
}
|
|
@@ -19056,7 +19219,7 @@ function completeInputErrorPrefix(reasons) {
|
|
|
19056
19219
|
const hasAggregateReason = aggregateSubjects.some(([reason]) => reasons.has(reason));
|
|
19057
19220
|
const hasOrderReason = reasons.has("LOCAL_ORDER") || reasons.has("WINDOW_ORDER");
|
|
19058
19221
|
const legacySubject = reasons.size === 1 && reasons.has("STATISTICAL_AGGREGATE") ? "\u7D71\u8A08\u96C6\u7D04\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("GROUPING_SETS") ? "\u5C0F\u8A08\u30FB\u7DCF\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("AGGREGATE") ? "\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("GROUP_BY") ? "\u30B0\u30EB\u30FC\u30D7\u96C6\u8A08\u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.size === 1 && reasons.has("DISTINCT") ? "DISTINCT \u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.has("GROUPING_SETS") ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
|
|
19059
|
-
const subject = reasons.has("DML") || reasons.has("VALIDATE") ? legacySubject : hasAggregateReason && hasOrderReason ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : hasAggregateReason ? aggregateSubjects.find(([reason]) => reasons.has(reason))[1] : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
|
|
19222
|
+
const subject = reasons.size === 1 && reasons.has("CROSS_JOIN") ? "CROSS JOIN \u306E\u6B63\u3057\u3044\u7D50\u679C" : reasons.has("DML") || reasons.has("VALIDATE") ? legacySubject : hasAggregateReason && hasOrderReason ? "\u30AF\u30A8\u30EA\u306E\u6B63\u3057\u3044\u7D50\u679C" : hasAggregateReason ? aggregateSubjects.find(([reason]) => reasons.has(reason))[1] : "ORDER BY\u306E\u6B63\u3057\u3044\u7D50\u679C";
|
|
19060
19223
|
return `${subject}\u306B\u306F\u5B8C\u5168\u306A\u5019\u88DC\u96C6\u5408\u304C\u5FC5\u8981\u3067\u3059\u3002complete input reason: ${reasonList}\u3002`;
|
|
19061
19224
|
}
|
|
19062
19225
|
function buildCompleteInputPolicy(stmt, options, orderPlan) {
|
|
@@ -19427,6 +19590,7 @@ async function validateB86SelectFieldCodes(stmt, client, cteCache, cacheContext)
|
|
|
19427
19590
|
for (const alias of b86SourceAliases(schema.table)) sourceByAlias.set(alias, schema);
|
|
19428
19591
|
}
|
|
19429
19592
|
for (const join2 of stmt.joins) {
|
|
19593
|
+
if (join2.type === "CROSS") continue;
|
|
19430
19594
|
for (const ref of [join2.on.left, join2.on.right]) {
|
|
19431
19595
|
if (!ref.tableAlias) continue;
|
|
19432
19596
|
const schema = sourceByAlias.get(ref.tableAlias);
|
|
@@ -19497,7 +19661,7 @@ function hasPushdownPlaceholder(where) {
|
|
|
19497
19661
|
}
|
|
19498
19662
|
var boundJoinRuntimePlans = /* @__PURE__ */ new WeakMap();
|
|
19499
19663
|
function buildRuntimeJoinPushdownPlan(stmt, metadata) {
|
|
19500
|
-
if (stmt.joins.length === 0 || stmt.where === null || stmt.joins.some((join2) => join2.type !== "INNER")) {
|
|
19664
|
+
if (stmt.joins.length === 0 || stmt.where === null || stmt.joins.some((join2) => join2.type !== "INNER" && join2.type !== "CROSS")) {
|
|
19501
19665
|
return null;
|
|
19502
19666
|
}
|
|
19503
19667
|
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
@@ -19556,7 +19720,7 @@ async function loadTypedPushdownMeta(stmt, client, cacheContext) {
|
|
|
19556
19720
|
else candidatesByApp.set(appId, [candidate]);
|
|
19557
19721
|
};
|
|
19558
19722
|
addCandidate(stmt.from.appId, extractMainTypedPushdownCandidate(stmt));
|
|
19559
|
-
const directInnerJoin = stmt.joins.length > 0 && stmt.where !== null && stmt.joins.every((join2) => join2.type === "INNER") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
|
|
19723
|
+
const directInnerJoin = stmt.joins.length > 0 && stmt.where !== null && stmt.joins.every((join2) => join2.type === "INNER" || join2.type === "CROSS") && [stmt.from, ...stmt.joins.map((join2) => join2.table)].every(
|
|
19560
19724
|
(table) => table.alias !== null && table.cteName === null && !table.subtableCode
|
|
19561
19725
|
);
|
|
19562
19726
|
if (directInnerJoin) {
|
|
@@ -24273,6 +24437,7 @@ var explainJoinPushdownPlans = /* @__PURE__ */ new WeakMap();
|
|
|
24273
24437
|
var explainPushdownPlans = /* @__PURE__ */ new WeakMap();
|
|
24274
24438
|
var explainJoinKeyPrefilters = /* @__PURE__ */ new WeakMap();
|
|
24275
24439
|
var explainChoiceEqualityRewrites = /* @__PURE__ */ new WeakMap();
|
|
24440
|
+
var explainCrossJoinSteps = /* @__PURE__ */ new WeakMap();
|
|
24276
24441
|
var validateExplainInfo = /* @__PURE__ */ new WeakMap();
|
|
24277
24442
|
var applyParentExplainPlan = /* @__PURE__ */ new WeakMap();
|
|
24278
24443
|
async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords = 1e4, relativeDatePlan, initialRelations) {
|
|
@@ -24304,6 +24469,54 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24304
24469
|
);
|
|
24305
24470
|
const explainRelations = new Map(initialRelations ?? []);
|
|
24306
24471
|
const staticExplainRelations = new Set(initialRelations?.keys() ?? []);
|
|
24472
|
+
const exactRelationRows = new Map(
|
|
24473
|
+
[...initialRelations ?? /* @__PURE__ */ new Map()].map(([name, relation]) => [name, relation.rows.length])
|
|
24474
|
+
);
|
|
24475
|
+
const staticSelectRows = /* @__PURE__ */ new WeakMap();
|
|
24476
|
+
const tableLabel = (table) => effectiveTableAlias(table) ?? (table.appId > 0 ? `APP${table.appId}` : "source");
|
|
24477
|
+
const tableExactRows = (table) => {
|
|
24478
|
+
if (table.cteName === NO_FROM_CTE_NAME) return 1;
|
|
24479
|
+
if (table.cteName !== null) return exactRelationRows.get(table.cteName) ?? null;
|
|
24480
|
+
return null;
|
|
24481
|
+
};
|
|
24482
|
+
const analyzeStaticSelectRows = (select) => {
|
|
24483
|
+
let currentRows = tableExactRows(select.from);
|
|
24484
|
+
let leftLabel = tableLabel(select.from);
|
|
24485
|
+
const steps = [];
|
|
24486
|
+
for (const join2 of select.joins) {
|
|
24487
|
+
const rightRows = tableExactRows(join2.table);
|
|
24488
|
+
const rightLabel = tableLabel(join2.table);
|
|
24489
|
+
if (join2.type === "CROSS") {
|
|
24490
|
+
const plan = currentRows !== null && rightRows !== null ? planCrossJoinRows(currentRows, rightRows) : null;
|
|
24491
|
+
steps.push({
|
|
24492
|
+
leftLabel,
|
|
24493
|
+
rightLabel,
|
|
24494
|
+
leftRows: currentRows,
|
|
24495
|
+
rightRows,
|
|
24496
|
+
plan,
|
|
24497
|
+
rightRuntimeLabel: join2.table.cteName === null ? `APP${join2.table.appId} fetched rows` : `${rightLabel} materialized rows`
|
|
24498
|
+
});
|
|
24499
|
+
currentRows = plan?.outputRows ?? null;
|
|
24500
|
+
leftLabel = `${leftLabel} \xD7 ${rightLabel}`;
|
|
24501
|
+
} else {
|
|
24502
|
+
currentRows = null;
|
|
24503
|
+
leftLabel = `${leftLabel} ${join2.type} JOIN ${rightLabel}`;
|
|
24504
|
+
}
|
|
24505
|
+
}
|
|
24506
|
+
if (steps.length > 0) explainCrossJoinSteps.set(select, steps);
|
|
24507
|
+
if (isConstantFalseWhere(select.where)) currentRows = 0;
|
|
24508
|
+
else if (select.where !== null) currentRows = null;
|
|
24509
|
+
const grouping = normalizeGroupingSpec(select);
|
|
24510
|
+
if (grouping.type !== "NONE" || select.distinct || select.having !== null || isAggregateQueryBlock(select) || select.columns.some((column) => column.type === "WINDOW_COL")) {
|
|
24511
|
+
currentRows = null;
|
|
24512
|
+
}
|
|
24513
|
+
if (currentRows !== null) {
|
|
24514
|
+
const offset = select.offset ?? 0;
|
|
24515
|
+
currentRows = Math.max(0, currentRows - offset);
|
|
24516
|
+
if (select.limit !== null) currentRows = Math.min(currentRows, select.limit);
|
|
24517
|
+
staticSelectRows.set(select, currentRows);
|
|
24518
|
+
}
|
|
24519
|
+
};
|
|
24307
24520
|
const explainSourceColumns = async (select) => {
|
|
24308
24521
|
const tables = [select.from, ...select.joins.map((join2) => join2.table)];
|
|
24309
24522
|
if (tables.length > 1 && select.columns.some(
|
|
@@ -24392,10 +24605,15 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24392
24605
|
uniqueGeneratedColumn: cte.query.columnAlias
|
|
24393
24606
|
});
|
|
24394
24607
|
staticExplainRelations.add(cte.name);
|
|
24608
|
+
exactRelationRows.set(cte.name, generated.rows.length);
|
|
24395
24609
|
continue;
|
|
24396
24610
|
}
|
|
24397
24611
|
const columns = await inferExplainRelationColumns(cte.query);
|
|
24398
24612
|
explainRelations.set(cte.name, { rows: [], columns });
|
|
24613
|
+
if (cte.query.type === "SELECT") {
|
|
24614
|
+
const rowCount = staticSelectRows.get(cte.query);
|
|
24615
|
+
if (rowCount !== void 0) exactRelationRows.set(cte.name, rowCount);
|
|
24616
|
+
}
|
|
24399
24617
|
}
|
|
24400
24618
|
await preflightExplainRelations(withStatement.query);
|
|
24401
24619
|
return;
|
|
@@ -24407,6 +24625,7 @@ async function buildExplainWhereAnalysis(query, client, cacheContext, maxRecords
|
|
|
24407
24625
|
}
|
|
24408
24626
|
if (typed["type"] === "SELECT") {
|
|
24409
24627
|
const select = node;
|
|
24628
|
+
analyzeStaticSelectRows(select);
|
|
24410
24629
|
for (const column of select.columns) {
|
|
24411
24630
|
if (column.type === "SCALAR_SUBQUERY_COL") await preflightExplainRelations(column.query);
|
|
24412
24631
|
}
|
|
@@ -25440,6 +25659,23 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
25440
25659
|
);
|
|
25441
25660
|
if (label) lines.push(label);
|
|
25442
25661
|
lines.push(` mode: ${mode}`);
|
|
25662
|
+
for (const step of explainCrossJoinSteps.get(stmt) ?? []) {
|
|
25663
|
+
lines.push(` cross join: ${step.leftLabel} \xD7 ${step.rightLabel}`);
|
|
25664
|
+
lines.push(` left rows: ${step.leftRows ?? "runtime (left intermediate rows)"}`);
|
|
25665
|
+
lines.push(` right rows: ${step.rightRows ?? `runtime (${step.rightRuntimeLabel})`}`);
|
|
25666
|
+
if (step.plan) {
|
|
25667
|
+
lines.push(` rows: ${step.plan.outputRows}`);
|
|
25668
|
+
lines.push(` row guard: ${step.plan.outputRows} / ${step.plan.limit}`);
|
|
25669
|
+
lines.push(" guard timing: before row materialization");
|
|
25670
|
+
} else {
|
|
25671
|
+
const left = step.leftRows === null ? "left rows" : String(step.leftRows);
|
|
25672
|
+
const right = step.rightRows === null ? "right rows" : String(step.rightRows);
|
|
25673
|
+
lines.push(` rows: runtime (${left} \xD7 ${right})`);
|
|
25674
|
+
lines.push(` row guard: runtime checked / ${CROSS_JOIN_MAX_ROWS}`);
|
|
25675
|
+
lines.push(" guard timing: after complete source fetch, before row materialization");
|
|
25676
|
+
}
|
|
25677
|
+
lines.push(" records API: none");
|
|
25678
|
+
}
|
|
25443
25679
|
for (const rewrite of explainChoiceEqualityRewrites.get(stmt) ?? choiceEqualityRewritesBySelect.get(stmt) ?? []) {
|
|
25444
25680
|
lines.push(formatChoiceEqualityRewrite(rewrite));
|
|
25445
25681
|
}
|
|
@@ -25604,7 +25840,7 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
25604
25840
|
}
|
|
25605
25841
|
}
|
|
25606
25842
|
} else {
|
|
25607
|
-
const reason = stmt.joins.some((join2) => join2.type !== "INNER") ? "OUTER_JOIN" : [stmt.from, ...stmt.joins.map((join2) => join2.table)].some(
|
|
25843
|
+
const reason = stmt.joins.some((join2) => join2.type !== "INNER" && join2.type !== "CROSS") ? "OUTER_JOIN" : [stmt.from, ...stmt.joins.map((join2) => join2.table)].some(
|
|
25608
25844
|
(table) => table.cteName !== null || Boolean(table.subtableCode)
|
|
25609
25845
|
) ? "SOURCE_KIND" : "PLAN_NOT_APPLICABLE";
|
|
25610
25846
|
lines.push(" join pushdown plan: not applied (join key/WHERE prefilters are reported per source below)");
|
|
@@ -25756,7 +25992,67 @@ function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans, colle
|
|
|
25756
25992
|
});
|
|
25757
25993
|
return lines;
|
|
25758
25994
|
}
|
|
25995
|
+
function populateWithCrossJoinExplain(stmt) {
|
|
25996
|
+
const exactRows = /* @__PURE__ */ new Map();
|
|
25997
|
+
const labelFor = (table) => effectiveTableAlias(table) ?? (table.appId > 0 ? `APP${table.appId}` : "source");
|
|
25998
|
+
const rowsFor = (table) => {
|
|
25999
|
+
if (table.cteName === NO_FROM_CTE_NAME) return 1;
|
|
26000
|
+
return table.cteName === null ? null : exactRows.get(table.cteName) ?? null;
|
|
26001
|
+
};
|
|
26002
|
+
const analyze = (select) => {
|
|
26003
|
+
let current = rowsFor(select.from);
|
|
26004
|
+
let leftLabel = labelFor(select.from);
|
|
26005
|
+
const steps = [];
|
|
26006
|
+
for (const join2 of select.joins) {
|
|
26007
|
+
const right = rowsFor(join2.table);
|
|
26008
|
+
const rightLabel = labelFor(join2.table);
|
|
26009
|
+
if (join2.type === "CROSS") {
|
|
26010
|
+
const plan = current !== null && right !== null ? planCrossJoinRows(current, right) : null;
|
|
26011
|
+
steps.push({
|
|
26012
|
+
leftLabel,
|
|
26013
|
+
rightLabel,
|
|
26014
|
+
leftRows: current,
|
|
26015
|
+
rightRows: right,
|
|
26016
|
+
plan,
|
|
26017
|
+
rightRuntimeLabel: join2.table.cteName === null ? `APP${join2.table.appId} fetched rows` : `${rightLabel} materialized rows`
|
|
26018
|
+
});
|
|
26019
|
+
current = plan?.outputRows ?? null;
|
|
26020
|
+
leftLabel = `${leftLabel} \xD7 ${rightLabel}`;
|
|
26021
|
+
} else {
|
|
26022
|
+
current = null;
|
|
26023
|
+
leftLabel = `${leftLabel} ${join2.type} JOIN ${rightLabel}`;
|
|
26024
|
+
}
|
|
26025
|
+
}
|
|
26026
|
+
if (steps.length > 0) explainCrossJoinSteps.set(select, steps);
|
|
26027
|
+
if (isConstantFalseWhere(select.where)) current = 0;
|
|
26028
|
+
else if (select.where !== null) current = null;
|
|
26029
|
+
if (normalizeGroupingSpec(select).type !== "NONE" || select.distinct || select.having !== null || isAggregateQueryBlock(select) || select.columns.some((column) => column.type === "WINDOW_COL")) return null;
|
|
26030
|
+
if (current === null) return null;
|
|
26031
|
+
current = Math.max(0, current - (select.offset ?? 0));
|
|
26032
|
+
return select.limit === null ? current : Math.min(current, select.limit);
|
|
26033
|
+
};
|
|
26034
|
+
const analyzeQuery = (query) => {
|
|
26035
|
+
if (query.type === "SELECT") {
|
|
26036
|
+
analyze(query);
|
|
26037
|
+
return;
|
|
26038
|
+
}
|
|
26039
|
+
analyzeQuery(query.left);
|
|
26040
|
+
analyze(query.right);
|
|
26041
|
+
};
|
|
26042
|
+
for (const cte of stmt.ctes) {
|
|
26043
|
+
if (cte.query.type === "GENERATE_SERIES") {
|
|
26044
|
+
exactRows.set(cte.name, resolveGenerateSeries(cte.query).rowCount);
|
|
26045
|
+
} else if (cte.query.type === "SELECT") {
|
|
26046
|
+
const rows = analyze(cte.query);
|
|
26047
|
+
if (rows !== null) exactRows.set(cte.name, rows);
|
|
26048
|
+
} else if (cte.query.type === "UNION") {
|
|
26049
|
+
analyzeQuery(cte.query);
|
|
26050
|
+
}
|
|
26051
|
+
}
|
|
26052
|
+
analyzeQuery(stmt.query);
|
|
26053
|
+
}
|
|
25759
26054
|
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
|
|
26055
|
+
populateWithCrossJoinExplain(stmt);
|
|
25760
26056
|
const lines = [];
|
|
25761
26057
|
for (const cte of stmt.ctes) {
|
|
25762
26058
|
if (cte.query.type === "SELECT") {
|
|
@@ -25774,7 +26070,7 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collec
|
|
|
25774
26070
|
lines.push("");
|
|
25775
26071
|
} else if (cte.query.type === "GENERATE_SERIES") {
|
|
25776
26072
|
const series = resolveGenerateSeries(cte.query);
|
|
25777
|
-
const step = series.kind === "DATE" ? `${series.step} ${Math.abs(series.step) === 1 ? "
|
|
26073
|
+
const step = series.kind === "DATE" ? `${series.step} ${String(series.dateUnit ?? "DAY").toLowerCase()}${Math.abs(series.step) === 1 ? "" : "s"}` : String(series.step);
|
|
25778
26074
|
lines.push(
|
|
25779
26075
|
`[cte: ${cte.name}]`,
|
|
25780
26076
|
" source: GENERATE_SERIES",
|
|
@@ -25825,7 +26121,9 @@ function collectFullScanReasons(stmt) {
|
|
|
25825
26121
|
const r = [];
|
|
25826
26122
|
if (stmt.from.subtableCode || stmt.joins.some((j) => j.table.subtableCode))
|
|
25827
26123
|
r.push("\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u4EEE\u60F3\u30C6\u30FC\u30D6\u30EB");
|
|
25828
|
-
if (stmt.joins.
|
|
26124
|
+
if (stmt.joins.some((join2) => join2.type === "CROSS"))
|
|
26125
|
+
r.push("CROSS JOIN \u3042\u308A");
|
|
26126
|
+
if (stmt.joins.some((join2) => join2.type !== "CROSS"))
|
|
25829
26127
|
r.push("JOIN \u3042\u308A");
|
|
25830
26128
|
const grouping = normalizeGroupingSpec(stmt);
|
|
25831
26129
|
if (grouping.type === "PLAIN")
|
|
@@ -28906,14 +29204,39 @@ function createDryRunClient() {
|
|
|
28906
29204
|
function hasStaticTypedPushdownCandidate(statement) {
|
|
28907
29205
|
if (statement === null || typeof statement !== "object") return false;
|
|
28908
29206
|
const node = statement;
|
|
28909
|
-
if (node["type"] === "WITH")
|
|
29207
|
+
if (node["type"] === "WITH") {
|
|
29208
|
+
const query = node["query"];
|
|
29209
|
+
const containsCross = (value) => {
|
|
29210
|
+
if (Array.isArray(value)) return value.some(containsCross);
|
|
29211
|
+
if (value === null || typeof value !== "object") return false;
|
|
29212
|
+
const item = value;
|
|
29213
|
+
if (item["type"] === "SELECT") {
|
|
29214
|
+
if (Array.isArray(item["joins"]) && item["joins"].some(
|
|
29215
|
+
(join2) => typeof join2 === "object" && join2 !== null && join2["type"] === "CROSS"
|
|
29216
|
+
)) return true;
|
|
29217
|
+
}
|
|
29218
|
+
return Object.values(item).some(containsCross);
|
|
29219
|
+
};
|
|
29220
|
+
const hasPhysicalCte = Array.isArray(node["ctes"]) && node["ctes"].some((cte) => {
|
|
29221
|
+
if (typeof cte !== "object" || cte === null) return false;
|
|
29222
|
+
const cteQuery = cte["query"];
|
|
29223
|
+
if (typeof cteQuery !== "object" || cteQuery === null) return false;
|
|
29224
|
+
const from = cteQuery["from"];
|
|
29225
|
+
return cteQuery["type"] === "SELECT" && typeof from === "object" && from !== null && from["cteName"] === null;
|
|
29226
|
+
});
|
|
29227
|
+
return (containsCross(node["ctes"]) || containsCross(query)) && hasPhysicalCte || hasStaticTypedPushdownCandidate(query);
|
|
29228
|
+
}
|
|
28910
29229
|
if (node["type"] !== "SELECT") return false;
|
|
28911
29230
|
const select = statement;
|
|
28912
|
-
if (!
|
|
29231
|
+
if (!Array.isArray(select.joins) || select.joins.length === 0) return false;
|
|
28913
29232
|
if (![select.from, ...select.joins.map((join2) => join2.table)].some((table) => table.cteName !== null)) return false;
|
|
29233
|
+
if (select.joins.some((join2) => join2.type === "CROSS" && join2.table.cteName === null)) {
|
|
29234
|
+
return true;
|
|
29235
|
+
}
|
|
29236
|
+
if (!select.where) return false;
|
|
28914
29237
|
const where = select.where;
|
|
28915
29238
|
return select.joins.some(
|
|
28916
|
-
(join2) => join2.type === "INNER" && join2.table?.alias && join2.table?.cteName === null && !join2.table?.subtableCode && extractTypedPushdownCandidates(where, { tableAlias: join2.table.alias }) !== null
|
|
29239
|
+
(join2) => (join2.type === "INNER" || join2.type === "CROSS") && join2.table?.alias && join2.table?.cteName === null && !join2.table?.subtableCode && extractTypedPushdownCandidates(where, { tableAlias: join2.table.alias }) !== null
|
|
28917
29240
|
);
|
|
28918
29241
|
}
|
|
28919
29242
|
async function runDiagnosticRecordGet(params) {
|
|
@@ -29987,7 +30310,7 @@ async function run() {
|
|
|
29987
30310
|
Object.keys(args.importCsv).length > 0 || Object.keys(args.importJson).length > 0,
|
|
29988
30311
|
dmlMaxRows,
|
|
29989
30312
|
dmlMaxSubtableRows,
|
|
29990
|
-
|
|
30313
|
+
!dryRunUsesStaticTypedPlan
|
|
29991
30314
|
);
|
|
29992
30315
|
const out = [];
|
|
29993
30316
|
const restoredStatements = sqlDiagnosticContext ? restoreSqlDiagnosticValue(plans.statements, sqlDiagnosticContext.appBindingByMappedApp) : plans.statements;
|