@rex0220/kintone-sql-tools 3.38.0 → 3.40.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 +408 -48
- package/dist-engine/index.cjs +12 -12
- package/dist-engine/index.mjs +12 -12
- package/dist-engine/ksql-engine.umd.js +12 -12
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +12 -12
- package/dist-engine/meta/esm.json +12 -12
- package/dist-engine/meta/umd.json +12 -12
- package/dist-engine/publicTypes.d.ts +15 -0
- package/dist-mcp/ksql-mcp.js +410 -50
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -1175,13 +1175,38 @@ var Parser = class {
|
|
|
1175
1175
|
parseDeclareVariable() {
|
|
1176
1176
|
this.advance();
|
|
1177
1177
|
const variable = this.expect("VARIABLE" /* VARIABLE */, "DECLARE \u306E\u5F8C\u306B\u306F\u5909\u6570\u540D\uFF08\u4F8B: @name\uFF09\u304C\u5FC5\u8981\u3067\u3059");
|
|
1178
|
+
const relativeDate = this.peek().kind === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "RELATIVE_DATE";
|
|
1179
|
+
if (relativeDate) this.advance();
|
|
1178
1180
|
this.expect("=" /* EQ */);
|
|
1181
|
+
if (relativeDate) {
|
|
1182
|
+
return {
|
|
1183
|
+
type: "DECLARE_VARIABLE",
|
|
1184
|
+
name: variable.value.slice(1).toLowerCase(),
|
|
1185
|
+
annotation: "RELATIVE_DATE",
|
|
1186
|
+
default: this.parseRelativeDateVariableToken()
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1179
1189
|
const expr = this.parseScalarExpr("DECLARE", false);
|
|
1180
1190
|
if (expr.type === "SCALAR_SUBQUERY") {
|
|
1181
1191
|
throw new ParseError("DECLARE \u306E\u65E2\u5B9A\u5024\u306B\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
1182
1192
|
}
|
|
1183
1193
|
return { type: "DECLARE_VARIABLE", name: variable.value.slice(1).toLowerCase(), default: expr };
|
|
1184
1194
|
}
|
|
1195
|
+
/** RELATIVE_DATE 宣言専用。WHERE と同じ関数パーサーを使い、日付系14個だけを許可する。 */
|
|
1196
|
+
parseRelativeDateVariableToken() {
|
|
1197
|
+
const tok = this.peek();
|
|
1198
|
+
const contextualFunction = PARSER_CONTEXTUAL_FUNCTION_TOKEN_MAP[tok.kind];
|
|
1199
|
+
if (contextualFunction === "TODAY" || contextualFunction === "NOW") {
|
|
1200
|
+
return this.parseSqlValue();
|
|
1201
|
+
}
|
|
1202
|
+
if (tok.kind === "IDENT" /* IDENT */ && this.peekAt(1).kind === "(" /* LPAREN */ && isRelativeDateFunctionName(tok.value.toUpperCase())) {
|
|
1203
|
+
return this.parseRelativeDateFunction();
|
|
1204
|
+
}
|
|
1205
|
+
throw new ParseError(
|
|
1206
|
+
"RELATIVE_DATE \u306E\u65E2\u5B9A\u5024\u306B\u306F\u30B5\u30DD\u30FC\u30C8\u5BFE\u8C61\u306E\u76F8\u5BFE\u65E5\u4ED8\u95A2\u6570\u30C8\u30FC\u30AF\u30F3\u304C\u5FC5\u8981\u3067\u3059",
|
|
1207
|
+
tok
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1185
1210
|
/** SET / DECLARE RHS 専用。既存式パーサーで構文を読み、フィールド参照を明示的に拒否する。 */
|
|
1186
1211
|
parseScalarExpr(context, allowScalarSubquery) {
|
|
1187
1212
|
const tok = this.peek();
|
|
@@ -6807,9 +6832,10 @@ function collectRefs(node, tempRefs, appIds) {
|
|
|
6807
6832
|
for (const v of Object.values(obj)) collectRefs(v, tempRefs, appIds);
|
|
6808
6833
|
}
|
|
6809
6834
|
}
|
|
6810
|
-
|
|
6835
|
+
var RELATIVE_DATE_COMPARISON_OPS = /* @__PURE__ */ new Set(["=", "!=", "<>", ">", "<", ">=", "<="]);
|
|
6836
|
+
function collectVariableRefs(node, refs, inWhere = false) {
|
|
6811
6837
|
if (Array.isArray(node)) {
|
|
6812
|
-
for (const v of node) collectVariableRefs(v, refs);
|
|
6838
|
+
for (const v of node) collectVariableRefs(v, refs, inWhere);
|
|
6813
6839
|
return;
|
|
6814
6840
|
}
|
|
6815
6841
|
if (node !== null && typeof node === "object") {
|
|
@@ -6818,13 +6844,27 @@ function collectVariableRefs(node, refs) {
|
|
|
6818
6844
|
if ((type === "VARIABLE" || type === "VARIABLE_COL" || type === "VARIABLE_IN_LIST") && typeof obj["name"] === "string") {
|
|
6819
6845
|
refs.push({
|
|
6820
6846
|
name: obj["name"],
|
|
6821
|
-
kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list"
|
|
6847
|
+
kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list",
|
|
6848
|
+
relativeDateAllowed: inWhere
|
|
6822
6849
|
});
|
|
6823
6850
|
return;
|
|
6824
6851
|
}
|
|
6825
|
-
|
|
6852
|
+
const preservesWhereContext = type === "BINARY" || type === "LOGICAL" || type === "NOT" || type === "GROUP" || type === "NULL_CHECK" || type === "BOOLEAN";
|
|
6853
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
6854
|
+
const directVariable = value !== null && typeof value === "object" && value["type"] === "VARIABLE";
|
|
6855
|
+
const directComparisonRight = inWhere && type === "BINARY" && key === "right" && directVariable && RELATIVE_DATE_COMPARISON_OPS.has(String(obj["op"]));
|
|
6856
|
+
collectVariableRefs(
|
|
6857
|
+
value,
|
|
6858
|
+
refs,
|
|
6859
|
+
key === "where" ? true : type === "BINARY" && key === "right" && directVariable ? directComparisonRight : preservesWhereContext ? inWhere : false
|
|
6860
|
+
);
|
|
6861
|
+
}
|
|
6826
6862
|
}
|
|
6827
6863
|
}
|
|
6864
|
+
function isRelativeDateDmlUse(stmt) {
|
|
6865
|
+
const target = stmt.type === "EXPLAIN" ? stmt.query : stmt;
|
|
6866
|
+
return isDmlType(target.type) || target.type === "VALIDATE";
|
|
6867
|
+
}
|
|
6828
6868
|
function validateGroupingStaticQueries(node) {
|
|
6829
6869
|
if (Array.isArray(node)) {
|
|
6830
6870
|
for (const value of node) validateGroupingStaticQueries(value);
|
|
@@ -6919,6 +6959,18 @@ function analyzeBatch(statements) {
|
|
|
6919
6959
|
index
|
|
6920
6960
|
);
|
|
6921
6961
|
}
|
|
6962
|
+
if (def.relativeDate && isRelativeDateDmlUse(stmt)) {
|
|
6963
|
+
throw new BatchAnalysisError(
|
|
6964
|
+
`ArgumentError: RELATIVE_DATE variable @${use.name} cannot be used in DML or VALIDATE statements.`,
|
|
6965
|
+
index
|
|
6966
|
+
);
|
|
6967
|
+
}
|
|
6968
|
+
if (def.relativeDate && !use.relativeDateAllowed) {
|
|
6969
|
+
throw new BatchAnalysisError(
|
|
6970
|
+
`ArgumentError: RELATIVE_DATE variable @${use.name} can only be used as a WHERE comparison right operand or BETWEEN boundary.`,
|
|
6971
|
+
index
|
|
6972
|
+
);
|
|
6973
|
+
}
|
|
6922
6974
|
if (!referencedThisStatement.has(use.name)) {
|
|
6923
6975
|
def.referencedBy.push(index);
|
|
6924
6976
|
referencedThisStatement.add(use.name);
|
|
@@ -6931,6 +6983,7 @@ function analyzeBatch(statements) {
|
|
|
6931
6983
|
variableDefs.set(stmt.name, {
|
|
6932
6984
|
index,
|
|
6933
6985
|
kind: stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? "array" : "scalar",
|
|
6986
|
+
relativeDate: stmt.type === "DECLARE_VARIABLE" && stmt.annotation === "RELATIVE_DATE",
|
|
6934
6987
|
referencedBy: []
|
|
6935
6988
|
});
|
|
6936
6989
|
variableOrder.push(stmt.name);
|
|
@@ -16123,6 +16176,7 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
16123
16176
|
throw new Error("UnsupportedError: APPLY mutation requires allowApplyMutation=true");
|
|
16124
16177
|
}
|
|
16125
16178
|
const injectedVariables = validateDeclaredBatchVariables(statements, options.variables);
|
|
16179
|
+
const relativeDateVariables = prepareRelativeDateVariables(statements, injectedVariables);
|
|
16126
16180
|
const batchOptions = { ...options, variables: injectedVariables };
|
|
16127
16181
|
if (options.continueOnError && analysis.containsDml) {
|
|
16128
16182
|
throw new Error("ArgumentError: continueOnError is not allowed for batches containing DML.");
|
|
@@ -16194,7 +16248,16 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
16194
16248
|
);
|
|
16195
16249
|
const cursorScope = wrapClientWithCursorScope(statementClient);
|
|
16196
16250
|
const outcome = await runWithDeadline(
|
|
16197
|
-
executeBatchStatement(
|
|
16251
|
+
executeBatchStatement(
|
|
16252
|
+
statements[i],
|
|
16253
|
+
info,
|
|
16254
|
+
cursorScope.client,
|
|
16255
|
+
stmtOptions,
|
|
16256
|
+
cacheContext,
|
|
16257
|
+
tempTables,
|
|
16258
|
+
variables,
|
|
16259
|
+
relativeDateVariables
|
|
16260
|
+
),
|
|
16198
16261
|
remaining,
|
|
16199
16262
|
cursorScope.closeActive
|
|
16200
16263
|
);
|
|
@@ -16239,7 +16302,7 @@ function statementHasApplyMutation(statement) {
|
|
|
16239
16302
|
}
|
|
16240
16303
|
return statement.type === "UPSERT" && statement.validateOnly !== true && Boolean(statement.onInsertApplyBlocks?.length || statement.onUpdateApplyBlocks?.length);
|
|
16241
16304
|
}
|
|
16242
|
-
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables) {
|
|
16305
|
+
async function executeBatchStatement(stmt, info, client, options, cacheContext, tempTables, variables, relativeDateVariables) {
|
|
16243
16306
|
if (stmt.type === "SET_VARIABLE") {
|
|
16244
16307
|
const resolvedStmt2 = resolveBatchVariableReferences(stmt, variables);
|
|
16245
16308
|
validateStatementStatic(resolvedStmt2);
|
|
@@ -16284,6 +16347,13 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
16284
16347
|
return {};
|
|
16285
16348
|
}
|
|
16286
16349
|
if (stmt.type === "DECLARE_VARIABLE") {
|
|
16350
|
+
if (stmt.annotation === "RELATIVE_DATE") {
|
|
16351
|
+
variables.set(stmt.name, {
|
|
16352
|
+
type: "relative-date",
|
|
16353
|
+
value: relativeDateVariables.get(stmt.name)
|
|
16354
|
+
});
|
|
16355
|
+
return {};
|
|
16356
|
+
}
|
|
16287
16357
|
const injected = options.variables ?? {};
|
|
16288
16358
|
if (Object.prototype.hasOwnProperty.call(injected, stmt.name)) {
|
|
16289
16359
|
variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
|
|
@@ -16507,6 +16577,32 @@ function parseSqlBatch(sql, enableImport = false) {
|
|
|
16507
16577
|
const tokens = new Lexer(sql).tokenize();
|
|
16508
16578
|
return new Parser(tokens, { import: enableImport }).parseStatements();
|
|
16509
16579
|
}
|
|
16580
|
+
function parseRelativeDateVariableValue(name, value) {
|
|
16581
|
+
try {
|
|
16582
|
+
const statements = parseSqlBatch(`DECLARE @__b111 RELATIVE_DATE = ${value}`);
|
|
16583
|
+
const declaration = statements[0];
|
|
16584
|
+
if (statements.length !== 1 || declaration?.type !== "DECLARE_VARIABLE" || declaration.annotation !== "RELATIVE_DATE") {
|
|
16585
|
+
throw new Error("token was not consumed as one RELATIVE_DATE declaration");
|
|
16586
|
+
}
|
|
16587
|
+
return declaration.default;
|
|
16588
|
+
} catch (error) {
|
|
16589
|
+
const detail = error instanceof Error ? ` ${error.message}` : "";
|
|
16590
|
+
throw new Error(
|
|
16591
|
+
`ArgumentError: RELATIVE_DATE variable @${name} requires one supported relative-date function token.${detail}`
|
|
16592
|
+
);
|
|
16593
|
+
}
|
|
16594
|
+
}
|
|
16595
|
+
function prepareRelativeDateVariables(statements, injectedVariables) {
|
|
16596
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
16597
|
+
for (const stmt of statements) {
|
|
16598
|
+
if (stmt.type !== "DECLARE_VARIABLE" || stmt.annotation !== "RELATIVE_DATE") continue;
|
|
16599
|
+
prepared.set(
|
|
16600
|
+
stmt.name,
|
|
16601
|
+
Object.prototype.hasOwnProperty.call(injectedVariables, stmt.name) ? parseRelativeDateVariableValue(stmt.name, injectedVariables[stmt.name]) : stmt.default
|
|
16602
|
+
);
|
|
16603
|
+
}
|
|
16604
|
+
return prepared;
|
|
16605
|
+
}
|
|
16510
16606
|
function evaluateScalarExpr(expr) {
|
|
16511
16607
|
switch (expr.type) {
|
|
16512
16608
|
case "STRING":
|
|
@@ -16543,7 +16639,8 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
|
|
|
16543
16639
|
if (value.type === "array") {
|
|
16544
16640
|
throw new Error(`ParseError: array variable @${obj["name"]} can only be used as IN @${obj["name"]}.`);
|
|
16545
16641
|
}
|
|
16546
|
-
if (
|
|
16642
|
+
if (value.type === "relative-date") return value.value;
|
|
16643
|
+
if (numericArithmeticOperand && value.type !== "number" && !(value.type === "string" && value.placeholder === true)) {
|
|
16547
16644
|
throw new Error(
|
|
16548
16645
|
`ArgumentError: variable @${obj["name"]} is not numeric and cannot be used in arithmetic.`
|
|
16549
16646
|
);
|
|
@@ -16554,6 +16651,9 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
|
|
|
16554
16651
|
const value = variables.get(obj["name"]);
|
|
16555
16652
|
if (value === void 0) throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
|
|
16556
16653
|
if (value.type === "array") throw new Error(`ParseError: array variable @${obj["name"]} cannot be used as a SELECT column.`);
|
|
16654
|
+
if (value.type === "relative-date") {
|
|
16655
|
+
throw new Error(`InternalError: RELATIVE_DATE variable @${obj["name"]} reached a SELECT column.`);
|
|
16656
|
+
}
|
|
16557
16657
|
const aliasDisplay = typeof obj["aliasDisplay"] === "string" ? { aliasDisplay: obj["aliasDisplay"] } : {};
|
|
16558
16658
|
return value.type === "number" ? { type: "ARITH_COL", expr: { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) }, alias: obj["alias"], ...aliasDisplay } : { type: "LITERAL_COL", value: value.value, alias: obj["alias"], ...aliasDisplay };
|
|
16559
16659
|
}
|
|
@@ -22668,14 +22768,20 @@ function serverFunctionClientEvaluationLabel(leaves) {
|
|
|
22668
22768
|
(leaf) => leaf.right.type === "KINTONE_FUNC" && isRelativeDateFunctionName(leaf.right.name)
|
|
22669
22769
|
) ? "relative date client evaluations" : "kintone function client evaluations";
|
|
22670
22770
|
}
|
|
22771
|
+
var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
|
|
22772
|
+
function setExplainFetchPlan(result, plan) {
|
|
22773
|
+
result[EXPLAIN_FETCH_PLAN] = plan;
|
|
22774
|
+
}
|
|
22671
22775
|
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
|
|
22672
22776
|
const invocationCacheContext = createInvocationCacheContext(cacheContext);
|
|
22673
22777
|
try {
|
|
22674
22778
|
const statements = parseSqlBatch(sql, enableImport);
|
|
22675
22779
|
const analysis = analyzeBatch(statements);
|
|
22676
|
-
validateDeclaredBatchVariables(statements, injectedVariables);
|
|
22780
|
+
const normalizedInjectedVariables = validateDeclaredBatchVariables(statements, injectedVariables);
|
|
22781
|
+
const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
|
|
22677
22782
|
const variables = /* @__PURE__ */ new Map();
|
|
22678
22783
|
const plans = [];
|
|
22784
|
+
const fetchStatements = [];
|
|
22679
22785
|
for (let i = 0; i < statements.length; i++) {
|
|
22680
22786
|
const stmt = statements[i];
|
|
22681
22787
|
const planStmt = stmt.type === "SET_VARIABLE" ? stmt.expr.type === "SCALAR_SUBQUERY" ? { ...stmt, expr: resolveBatchVariableReferences(stmt.expr, variables) } : stmt : resolveBatchVariableReferences(stmt, variables);
|
|
@@ -22688,6 +22794,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
22688
22794
|
maxRecords,
|
|
22689
22795
|
relativeDatePlan
|
|
22690
22796
|
);
|
|
22797
|
+
const fetchCollector = { sources: [] };
|
|
22691
22798
|
const statementPlan = relativeDatePlan.hasServerOnlyWhereFunction && !relativeDatePlan.allowed ? relativeDateExplainLines(relativeDatePlan) : [
|
|
22692
22799
|
...relativeDateExplainLines(relativeDatePlan),
|
|
22693
22800
|
...addCursorConcurrency(buildBatchStatementPlan(
|
|
@@ -22696,7 +22803,8 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
22696
22803
|
whereAnalysis.capabilities,
|
|
22697
22804
|
whereAnalysis.orderPlans,
|
|
22698
22805
|
dmlMaxRows,
|
|
22699
|
-
dmlMaxSubtableRows
|
|
22806
|
+
dmlMaxSubtableRows,
|
|
22807
|
+
fetchCollector
|
|
22700
22808
|
), cursorMaxActive)
|
|
22701
22809
|
];
|
|
22702
22810
|
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
@@ -22705,22 +22813,36 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
22705
22813
|
type: analysis.statements[i].statementType,
|
|
22706
22814
|
plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
|
|
22707
22815
|
});
|
|
22816
|
+
fetchStatements.push({
|
|
22817
|
+
index: i,
|
|
22818
|
+
fetch: worstExplainFetch(fetchCollector.sources),
|
|
22819
|
+
sources: fetchCollector.sources
|
|
22820
|
+
});
|
|
22708
22821
|
if (stmt.type === "SET_VARIABLE" || stmt.type === "DECLARE_VARIABLE") {
|
|
22709
|
-
variables.set(stmt.name, stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? { type: "array", elements: stmt.expr.elements.map((element) => ({ type: "string", value: element.value })) } : { type: "string", value: `@${stmt.name}`, placeholder: true });
|
|
22822
|
+
variables.set(stmt.name, stmt.type === "DECLARE_VARIABLE" && stmt.annotation === "RELATIVE_DATE" ? { type: "relative-date", value: relativeDateVariables.get(stmt.name) } : stmt.type === "SET_VARIABLE" && stmt.expr.type === "ARRAY" ? { type: "array", elements: stmt.expr.elements.map((element) => ({ type: "string", value: element.value })) } : { type: "string", value: `@${stmt.name}`, placeholder: true });
|
|
22710
22823
|
}
|
|
22711
22824
|
}
|
|
22712
|
-
|
|
22825
|
+
const result = { statementCount: statements.length, statements: plans };
|
|
22826
|
+
setExplainFetchPlan(result, { statements: fetchStatements });
|
|
22827
|
+
return result;
|
|
22713
22828
|
} finally {
|
|
22714
22829
|
releaseMetadataCacheScope(invocationCacheContext);
|
|
22715
22830
|
}
|
|
22716
22831
|
}
|
|
22717
|
-
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS) {
|
|
22832
|
+
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }) {
|
|
22718
22833
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
22719
22834
|
return [
|
|
22720
22835
|
`CREATE TEMP TABLE ${stmt.name}`,
|
|
22721
22836
|
` scope: batch\uFF08\u30D0\u30C3\u30C1\u7D42\u4E86\u6642\u306B\u81EA\u52D5\u7834\u68C4\uFF09`,
|
|
22722
22837
|
` rows: \u5B9F\u4F53\u5316\u524D\u306E\u305F\u3081\u4E0D\u660E\uFF08\u65E2\u5B9A\u4E0A\u9650 ${TEMP_TABLE_MAX_ROWS} \u884C\u3001tempTableMaxRows \u3067\u5909\u66F4\u53EF\u3001\u8D85\u904E\u306F\u30A8\u30E9\u30FC\uFF09`,
|
|
22723
|
-
...buildPlanForBatchQuery(
|
|
22838
|
+
...buildPlanForBatchQuery(
|
|
22839
|
+
stmt.query,
|
|
22840
|
+
info,
|
|
22841
|
+
capabilities,
|
|
22842
|
+
orderPlans,
|
|
22843
|
+
collector,
|
|
22844
|
+
"main"
|
|
22845
|
+
).map((l) => ` ${l}`)
|
|
22724
22846
|
];
|
|
22725
22847
|
}
|
|
22726
22848
|
if (stmt.type === "DROP_TEMP_TABLE") {
|
|
@@ -22736,7 +22858,13 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
22736
22858
|
`SET @${stmt.name} = (SELECT ...)`,
|
|
22737
22859
|
" value: \u30B5\u30D6\u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF081\u884C1\u5217\u30FB\u30D0\u30C3\u30C1\u5185\u5B9A\u6570\u30FB\u7D50\u679C\u30E1\u30BF\u30C7\u30FC\u30BF\u306B\u306F\u975E\u516C\u958B\uFF09",
|
|
22738
22860
|
" subquery:",
|
|
22739
|
-
...buildPlanForBatchQuery(
|
|
22861
|
+
...buildPlanForBatchQuery(
|
|
22862
|
+
stmt.expr.query,
|
|
22863
|
+
subInfo,
|
|
22864
|
+
capabilities,
|
|
22865
|
+
orderPlans,
|
|
22866
|
+
collector
|
|
22867
|
+
).map((l) => ` ${l}`)
|
|
22740
22868
|
];
|
|
22741
22869
|
}
|
|
22742
22870
|
return [
|
|
@@ -22745,6 +22873,12 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
22745
22873
|
];
|
|
22746
22874
|
}
|
|
22747
22875
|
if (stmt.type === "DECLARE_VARIABLE") {
|
|
22876
|
+
if (stmt.annotation === "RELATIVE_DATE") {
|
|
22877
|
+
return [
|
|
22878
|
+
`DECLARE @${stmt.name} RELATIVE_DATE = <relative-date token>`,
|
|
22879
|
+
" value: \u5916\u90E8\u6CE8\u5165\u304C\u3042\u308C\u3070\u63A1\u7528\u3001\u306A\u3051\u308C\u3070\u65E2\u5B9A\u30C8\u30FC\u30AF\u30F3\u3092\u4F7F\u7528\uFF08\u5024\u306F\u975E\u516C\u958B\uFF09"
|
|
22880
|
+
];
|
|
22881
|
+
}
|
|
22748
22882
|
return [
|
|
22749
22883
|
`DECLARE @${stmt.name} = <default scalar expression>`,
|
|
22750
22884
|
" value: \u5916\u90E8\u6CE8\u5165\u304C\u3042\u308C\u3070\u63A1\u7528\u3001\u306A\u3051\u308C\u3070\u65E2\u5B9A\u5024\u3092\u5B9F\u884C\u6642\u306B1\u56DE\u8A55\u4FA1\uFF08\u5024\u306F\u975E\u516C\u958B\uFF09"
|
|
@@ -22752,7 +22886,15 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
22752
22886
|
}
|
|
22753
22887
|
if (stmt.type === "SHOW_APPS") return ["SHOW APPS\uFF08\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\uFF09"];
|
|
22754
22888
|
if (stmt.type === "DESCRIBE") return [`DESCRIBE APP${stmt.appId}\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\uFF09`];
|
|
22755
|
-
if (stmt.type === "EXPLAIN")
|
|
22889
|
+
if (stmt.type === "EXPLAIN") {
|
|
22890
|
+
return buildPlanForBatchQuery(
|
|
22891
|
+
stmt.query,
|
|
22892
|
+
info,
|
|
22893
|
+
capabilities,
|
|
22894
|
+
orderPlans,
|
|
22895
|
+
collector
|
|
22896
|
+
);
|
|
22897
|
+
}
|
|
22756
22898
|
if (stmt.type === "ASSERT") {
|
|
22757
22899
|
const lines = [
|
|
22758
22900
|
`ASSERT ${stmt.text}`,
|
|
@@ -22764,14 +22906,20 @@ function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, dmlMaxRow
|
|
|
22764
22906
|
subqueries.forEach((sq, i) => {
|
|
22765
22907
|
lines.push(subqueries.length > 1 ? ` subquery[${i + 1}]:` : " subquery:");
|
|
22766
22908
|
const subInfo = hasTempTableRef(sq.query) ? info : { ...info, tempTablesReferenced: [] };
|
|
22767
|
-
lines.push(...buildPlanForBatchQuery(
|
|
22909
|
+
lines.push(...buildPlanForBatchQuery(
|
|
22910
|
+
sq.query,
|
|
22911
|
+
subInfo,
|
|
22912
|
+
capabilities,
|
|
22913
|
+
orderPlans,
|
|
22914
|
+
collector
|
|
22915
|
+
).map((l) => ` ${l}`));
|
|
22768
22916
|
});
|
|
22769
22917
|
return lines;
|
|
22770
22918
|
}
|
|
22771
22919
|
if (stmt.type === "UPDATE" && (stmt.applyBlocks?.length ?? 0) > 0) {
|
|
22772
22920
|
return buildExplainPlan(stmt, void 0, capabilities, orderPlans, dmlMaxRows, dmlMaxSubtableRows);
|
|
22773
22921
|
}
|
|
22774
|
-
return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans);
|
|
22922
|
+
return buildPlanForBatchQuery(stmt, info, capabilities, orderPlans, collector);
|
|
22775
22923
|
}
|
|
22776
22924
|
function hasTempTableRef(node) {
|
|
22777
22925
|
if (Array.isArray(node)) return node.some(hasTempTableRef);
|
|
@@ -22783,9 +22931,21 @@ function hasTempTableRef(node) {
|
|
|
22783
22931
|
}
|
|
22784
22932
|
return false;
|
|
22785
22933
|
}
|
|
22786
|
-
function buildPlanForBatchQuery(query, info, capabilities, orderPlans) {
|
|
22934
|
+
function buildPlanForBatchQuery(query, info, capabilities, orderPlans, collector = { sources: [] }, sourceRole = "main") {
|
|
22787
22935
|
if (info.tempTablesReferenced.length === 0) {
|
|
22788
|
-
return buildExplainPlan(
|
|
22936
|
+
return buildExplainPlan(
|
|
22937
|
+
query,
|
|
22938
|
+
void 0,
|
|
22939
|
+
capabilities,
|
|
22940
|
+
orderPlans,
|
|
22941
|
+
100,
|
|
22942
|
+
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
22943
|
+
1e4,
|
|
22944
|
+
void 0,
|
|
22945
|
+
true,
|
|
22946
|
+
collector,
|
|
22947
|
+
sourceRole
|
|
22948
|
+
);
|
|
22789
22949
|
}
|
|
22790
22950
|
const lines = [];
|
|
22791
22951
|
if (query.type === "INSERT_SELECT") {
|
|
@@ -22819,8 +22979,9 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
|
|
|
22819
22979
|
maxRecords,
|
|
22820
22980
|
sharedPlan
|
|
22821
22981
|
);
|
|
22982
|
+
const fetchCollector = { sources: [] };
|
|
22822
22983
|
const relativeLines = relativeDateExplainLines(sharedPlan);
|
|
22823
|
-
const
|
|
22984
|
+
const planLines = sharedPlan.hasServerOnlyWhereFunction && !sharedPlan.allowed ? [...explainMetadataLines(analysis), ...relativeLines] : [
|
|
22824
22985
|
...explainMetadataLines(analysis),
|
|
22825
22986
|
...relativeLines,
|
|
22826
22987
|
...addCursorConcurrency(
|
|
@@ -22832,17 +22993,28 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
|
|
|
22832
22993
|
dmlMaxRows,
|
|
22833
22994
|
dmlMaxSubtableRows,
|
|
22834
22995
|
maxRecords,
|
|
22835
|
-
analysis.plainGroupByPlans
|
|
22996
|
+
analysis.plainGroupByPlans,
|
|
22997
|
+
true,
|
|
22998
|
+
fetchCollector
|
|
22836
22999
|
),
|
|
22837
23000
|
cursorMaxActive
|
|
22838
23001
|
)
|
|
22839
23002
|
];
|
|
22840
|
-
|
|
23003
|
+
const lines = addFetchSummary(planLines, fetchCollector.sources);
|
|
23004
|
+
const result = {
|
|
22841
23005
|
type: "SELECT",
|
|
22842
23006
|
columns: ["plan"],
|
|
22843
23007
|
rows: lines.map((line) => ({ plan: line })),
|
|
22844
23008
|
rowCount: lines.length
|
|
22845
23009
|
};
|
|
23010
|
+
setExplainFetchPlan(result, {
|
|
23011
|
+
statements: [{
|
|
23012
|
+
index: 0,
|
|
23013
|
+
fetch: worstExplainFetch(fetchCollector.sources),
|
|
23014
|
+
sources: fetchCollector.sources
|
|
23015
|
+
}]
|
|
23016
|
+
});
|
|
23017
|
+
return result;
|
|
22846
23018
|
}
|
|
22847
23019
|
function addCursorConcurrency(lines, cursorMaxActive) {
|
|
22848
23020
|
const result = [];
|
|
@@ -22855,9 +23027,28 @@ function addCursorConcurrency(lines, cursorMaxActive) {
|
|
|
22855
23027
|
}
|
|
22856
23028
|
return result;
|
|
22857
23029
|
}
|
|
22858
|
-
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans) {
|
|
22859
|
-
|
|
22860
|
-
if (query.type === "
|
|
23030
|
+
function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4, plainGroupByPlans, includeFetchSummary = true, collector, sourceRole = "main") {
|
|
23031
|
+
const fetchCollector = collector ?? { sources: [] };
|
|
23032
|
+
if (query.type === "UNION") {
|
|
23033
|
+
const lines2 = buildUnionPlan(
|
|
23034
|
+
query,
|
|
23035
|
+
capabilities,
|
|
23036
|
+
orderPlans,
|
|
23037
|
+
plainGroupByPlans,
|
|
23038
|
+
fetchCollector
|
|
23039
|
+
);
|
|
23040
|
+
return includeFetchSummary ? addFetchSummary(lines2, fetchCollector.sources) : lines2;
|
|
23041
|
+
}
|
|
23042
|
+
if (query.type === "WITH") {
|
|
23043
|
+
const lines2 = buildWithPlan(
|
|
23044
|
+
query,
|
|
23045
|
+
capabilities,
|
|
23046
|
+
orderPlans,
|
|
23047
|
+
plainGroupByPlans,
|
|
23048
|
+
fetchCollector
|
|
23049
|
+
);
|
|
23050
|
+
return includeFetchSummary ? addFetchSummary(lines2, fetchCollector.sources) : lines2;
|
|
23051
|
+
}
|
|
22861
23052
|
if (query.type === "INSERT") return buildInsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
|
|
22862
23053
|
if (query.type === "INSERT_SELECT") return buildInsertSelectPlan(query, label, capabilities, orderPlans, plainGroupByPlans);
|
|
22863
23054
|
if (query.type === "UPSERT") return buildUpsertPlan(query, label, dmlMaxRows, dmlMaxSubtableRows);
|
|
@@ -22947,7 +23138,62 @@ function buildExplainPlan(query, label, capabilities, orderPlans, dmlMaxRows = 1
|
|
|
22947
23138
|
` duplicateKey: preflight before lookup/write (requires load)`
|
|
22948
23139
|
];
|
|
22949
23140
|
}
|
|
22950
|
-
|
|
23141
|
+
const lines = buildSelectPlan(
|
|
23142
|
+
query,
|
|
23143
|
+
label,
|
|
23144
|
+
capabilities,
|
|
23145
|
+
orderPlans,
|
|
23146
|
+
plainGroupByPlans,
|
|
23147
|
+
true,
|
|
23148
|
+
true,
|
|
23149
|
+
fetchCollector,
|
|
23150
|
+
sourceRole
|
|
23151
|
+
);
|
|
23152
|
+
return includeFetchSummary ? addFetchSummary(lines, fetchCollector.sources) : lines;
|
|
23153
|
+
}
|
|
23154
|
+
var EXPLAIN_FETCH_VALUE_RANK = {
|
|
23155
|
+
none: 0,
|
|
23156
|
+
exact: 1,
|
|
23157
|
+
prefiltered: 2,
|
|
23158
|
+
all: 3
|
|
23159
|
+
};
|
|
23160
|
+
function worstExplainFetch(sources) {
|
|
23161
|
+
return sources.reduce(
|
|
23162
|
+
(worst, source) => EXPLAIN_FETCH_VALUE_RANK[worst] >= EXPLAIN_FETCH_VALUE_RANK[source.fetch] ? worst : source.fetch,
|
|
23163
|
+
"none"
|
|
23164
|
+
);
|
|
23165
|
+
}
|
|
23166
|
+
function addFetchSummary(lines, sources) {
|
|
23167
|
+
const detailLines = lines.filter((line) => !line.startsWith("fetch summary:"));
|
|
23168
|
+
if (sources.length === 0) return detailLines;
|
|
23169
|
+
return [`fetch summary: ${worstExplainFetch(sources).toUpperCase()}`, ...detailLines];
|
|
23170
|
+
}
|
|
23171
|
+
function pushedQueryLimit(query) {
|
|
23172
|
+
const match = /(?:^|\s)limit\s+(\d+)(?:\s|$)/i.exec(query);
|
|
23173
|
+
return match ? Number(match[1]) : null;
|
|
23174
|
+
}
|
|
23175
|
+
function createExplainFetchSource(collector, app, alias, role, scope, query, pending = false) {
|
|
23176
|
+
const source = {
|
|
23177
|
+
app,
|
|
23178
|
+
alias,
|
|
23179
|
+
role,
|
|
23180
|
+
fetch: scope.toLowerCase(),
|
|
23181
|
+
pending,
|
|
23182
|
+
kintoneQuery: query === "(\u5168\u4EF6\u53D6\u5F97)" || query === "(\u306A\u3057)" || query === "" ? null : query,
|
|
23183
|
+
limit: pushedQueryLimit(query)
|
|
23184
|
+
};
|
|
23185
|
+
collector.sources.push(source);
|
|
23186
|
+
return source;
|
|
23187
|
+
}
|
|
23188
|
+
function formatFetchScope(source) {
|
|
23189
|
+
return [
|
|
23190
|
+
source.fetch.toUpperCase(),
|
|
23191
|
+
...source.limit === null ? [] : [`(limit ${source.limit})`],
|
|
23192
|
+
...source.pending ? ["(\u672A\u78BA\u5B9A)"] : []
|
|
23193
|
+
].join(" ");
|
|
23194
|
+
}
|
|
23195
|
+
function renderFetchScope(source) {
|
|
23196
|
+
return ` fetch: ${formatFetchScope(source)}`;
|
|
22951
23197
|
}
|
|
22952
23198
|
function buildValidatePlan(stmt, label) {
|
|
22953
23199
|
const info = validateExplainInfo.get(stmt);
|
|
@@ -22974,7 +23220,7 @@ function buildValidatePlan(stmt, label) {
|
|
|
22974
23220
|
lines.push(" records/mutation API during EXPLAIN: none; violation count unavailable");
|
|
22975
23221
|
return lines;
|
|
22976
23222
|
}
|
|
22977
|
-
function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans, allowTotalCountPlan = true) {
|
|
23223
|
+
function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlans, allowTotalCountPlan = true, emitFetch = true, collector = { sources: [] }, sourceRole = "main") {
|
|
22978
23224
|
const whereCapability = capabilities?.get(stmt) ?? (capabilities ? [...capabilities].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
22979
23225
|
const orderPlan = orderPlans?.get(stmt) ?? (orderPlans ? [...orderPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
22980
23226
|
const plainGroupByPlan = plainGroupByPlans?.get(stmt) ?? (plainGroupByPlans ? [...plainGroupByPlans].find(([candidate]) => JSON.stringify(candidate) === JSON.stringify(stmt))?.[1] : void 0);
|
|
@@ -23032,6 +23278,17 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23032
23278
|
lines.push(
|
|
23033
23279
|
` kintone query: ${baseQuery}${baseQuery ? " " : ""}limit 1`
|
|
23034
23280
|
);
|
|
23281
|
+
if (emitFetch) {
|
|
23282
|
+
const source = createExplainFetchSource(
|
|
23283
|
+
collector,
|
|
23284
|
+
stmt.from.appId,
|
|
23285
|
+
stmt.from.alias,
|
|
23286
|
+
sourceRole,
|
|
23287
|
+
"NONE",
|
|
23288
|
+
`${baseQuery}${baseQuery ? " " : ""}limit 1`
|
|
23289
|
+
);
|
|
23290
|
+
lines.push(renderFetchScope(source));
|
|
23291
|
+
}
|
|
23035
23292
|
lines.push(" fields: $id");
|
|
23036
23293
|
lines.push(" fetch API: GET records.json (totalCount=true)");
|
|
23037
23294
|
lines.push(" REST execution: single GET");
|
|
@@ -23078,6 +23335,17 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23078
23335
|
lines.push(` app: APP${stmt.from.appId} (${stmt.from.appId})`);
|
|
23079
23336
|
const displayedQuery = orderPlan?.kind === "KORDER_CURSOR" ? buildKorderCursorQuery(stmt) : params.query;
|
|
23080
23337
|
lines.push(` kintone query: ${displayedQuery || "(\u306A\u3057)"}`);
|
|
23338
|
+
if (emitFetch && stmt.from.cteName === null) {
|
|
23339
|
+
const fetchScope = displayedQuery ? "EXACT" : "ALL";
|
|
23340
|
+
lines.push(renderFetchScope(createExplainFetchSource(
|
|
23341
|
+
collector,
|
|
23342
|
+
stmt.from.appId,
|
|
23343
|
+
stmt.from.alias,
|
|
23344
|
+
sourceRole,
|
|
23345
|
+
fetchScope,
|
|
23346
|
+
displayedQuery
|
|
23347
|
+
)));
|
|
23348
|
+
}
|
|
23081
23349
|
lines.push(` fields: ${params.fields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : params.fields.join(", ")}`);
|
|
23082
23350
|
} else {
|
|
23083
23351
|
const runtimeJoinPlan = explainJoinPushdownPlans.get(stmt);
|
|
@@ -23127,6 +23395,19 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23127
23395
|
const mainFunctionConsumption = runtimeJoinPlan?.joinPlan.serverFunctionConsumptions.find(
|
|
23128
23396
|
(consumption) => consumption.targetAlias === stmt.from.alias
|
|
23129
23397
|
);
|
|
23398
|
+
if (emitFetch && stmt.from.cteName === null) {
|
|
23399
|
+
const mainPending = !runtimeJoinPlan && mainCandidate !== null;
|
|
23400
|
+
const mainFetchScope = mainQ === "(\u5168\u4EF6\u53D6\u5F97)" ? "ALL" : mainPending ? "PREFILTERED" : mainJoinItem?.relation === "exact" || mainFunctionConsumption || exactOriginalWhere !== "" ? "EXACT" : "PREFILTERED";
|
|
23401
|
+
lines.push(renderFetchScope(createExplainFetchSource(
|
|
23402
|
+
collector,
|
|
23403
|
+
stmt.from.appId,
|
|
23404
|
+
stmt.from.alias,
|
|
23405
|
+
sourceRole,
|
|
23406
|
+
mainFetchScope,
|
|
23407
|
+
mainQ,
|
|
23408
|
+
mainPending
|
|
23409
|
+
)));
|
|
23410
|
+
}
|
|
23130
23411
|
if (mainJoinItem || mainFunctionConsumption) {
|
|
23131
23412
|
lines.push(` pushdown applied: ${mainBoundQuery}`);
|
|
23132
23413
|
lines.push(` relation: ${mainJoinItem?.relation ?? "exact"}`);
|
|
@@ -23150,6 +23431,19 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23150
23431
|
const joinFunctionConsumption = runtimeJoinPlan?.joinPlan.serverFunctionConsumptions.find(
|
|
23151
23432
|
(consumption) => consumption.targetAlias === join2.table.alias
|
|
23152
23433
|
);
|
|
23434
|
+
if (emitFetch && join2.table.cteName === null) {
|
|
23435
|
+
const joinPending = !runtimeJoinPlan && joinCandidate !== null;
|
|
23436
|
+
const joinFetchScope = joinQ === "(\u5168\u4EF6\u53D6\u5F97)" ? "ALL" : joinPending ? "PREFILTERED" : joinPlanItem?.relation === "exact" || joinFunctionConsumption ? "EXACT" : "PREFILTERED";
|
|
23437
|
+
lines.push(renderFetchScope(createExplainFetchSource(
|
|
23438
|
+
collector,
|
|
23439
|
+
join2.table.appId,
|
|
23440
|
+
join2.table.alias,
|
|
23441
|
+
"join",
|
|
23442
|
+
joinFetchScope,
|
|
23443
|
+
joinQ,
|
|
23444
|
+
joinPending
|
|
23445
|
+
)));
|
|
23446
|
+
}
|
|
23153
23447
|
if (joinPlanItem || joinFunctionConsumption) {
|
|
23154
23448
|
lines.push(` pushdown applied: ${joinBoundQuery}`);
|
|
23155
23449
|
lines.push(` relation: ${joinPlanItem?.relation ?? "exact"}`);
|
|
@@ -23159,10 +23453,16 @@ function buildSelectPlan(stmt, label, capabilities, orderPlans, plainGroupByPlan
|
|
|
23159
23453
|
lines.push(` fields: ${joinFields.length === 0 ? "(\u5168\u30D5\u30A3\u30FC\u30EB\u30C9)" : joinFields.join(", ")}`);
|
|
23160
23454
|
}
|
|
23161
23455
|
}
|
|
23162
|
-
lines.push(...collectSubqueryPlans(
|
|
23456
|
+
lines.push(...collectSubqueryPlans(
|
|
23457
|
+
stmt,
|
|
23458
|
+
capabilities,
|
|
23459
|
+
orderPlans,
|
|
23460
|
+
plainGroupByPlans,
|
|
23461
|
+
collector
|
|
23462
|
+
));
|
|
23163
23463
|
return lines;
|
|
23164
23464
|
}
|
|
23165
|
-
function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
23465
|
+
function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
|
|
23166
23466
|
const selects = [];
|
|
23167
23467
|
const collect = (u) => {
|
|
23168
23468
|
if (u.type === "SELECT") {
|
|
@@ -23176,15 +23476,35 @@ function buildUnionPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
|
23176
23476
|
const lines = [];
|
|
23177
23477
|
selects.forEach((sel, i) => {
|
|
23178
23478
|
if (i > 0) lines.push("");
|
|
23179
|
-
lines.push(...buildSelectPlan(
|
|
23479
|
+
lines.push(...buildSelectPlan(
|
|
23480
|
+
sel,
|
|
23481
|
+
`[union:${i + 1}]`,
|
|
23482
|
+
capabilities,
|
|
23483
|
+
orderPlans,
|
|
23484
|
+
plainGroupByPlans,
|
|
23485
|
+
true,
|
|
23486
|
+
true,
|
|
23487
|
+
collector,
|
|
23488
|
+
"union"
|
|
23489
|
+
));
|
|
23180
23490
|
});
|
|
23181
23491
|
return lines;
|
|
23182
23492
|
}
|
|
23183
|
-
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
23493
|
+
function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
|
|
23184
23494
|
const lines = [];
|
|
23185
23495
|
for (const cte of stmt.ctes) {
|
|
23186
23496
|
if (cte.query.type === "SELECT") {
|
|
23187
|
-
lines.push(...buildSelectPlan(
|
|
23497
|
+
lines.push(...buildSelectPlan(
|
|
23498
|
+
cte.query,
|
|
23499
|
+
`[cte: ${cte.name}]`,
|
|
23500
|
+
capabilities,
|
|
23501
|
+
orderPlans,
|
|
23502
|
+
plainGroupByPlans,
|
|
23503
|
+
false,
|
|
23504
|
+
true,
|
|
23505
|
+
collector,
|
|
23506
|
+
"cte"
|
|
23507
|
+
));
|
|
23188
23508
|
lines.push("");
|
|
23189
23509
|
}
|
|
23190
23510
|
}
|
|
@@ -23197,13 +23517,25 @@ function buildWithPlan(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
|
23197
23517
|
100,
|
|
23198
23518
|
DEFAULT_APPLY_MAX_SUBTABLE_ROWS,
|
|
23199
23519
|
1e4,
|
|
23200
|
-
plainGroupByPlans
|
|
23520
|
+
plainGroupByPlans,
|
|
23521
|
+
false,
|
|
23522
|
+
collector
|
|
23201
23523
|
));
|
|
23202
23524
|
}
|
|
23203
23525
|
if (canInlineSingleCte(stmt)) {
|
|
23204
23526
|
lines.push("");
|
|
23205
23527
|
const inlined = buildInlinedQuery(stmt);
|
|
23206
|
-
lines.push(...buildSelectPlan(
|
|
23528
|
+
lines.push(...buildSelectPlan(
|
|
23529
|
+
inlined,
|
|
23530
|
+
"[effective: inlined CTE]",
|
|
23531
|
+
capabilities,
|
|
23532
|
+
orderPlans,
|
|
23533
|
+
plainGroupByPlans,
|
|
23534
|
+
false,
|
|
23535
|
+
true,
|
|
23536
|
+
collector,
|
|
23537
|
+
"cte"
|
|
23538
|
+
));
|
|
23207
23539
|
}
|
|
23208
23540
|
return lines;
|
|
23209
23541
|
}
|
|
@@ -23236,7 +23568,7 @@ function collectFullScanReasons(stmt) {
|
|
|
23236
23568
|
r.push("ORDER BY \u306B\u5F0F");
|
|
23237
23569
|
return r;
|
|
23238
23570
|
}
|
|
23239
|
-
function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans) {
|
|
23571
|
+
function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans, collector = { sources: [] }) {
|
|
23240
23572
|
const lines = [];
|
|
23241
23573
|
let idx = 1;
|
|
23242
23574
|
const visitWhere = (w) => {
|
|
@@ -23245,16 +23577,16 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans)
|
|
|
23245
23577
|
case "BINARY":
|
|
23246
23578
|
if (w.right.type === "SCALAR_SUBQUERY") {
|
|
23247
23579
|
lines.push("");
|
|
23248
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
|
|
23580
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
|
|
23249
23581
|
}
|
|
23250
23582
|
if (w.right.type === "SUBQUERY_IN_LIST") {
|
|
23251
23583
|
lines.push("");
|
|
23252
|
-
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
|
|
23584
|
+
lines.push(...buildSelectPlan(w.right.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
|
|
23253
23585
|
}
|
|
23254
23586
|
break;
|
|
23255
23587
|
case "EXISTS":
|
|
23256
23588
|
lines.push("");
|
|
23257
|
-
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
|
|
23589
|
+
lines.push(...buildSelectPlan(w.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
|
|
23258
23590
|
break;
|
|
23259
23591
|
case "LOGICAL":
|
|
23260
23592
|
visitWhere(w.left);
|
|
@@ -23274,7 +23606,7 @@ function collectSubqueryPlans(stmt, capabilities, orderPlans, plainGroupByPlans)
|
|
|
23274
23606
|
for (const col of stmt.columns) {
|
|
23275
23607
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
23276
23608
|
lines.push("");
|
|
23277
|
-
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false));
|
|
23609
|
+
lines.push(...buildSelectPlan(col.query, `[subquery:${idx++}]`, capabilities, orderPlans, plainGroupByPlans, false, true, collector, "subquery"));
|
|
23278
23610
|
}
|
|
23279
23611
|
}
|
|
23280
23612
|
if (stmt.having) visitWhere(stmt.having);
|
|
@@ -23300,7 +23632,15 @@ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroup
|
|
|
23300
23632
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
23301
23633
|
lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
|
|
23302
23634
|
lines.push("");
|
|
23303
|
-
lines.push(...buildSelectPlan(
|
|
23635
|
+
lines.push(...buildSelectPlan(
|
|
23636
|
+
stmt.select,
|
|
23637
|
+
"[source SELECT]",
|
|
23638
|
+
capabilities,
|
|
23639
|
+
orderPlans,
|
|
23640
|
+
plainGroupByPlans,
|
|
23641
|
+
false,
|
|
23642
|
+
false
|
|
23643
|
+
));
|
|
23304
23644
|
return lines;
|
|
23305
23645
|
}
|
|
23306
23646
|
function buildUpdatePlan(stmt, label, capabilities, orderPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, maxRecords = 1e4) {
|
|
@@ -23347,7 +23687,15 @@ function buildUpdatePlan(stmt, label, capabilities, orderPlans, dmlMaxRows = 100
|
|
|
23347
23687
|
for (const a of stmt.assignments) {
|
|
23348
23688
|
if (a.value.type === "SCALAR_SUBQUERY") {
|
|
23349
23689
|
lines.push("");
|
|
23350
|
-
lines.push(...buildSelectPlan(
|
|
23690
|
+
lines.push(...buildSelectPlan(
|
|
23691
|
+
a.value.query,
|
|
23692
|
+
`[subquery: ${a.field}]`,
|
|
23693
|
+
capabilities,
|
|
23694
|
+
orderPlans,
|
|
23695
|
+
void 0,
|
|
23696
|
+
false,
|
|
23697
|
+
false
|
|
23698
|
+
));
|
|
23351
23699
|
}
|
|
23352
23700
|
}
|
|
23353
23701
|
return lines;
|
|
@@ -23464,7 +23812,15 @@ function buildUpsertSelectPlan(stmt, label, capabilities, orderPlans, plainGroup
|
|
|
23464
23812
|
` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
|
|
23465
23813
|
``
|
|
23466
23814
|
];
|
|
23467
|
-
lines.push(...buildSelectPlan(
|
|
23815
|
+
lines.push(...buildSelectPlan(
|
|
23816
|
+
stmt.select,
|
|
23817
|
+
"[source SELECT]",
|
|
23818
|
+
capabilities,
|
|
23819
|
+
orderPlans,
|
|
23820
|
+
plainGroupByPlans,
|
|
23821
|
+
false,
|
|
23822
|
+
false
|
|
23823
|
+
));
|
|
23468
23824
|
return lines;
|
|
23469
23825
|
}
|
|
23470
23826
|
function buildReorderPlan(stmt, label) {
|
|
@@ -25374,13 +25730,17 @@ function restoreSqlDiagnosticValue(value, bindings, options = {}) {
|
|
|
25374
25730
|
return `${dmlTarget[1]}${target}`;
|
|
25375
25731
|
}
|
|
25376
25732
|
}
|
|
25377
|
-
|
|
25378
|
-
|
|
25379
|
-
|
|
25733
|
+
if (bindings.size === 0) return value;
|
|
25734
|
+
const mappedIds = [...bindings.keys()].sort((a, b) => String(b).length - String(a).length);
|
|
25735
|
+
const internalApp = new RegExp(
|
|
25736
|
+
`APP(${mappedIds.join("|")})(?!\\d)(\\s+AS\\s+[^\\s()]+)?(?:\\s+\\(\\1\\))?`,
|
|
25737
|
+
"g"
|
|
25738
|
+
);
|
|
25739
|
+
return value.replace(internalApp, (_match, mappedIdText, alias) => {
|
|
25740
|
+
const binding = bindings.get(Number(mappedIdText));
|
|
25380
25741
|
const display = binding.source === "logical" ? displayMode === "physical" ? `LAPP_${binding.logicalName} -> APP${binding.appId}` : `LAPP_${binding.logicalName}@${binding.profile}` : displayMode === "physical" ? `APP${binding.appId}` : `APP${binding.appId}@${binding.profile}`;
|
|
25381
|
-
|
|
25382
|
-
}
|
|
25383
|
-
return restored;
|
|
25742
|
+
return `${display}${alias ?? ""}`;
|
|
25743
|
+
});
|
|
25384
25744
|
}
|
|
25385
25745
|
if (Array.isArray(value)) {
|
|
25386
25746
|
return value.map((item) => restoreSqlDiagnosticValue(item, bindings, options));
|