@rex0220/kintone-sql-tools 3.68.0 → 3.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist-cli/ksql.js +318 -59
- package/dist-engine/index.cjs +16 -16
- package/dist-engine/index.mjs +16 -16
- package/dist-engine/ksql-engine.umd.js +16 -16
- package/dist-engine/meta/bundle-baseline.json +10 -10
- package/dist-engine/meta/cjs.json +100 -43
- package/dist-engine/meta/esm.json +100 -43
- package/dist-engine/meta/umd.json +100 -43
- package/dist-flow/flow-library/errors.d.ts +6 -0
- package/dist-flow/flow-library/index.d.ts +12 -0
- package/dist-flow/flow-library/publicTypes.d.ts +225 -0
- package/dist-flow/flow-library/writableClient.d.ts +2 -0
- package/dist-flow/index.cjs +18 -0
- package/dist-flow/index.mjs +18 -0
- package/dist-flow/meta/cjs.json +2333 -0
- package/dist-flow/meta/esm.json +2343 -0
- package/dist-flow/types/ast.d.ts +881 -0
- package/dist-mcp/ksql-mcp.js +674 -157
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -259,6 +259,44 @@ Options:
|
|
|
259
259
|
6. Windows で `ksql --help` 実行時にエディタが開いてしまう
|
|
260
260
|
- `.js` 関連付けの影響の可能性があります。`ksql.cmd --help` または `node dist-cli/ksql.js --help` で確認してください。
|
|
261
261
|
|
|
262
|
+
## 公式 API(プログラムから使う)
|
|
263
|
+
|
|
264
|
+
npm パッケージは 2 つのサブパスを **semver 対象の公開 API** として提供します。
|
|
265
|
+
ここに載る export のシグネチャ・挙動の互換性は semver(破壊的変更=メジャー、追加=マイナー)で管理します。
|
|
266
|
+
|
|
267
|
+
| サブパス | 用途 | 主な export |
|
|
268
|
+
|---|---|---|
|
|
269
|
+
| `@rex0220/kintone-sql-tools/engine` | **read-only** のクエリ実行(ダッシュボード等)。書込 API は構造的に遮断 | `runQuery` / `runBatch` / `explainQuery` / `createReadonlyKintoneClient` / `KsqlEngineError` / `version` |
|
|
270
|
+
| `@rex0220/kintone-sql-tools/flow` | **Flow dialect 1**(→ [言語リファレンス §27](docs/ksql_language_reference.md))のスクリプト解析・検証・**文単位実行**(バッチランナー向け・書込可能) | `parseScript` / `validateScript` / `explainScript` / `createExecutionContext` / `executeStatement` / `disposeExecutionContext` / `createKintoneClient` / `version` |
|
|
271
|
+
|
|
272
|
+
`/flow` の典型的な使い方(1 文ずつ実行して結果で継続判断する):
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
import { parseScript, createExecutionContext, executeStatement, disposeExecutionContext, createKintoneClient } from "@rex0220/kintone-sql-tools/flow";
|
|
276
|
+
|
|
277
|
+
const client = createKintoneClient({ baseUrl, auth: { type: "apiToken", apiToken } });
|
|
278
|
+
const { statements, meta, diagnostics } = parseScript(source, { apps: { 受注: 100 } });
|
|
279
|
+
const ctx = createExecutionContext({ client, script: source, apps: { 受注: 100, 顧客マスタ: 200 }, asOf: new Date("2026-08-01T00:00:00+09:00"), timezone: "Asia/Tokyo" });
|
|
280
|
+
try {
|
|
281
|
+
for (const stmt of statements) {
|
|
282
|
+
const result = await executeStatement(stmt, ctx);
|
|
283
|
+
// result で ASSERT 違反 / EXIT 成立 / skipped を判別して継続を判断する
|
|
284
|
+
}
|
|
285
|
+
} finally {
|
|
286
|
+
await disposeExecutionContext(ctx);
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### エンジンバージョン × dialect 対応表
|
|
291
|
+
|
|
292
|
+
| エンジン | dialect 0(既定・宣言なし) | dialect 1(`-- @ksql dialect: 1`) |
|
|
293
|
+
|---|---|---|
|
|
294
|
+
| 〜 v3.67.0 | ✅ | —(未実装) |
|
|
295
|
+
| v3.68.0 | ✅ | 解析のみ(エンジン内部 API。実行できる出荷面なし・実験的) |
|
|
296
|
+
| v3.69.0 〜 | ✅ | ✅ CLI / MCP / プラグイン / `/flow` で実行可 |
|
|
297
|
+
|
|
298
|
+
dialect は後方互換で管理します: dialect 0 のスクリプトはどのエンジン版でも挙動不変・破壊的変更は dialect 番号の繰り上げでのみ導入します。変更履歴は [CHANGELOG.md](CHANGELOG.md) を参照してください。
|
|
299
|
+
|
|
262
300
|
## 機密情報の取り扱い
|
|
263
301
|
|
|
264
302
|
- token / password は直書きせず、環境変数または `env:` 参照を推奨します。
|
package/dist-cli/ksql.js
CHANGED
|
@@ -677,6 +677,75 @@ function resolveGroupingSpec(stmt, resolve2) {
|
|
|
677
677
|
};
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
// src/core/asOfClock.ts
|
|
681
|
+
var AS_OF_FUNCTION_NAMES = [
|
|
682
|
+
"NOW",
|
|
683
|
+
"TODAY",
|
|
684
|
+
"MONTH_START",
|
|
685
|
+
"NEXT_MONTH_START"
|
|
686
|
+
];
|
|
687
|
+
var AS_OF_VARIABLE_PREFIX = "\0as-of:";
|
|
688
|
+
function asOfVariableName(name) {
|
|
689
|
+
return `${AS_OF_VARIABLE_PREFIX}${name}`;
|
|
690
|
+
}
|
|
691
|
+
function asOfFunctionNameFromVariable(name) {
|
|
692
|
+
if (!name.startsWith(AS_OF_VARIABLE_PREFIX)) return null;
|
|
693
|
+
const candidate = name.slice(AS_OF_VARIABLE_PREFIX.length);
|
|
694
|
+
return isAsOfFunctionName(candidate) ? candidate : null;
|
|
695
|
+
}
|
|
696
|
+
function isAsOfFunctionName(name) {
|
|
697
|
+
return AS_OF_FUNCTION_NAMES.includes(name);
|
|
698
|
+
}
|
|
699
|
+
function createAsOfClock(asOf = /* @__PURE__ */ new Date(), timezone) {
|
|
700
|
+
if (!(asOf instanceof Date) || !Number.isFinite(asOf.getTime())) {
|
|
701
|
+
throw new Error("ArgumentError: asOf must be a valid Date.");
|
|
702
|
+
}
|
|
703
|
+
let formatter;
|
|
704
|
+
try {
|
|
705
|
+
formatter = new Intl.DateTimeFormat("en-CA", {
|
|
706
|
+
...timezone === void 0 ? {} : { timeZone: timezone },
|
|
707
|
+
year: "numeric",
|
|
708
|
+
month: "2-digit",
|
|
709
|
+
day: "2-digit"
|
|
710
|
+
});
|
|
711
|
+
formatter.format(asOf);
|
|
712
|
+
} catch {
|
|
713
|
+
throw new Error(`ArgumentError: invalid IANA timezone: ${timezone ?? ""}.`);
|
|
714
|
+
}
|
|
715
|
+
const parts = formatter.formatToParts(asOf);
|
|
716
|
+
const year = partNumber(parts, "year");
|
|
717
|
+
const month = partNumber(parts, "month");
|
|
718
|
+
const day = partNumber(parts, "day");
|
|
719
|
+
const today = `${pad4(year)}-${pad2(month)}-${pad2(day)}`;
|
|
720
|
+
const monthStart = `${pad4(year)}-${pad2(month)}-01`;
|
|
721
|
+
const nextYear = month === 12 ? year + 1 : year;
|
|
722
|
+
const nextMonth = month === 12 ? 1 : month + 1;
|
|
723
|
+
return {
|
|
724
|
+
asOf: new Date(asOf.getTime()),
|
|
725
|
+
...timezone === void 0 ? {} : { timezone },
|
|
726
|
+
values: {
|
|
727
|
+
NOW: asOf.toISOString(),
|
|
728
|
+
TODAY: today,
|
|
729
|
+
MONTH_START: monthStart,
|
|
730
|
+
NEXT_MONTH_START: `${pad4(nextYear)}-${pad2(nextMonth)}-01`
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function partNumber(parts, type) {
|
|
735
|
+
const value = parts.find((part) => part.type === type)?.value;
|
|
736
|
+
const parsed = Number(value);
|
|
737
|
+
if (!Number.isInteger(parsed)) {
|
|
738
|
+
throw new Error(`InternalError: Intl.DateTimeFormat did not return ${type}.`);
|
|
739
|
+
}
|
|
740
|
+
return parsed;
|
|
741
|
+
}
|
|
742
|
+
function pad2(value) {
|
|
743
|
+
return String(value).padStart(2, "0");
|
|
744
|
+
}
|
|
745
|
+
function pad4(value) {
|
|
746
|
+
return String(value).padStart(4, "0");
|
|
747
|
+
}
|
|
748
|
+
|
|
680
749
|
// src/core/aggregateExpression.ts
|
|
681
750
|
function quote(value) {
|
|
682
751
|
return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -1095,6 +1164,19 @@ var Parser = class {
|
|
|
1095
1164
|
this.activeCteDefinition = null;
|
|
1096
1165
|
this.provisionalRecursiveCte = null;
|
|
1097
1166
|
this.allowSelectArithVariable = false;
|
|
1167
|
+
if (capabilities.dialect1) {
|
|
1168
|
+
for (let index = 0; index + 1 < tokens.length; index++) {
|
|
1169
|
+
const token = tokens[index];
|
|
1170
|
+
if (token.kind !== "VARIABLE" /* VARIABLE */ || tokens[index + 1].kind !== "(" /* LPAREN */) continue;
|
|
1171
|
+
const name = token.value.slice(1).toUpperCase();
|
|
1172
|
+
if (!isAsOfFunctionName(name)) {
|
|
1173
|
+
throw new ParseError(
|
|
1174
|
+
`\u4F7F\u7528\u53EF\u80FD\u306A as-of \u95A2\u6570\u306F ${AS_OF_FUNCTION_NAMES.map((item) => `@${item}`).join("/")} \u3067\u3059`,
|
|
1175
|
+
token
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1098
1180
|
}
|
|
1099
1181
|
// ----------------------------------------------------------
|
|
1100
1182
|
// 公開 API
|
|
@@ -1264,6 +1346,10 @@ var Parser = class {
|
|
|
1264
1346
|
parseScalarExpr(context, allowScalarSubquery) {
|
|
1265
1347
|
const tok = this.peek();
|
|
1266
1348
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
1349
|
+
if (this.peekAt(1).kind === "(" /* LPAREN */ && this.capabilities.dialect1) {
|
|
1350
|
+
this.advance();
|
|
1351
|
+
return this.finishVariableReference(tok);
|
|
1352
|
+
}
|
|
1267
1353
|
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u4ED6\u306E\u5909\u6570\u3092\u53C2\u7167\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
1268
1354
|
}
|
|
1269
1355
|
if (tok.kind === "NULL" /* NULL */) {
|
|
@@ -1803,12 +1889,28 @@ var Parser = class {
|
|
|
1803
1889
|
throw new ParseError("\u3053\u306E\u69CB\u6587\u306B\u306F -- @ksql dialect: 1 \u306E\u5BA3\u8A00\u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
1804
1890
|
}
|
|
1805
1891
|
}
|
|
1892
|
+
/** VARIABLE + `()` is the dialect-1 as-of call syntax; a bare VARIABLE stays unchanged. */
|
|
1893
|
+
finishVariableReference(tok) {
|
|
1894
|
+
const ordinary = { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
1895
|
+
if (this.peek().kind !== "(" /* LPAREN */) return ordinary;
|
|
1896
|
+
if (!this.capabilities.dialect1) return ordinary;
|
|
1897
|
+
const name = tok.value.slice(1).toUpperCase();
|
|
1898
|
+
if (!isAsOfFunctionName(name)) {
|
|
1899
|
+
throw new ParseError(
|
|
1900
|
+
`\u4F7F\u7528\u53EF\u80FD\u306A as-of \u95A2\u6570\u306F ${AS_OF_FUNCTION_NAMES.map((item) => `@${item}`).join("/")} \u3067\u3059`,
|
|
1901
|
+
tok
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
this.advance();
|
|
1905
|
+
this.expect(")" /* RPAREN */, `@${name} \u306F\u5F15\u6570\u306A\u3057\u306E () \u3067\u547C\u3073\u51FA\u3057\u3066\u304F\u3060\u3055\u3044`);
|
|
1906
|
+
return { type: "VARIABLE", name: asOfVariableName(name) };
|
|
1907
|
+
}
|
|
1806
1908
|
/** ASSERT のオペランド: 文字列 / スカラーサブクエリ / 数値算術式 */
|
|
1807
1909
|
parseAssertOperand() {
|
|
1808
1910
|
const tok = this.peek();
|
|
1809
1911
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
1810
1912
|
this.advance();
|
|
1811
|
-
return
|
|
1913
|
+
return this.finishVariableReference(tok);
|
|
1812
1914
|
}
|
|
1813
1915
|
if (tok.kind === "STRING" /* STRING */) {
|
|
1814
1916
|
this.advance();
|
|
@@ -2182,7 +2284,7 @@ var Parser = class {
|
|
|
2182
2284
|
}
|
|
2183
2285
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
2184
2286
|
this.advance();
|
|
2185
|
-
args.push(
|
|
2287
|
+
args.push(this.finishVariableReference(tok));
|
|
2186
2288
|
continue;
|
|
2187
2289
|
}
|
|
2188
2290
|
let sign = "";
|
|
@@ -2267,15 +2369,21 @@ var Parser = class {
|
|
|
2267
2369
|
return this.withAliasDisplay({ type: "SCALAR_VALUE_COL", expr, alias: parsedAlias2?.alias ?? null }, parsedAlias2);
|
|
2268
2370
|
}
|
|
2269
2371
|
if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
|
|
2270
|
-
const variable = this.advance();
|
|
2271
|
-
|
|
2272
|
-
|
|
2372
|
+
const variable = this.finishVariableReference(this.advance());
|
|
2373
|
+
const asOfFunction = asOfFunctionNameFromVariable(variable.name);
|
|
2374
|
+
let parsedAlias2 = null;
|
|
2375
|
+
if (asOfFunction === null) {
|
|
2376
|
+
if (!this.consume("AS" /* AS */)) {
|
|
2377
|
+
throw new ParseError("SELECT \u5217\u306E\u30D0\u30C3\u30C1\u5909\u6570\u306B\u306F AS alias \u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
2378
|
+
}
|
|
2379
|
+
parsedAlias2 = this.parseAliasName();
|
|
2380
|
+
} else if (this.consume("AS" /* AS */)) {
|
|
2381
|
+
parsedAlias2 = this.parseAliasName();
|
|
2273
2382
|
}
|
|
2274
|
-
const parsedAlias2 = this.parseAliasName();
|
|
2275
2383
|
return this.withAliasDisplay({
|
|
2276
2384
|
type: "VARIABLE_COL",
|
|
2277
|
-
name: variable.
|
|
2278
|
-
alias: parsedAlias2
|
|
2385
|
+
name: variable.name,
|
|
2386
|
+
alias: parsedAlias2?.alias ?? null
|
|
2279
2387
|
}, parsedAlias2);
|
|
2280
2388
|
}
|
|
2281
2389
|
const windowFunc = this.tryWindowFunc();
|
|
@@ -2611,7 +2719,7 @@ var Parser = class {
|
|
|
2611
2719
|
}
|
|
2612
2720
|
if (this.peek().kind === "VARIABLE" /* VARIABLE */) {
|
|
2613
2721
|
const tok = this.advance();
|
|
2614
|
-
return
|
|
2722
|
+
return this.finishVariableReference(tok);
|
|
2615
2723
|
}
|
|
2616
2724
|
const aggFunc = this.tryAggregateFunc();
|
|
2617
2725
|
if (aggFunc !== null) {
|
|
@@ -2771,7 +2879,7 @@ var Parser = class {
|
|
|
2771
2879
|
}
|
|
2772
2880
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
2773
2881
|
this.advance();
|
|
2774
|
-
return
|
|
2882
|
+
return this.finishVariableReference(tok);
|
|
2775
2883
|
}
|
|
2776
2884
|
if (tok.kind === "CASE" /* CASE */) {
|
|
2777
2885
|
if (!allowCase) throw new ParseError("\u3053\u306E\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
@@ -2871,7 +2979,7 @@ var Parser = class {
|
|
|
2871
2979
|
}
|
|
2872
2980
|
if (this.allowSelectArithVariable && tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
2873
2981
|
this.advance();
|
|
2874
|
-
return
|
|
2982
|
+
return this.finishVariableReference(tok);
|
|
2875
2983
|
}
|
|
2876
2984
|
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
2877
2985
|
this.advance();
|
|
@@ -3479,7 +3587,7 @@ var Parser = class {
|
|
|
3479
3587
|
}
|
|
3480
3588
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
3481
3589
|
this.advance();
|
|
3482
|
-
return
|
|
3590
|
+
return this.finishVariableReference(tok);
|
|
3483
3591
|
}
|
|
3484
3592
|
throw new ParseError(
|
|
3485
3593
|
"KLIKE / NOT KLIKE \u306E\u53F3\u8FBA\u306B\u306F\u6587\u5B57\u5217\u30EA\u30C6\u30E9\u30EB\u307E\u305F\u306F\u30D0\u30C3\u30C1\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059",
|
|
@@ -3672,7 +3780,7 @@ var Parser = class {
|
|
|
3672
3780
|
const tok = this.peek();
|
|
3673
3781
|
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
3674
3782
|
this.advance();
|
|
3675
|
-
return
|
|
3783
|
+
return this.finishVariableReference(tok);
|
|
3676
3784
|
}
|
|
3677
3785
|
if (tok.kind === "STRING" /* STRING */) {
|
|
3678
3786
|
this.advance();
|
|
@@ -3728,6 +3836,9 @@ var Parser = class {
|
|
|
3728
3836
|
"VARIABLE" /* VARIABLE */,
|
|
3729
3837
|
"IN / NOT IN \u306E\u5F8C\u306B\u306F (\u5024\u30EA\u30B9\u30C8\u307E\u305F\u306F SELECT) \u304B\u914D\u5217\u5909\u6570\u304C\u5FC5\u8981\u3067\u3059"
|
|
3730
3838
|
);
|
|
3839
|
+
if (this.peek().kind === "(" /* LPAREN */ && this.capabilities.dialect1) {
|
|
3840
|
+
return { type: "IN_LIST", values: [this.finishVariableReference(variable)] };
|
|
3841
|
+
}
|
|
3731
3842
|
return { type: "VARIABLE_IN_LIST", name: variable.value.slice(1).toLowerCase() };
|
|
3732
3843
|
}
|
|
3733
3844
|
parseInListOrSubquery() {
|
|
@@ -3759,7 +3870,7 @@ var Parser = class {
|
|
|
3759
3870
|
const sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
|
|
3760
3871
|
values.push(makeNumberLiteral(`${sign}${number.value}`));
|
|
3761
3872
|
} else if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
3762
|
-
values.push(
|
|
3873
|
+
values.push(this.finishVariableReference(tok));
|
|
3763
3874
|
} else if (tok.kind === "LOGINUSER" /* LOGINUSER */) {
|
|
3764
3875
|
if (values.length > 0) {
|
|
3765
3876
|
throw new ParseError(mixedLoginUserMessage, tok);
|
|
@@ -9282,6 +9393,7 @@ function collectVariableRefs(node, refs, inWhere = false) {
|
|
|
9282
9393
|
const obj = node;
|
|
9283
9394
|
const type = obj["type"];
|
|
9284
9395
|
if ((type === "VARIABLE" || type === "VARIABLE_COL" || type === "VARIABLE_IN_LIST") && typeof obj["name"] === "string") {
|
|
9396
|
+
if (asOfFunctionNameFromVariable(obj["name"]) !== null) return;
|
|
9285
9397
|
refs.push({
|
|
9286
9398
|
name: obj["name"],
|
|
9287
9399
|
kind: type === "VARIABLE" ? "scalar" : type === "VARIABLE_COL" ? "select-column" : "array-in-list",
|
|
@@ -16465,7 +16577,14 @@ var DiagnosticCodes = {
|
|
|
16465
16577
|
HEADER_INVALID_DIALECT: "KSQL1006",
|
|
16466
16578
|
LOGICAL_APP_UNRESOLVED: "KSQL1101",
|
|
16467
16579
|
LEX_ERROR: "KSQL1201",
|
|
16468
|
-
PARSE_ERROR: "KSQL1202"
|
|
16580
|
+
PARSE_ERROR: "KSQL1202",
|
|
16581
|
+
DIALECT1_REQUIRED: "KSQL1203",
|
|
16582
|
+
UPDATE_KEY_COMPOSITE: "KSQL1301",
|
|
16583
|
+
UPDATE_KEY_FIELD_TYPE: "KSQL1302",
|
|
16584
|
+
UPDATE_KEY_NOT_UNIQUE: "KSQL1303",
|
|
16585
|
+
SUBTABLE_DML_FORBIDDEN: "KSQL1304",
|
|
16586
|
+
BARE_INSERT_NOT_IDEMPOTENT: "KSQL1305",
|
|
16587
|
+
SERVER_TIME_FUNCTION_NOT_AS_OF: "KSQL1306"
|
|
16469
16588
|
};
|
|
16470
16589
|
function sourceLocationAt(source, offset) {
|
|
16471
16590
|
const target = Math.max(0, Math.min(offset, source.length));
|
|
@@ -16596,6 +16715,86 @@ function findLineEnd(source, start) {
|
|
|
16596
16715
|
return { contentEnd, next: i };
|
|
16597
16716
|
}
|
|
16598
16717
|
|
|
16718
|
+
// src/core/sql.ts
|
|
16719
|
+
function parseSqlStatements(sql, capabilities = {}) {
|
|
16720
|
+
const tokens = new Lexer(sql).tokenize();
|
|
16721
|
+
const statements = new Parser(tokens, capabilities).parseStatements();
|
|
16722
|
+
statements.forEach(validateStatementStatic);
|
|
16723
|
+
return statements;
|
|
16724
|
+
}
|
|
16725
|
+
function parseSqlStatementsForScript(sql, capabilities = {}) {
|
|
16726
|
+
const header = parseScriptHeader(sql);
|
|
16727
|
+
const headerError = header.diagnostics.find((diagnostic2) => diagnostic2.severity === "error");
|
|
16728
|
+
if (header.hasDirectives && headerError) {
|
|
16729
|
+
throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
|
|
16730
|
+
}
|
|
16731
|
+
const scriptSql = header.hasDirectives ? sql.slice(header.headerEnd) : sql;
|
|
16732
|
+
const scriptCapabilities = header.hasDirectives ? { ...capabilities, dialect1: header.meta.dialect === 1 } : capabilities;
|
|
16733
|
+
return {
|
|
16734
|
+
statements: parseSqlStatements(scriptSql, scriptCapabilities),
|
|
16735
|
+
meta: header.meta
|
|
16736
|
+
};
|
|
16737
|
+
}
|
|
16738
|
+
|
|
16739
|
+
// src/core/dialect1Validation.ts
|
|
16740
|
+
var DIALECT1_SERVER_TIME_FUNCTION_WARNING = "bare \u306E\u6642\u523B\u4F9D\u5B58\u95A2\u6570\u306F kintone \u30B5\u30FC\u30D0\u30FC\u8A55\u4FA1\u306E\u305F\u3081 as-of \u306E\u5BFE\u8C61\u5916\u3067\u3059\u3002\u518D\u73FE\u6027\u304C\u5FC5\u8981\u306A\u3089 @ \u4ED8\u304D\u95A2\u6570\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
|
|
16741
|
+
function validateDialect1UpdateKey(statement, fieldInfos) {
|
|
16742
|
+
if (fieldInfos === void 0) {
|
|
16743
|
+
return statement.keyFields.length === 1 ? [] : [{
|
|
16744
|
+
code: DiagnosticCodes.UPDATE_KEY_COMPOSITE,
|
|
16745
|
+
severity: "error",
|
|
16746
|
+
message: "dialect 1 \u306E UPSERT / MERGE \u306E\u30AD\u30FC\u306F\u5358\u4E00\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u8907\u5408\u30AD\u30FC\u306E\u4EE3\u308F\u308A\u306B\u3001\u9023\u7D50\u30AD\u30FC\u30D5\u30A3\u30FC\u30EB\u30C9\uFF08\u4F8B: \u9867\u5BA2\u30B3\u30FC\u30C9_\u5E74\u6708\uFF09\u3092\u30A2\u30D7\u30EA\u5074\u306B\u7528\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
16747
|
+
}];
|
|
16748
|
+
}
|
|
16749
|
+
if (statement.keyFields.length !== 1) return [];
|
|
16750
|
+
const key = statement.keyFields[0];
|
|
16751
|
+
const field = fieldInfos.find((candidate) => candidate.code === key);
|
|
16752
|
+
const issues = [];
|
|
16753
|
+
if (field === void 0 || field.fieldType !== "SINGLE_LINE_TEXT" && field.fieldType !== "NUMBER") {
|
|
16754
|
+
issues.push({
|
|
16755
|
+
code: DiagnosticCodes.UPDATE_KEY_FIELD_TYPE,
|
|
16756
|
+
severity: "error",
|
|
16757
|
+
message: field === void 0 ? `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u304C APP${statement.appId} \u306E\u30D5\u30A9\u30FC\u30E0\u306B\u5B58\u5728\u3057\u307E\u305B\u3093\u3002\u91CD\u8907\u7981\u6B62\u3092\u8A2D\u5B9A\u3057\u305F\u6587\u5B57\u5217\uFF081\u884C\uFF09\u307E\u305F\u306F\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30AD\u30FC\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002` : `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306E\u578B ${field.fieldType} \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u91CD\u8907\u7981\u6B62\u3092\u8A2D\u5B9A\u3057\u305F\u6587\u5B57\u5217\uFF081\u884C\uFF09\u307E\u305F\u306F\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30AD\u30FC\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
16758
|
+
});
|
|
16759
|
+
}
|
|
16760
|
+
if (field?.isUnique === false) {
|
|
16761
|
+
issues.push({
|
|
16762
|
+
code: DiagnosticCodes.UPDATE_KEY_NOT_UNIQUE,
|
|
16763
|
+
severity: "error",
|
|
16764
|
+
message: `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306F\u91CD\u8907\u7981\u6B62\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u30A2\u30D7\u30EA\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u8A2D\u5B9A\u3067\u300C\u5024\u306E\u91CD\u8907\u3092\u7981\u6B62\u3059\u308B\u300D\u3092\u6709\u52B9\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
16765
|
+
});
|
|
16766
|
+
} else if (field !== void 0 && field.isUnique === void 0) {
|
|
16767
|
+
issues.push({
|
|
16768
|
+
code: DiagnosticCodes.UPDATE_KEY_NOT_UNIQUE,
|
|
16769
|
+
severity: "warning",
|
|
16770
|
+
message: `UPSERT / MERGE \u306E\u30AD\u30FC\u300C${key}\u300D\u306E\u91CD\u8907\u7981\u6B62\u8A2D\u5B9A\u3092 schema resolver \u304B\u3089\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3002isUnique \u3092\u8FD4\u3059 resolver \u3092\u4F7F\u7528\u3057\u3001\u30A2\u30D7\u30EA\u5074\u3067\u300C\u5024\u306E\u91CD\u8907\u3092\u7981\u6B62\u3059\u308B\u300D\u304C\u6709\u52B9\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
16771
|
+
});
|
|
16772
|
+
}
|
|
16773
|
+
return issues;
|
|
16774
|
+
}
|
|
16775
|
+
function statementHasBareServerTimeFunctionInWhere(statement) {
|
|
16776
|
+
let found = false;
|
|
16777
|
+
const visit = (node) => {
|
|
16778
|
+
if (found || node === null || typeof node !== "object") return;
|
|
16779
|
+
if (Array.isArray(node)) {
|
|
16780
|
+
node.forEach(visit);
|
|
16781
|
+
return;
|
|
16782
|
+
}
|
|
16783
|
+
const value = node;
|
|
16784
|
+
const where = value["where"];
|
|
16785
|
+
if (where !== null && typeof where === "object") {
|
|
16786
|
+
const names = serverOnlyFunctionOccurrencesInWhere(where);
|
|
16787
|
+
if (names.some((name) => name === "TODAY" || name === "NOW" || isRelativeDateFunctionName(name))) {
|
|
16788
|
+
found = true;
|
|
16789
|
+
return;
|
|
16790
|
+
}
|
|
16791
|
+
}
|
|
16792
|
+
Object.values(value).forEach(visit);
|
|
16793
|
+
};
|
|
16794
|
+
visit(statement);
|
|
16795
|
+
return found;
|
|
16796
|
+
}
|
|
16797
|
+
|
|
16599
16798
|
// src/core/dmlPrevalidation.ts
|
|
16600
16799
|
function collectDmlPrevalidationSnapshotFields(fieldIndex) {
|
|
16601
16800
|
return [
|
|
@@ -18885,17 +19084,10 @@ var BatchTimeoutError = class extends Error {
|
|
|
18885
19084
|
}
|
|
18886
19085
|
};
|
|
18887
19086
|
async function executeBatch(sql, client, options = {}) {
|
|
19087
|
+
const asOfClock = createAsOfClock(options.asOf ?? /* @__PURE__ */ new Date(), options.timezone);
|
|
18888
19088
|
resolveRecursiveCteLimits(options);
|
|
18889
|
-
const
|
|
18890
|
-
const
|
|
18891
|
-
if (header.hasDirectives && headerError) {
|
|
18892
|
-
throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
|
|
18893
|
-
}
|
|
18894
|
-
const statements = parseSqlBatch(
|
|
18895
|
-
header.hasDirectives ? sql.slice(header.headerEnd) : sql,
|
|
18896
|
-
options.enableImport === true,
|
|
18897
|
-
header.hasDirectives && header.meta.dialect === 1
|
|
18898
|
-
);
|
|
19089
|
+
const { statements, meta } = parseSqlStatementsForScript(sql, { import: options.enableImport === true });
|
|
19090
|
+
const dialect1Warnings = meta.dialect === 1 && statements.some(statementHasBareServerTimeFunctionInWhere) ? [DIALECT1_SERVER_TIME_FUNCTION_WARNING] : [];
|
|
18899
19091
|
const analysis = analyzeBatch(statements);
|
|
18900
19092
|
statements.forEach((statement) => assertApplyExecutionScope("phase15b", statement));
|
|
18901
19093
|
if (options.allowApplyMutation !== true && statements.some(
|
|
@@ -18929,6 +19121,9 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
18929
19121
|
try {
|
|
18930
19122
|
const tempTables = /* @__PURE__ */ new Map();
|
|
18931
19123
|
const variables = /* @__PURE__ */ new Map();
|
|
19124
|
+
for (const [name, value] of Object.entries(asOfClock.values)) {
|
|
19125
|
+
variables.set(asOfVariableName(name), { type: "string", value });
|
|
19126
|
+
}
|
|
18932
19127
|
const results = [];
|
|
18933
19128
|
const failed = /* @__PURE__ */ new Set();
|
|
18934
19129
|
let aborted = null;
|
|
@@ -18985,7 +19180,8 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
18985
19180
|
tempTables,
|
|
18986
19181
|
variables,
|
|
18987
19182
|
relativeDateVariables,
|
|
18988
|
-
clock: statementEvaluationContext(boundOptions)
|
|
19183
|
+
clock: statementEvaluationContext(boundOptions),
|
|
19184
|
+
dialect: meta.dialect
|
|
18989
19185
|
};
|
|
18990
19186
|
const outcome = await runWithDeadline(
|
|
18991
19187
|
executeBatchStatement(statementContext),
|
|
@@ -18994,6 +19190,9 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
18994
19190
|
);
|
|
18995
19191
|
if (outcome.result) {
|
|
18996
19192
|
outcome.result = attachSearchAbortWarning(outcome.result, searchAbortCollector);
|
|
19193
|
+
if (dialect1Warnings.length > 0 && statementHasBareServerTimeFunctionInWhere(statements[i]) && outcome.result.type === "SELECT") {
|
|
19194
|
+
outcome.result = mergeSelectWarnings(outcome.result, dialect1Warnings);
|
|
19195
|
+
}
|
|
18997
19196
|
}
|
|
18998
19197
|
const { exitTriggered, ...statementOutcome } = outcome;
|
|
18999
19198
|
results.push({ ...base, status: "success", ...statementOutcome });
|
|
@@ -19023,7 +19222,8 @@ async function executeBatch(sql, client, options = {}) {
|
|
|
19023
19222
|
statementCount: statements.length,
|
|
19024
19223
|
statements: results,
|
|
19025
19224
|
analysis,
|
|
19026
|
-
metrics
|
|
19225
|
+
metrics,
|
|
19226
|
+
...dialect1Warnings.length > 0 ? { warnings: dialect1Warnings } : {}
|
|
19027
19227
|
};
|
|
19028
19228
|
} finally {
|
|
19029
19229
|
releaseMetadataCacheScope(cacheContext);
|
|
@@ -19045,7 +19245,8 @@ async function executeBatchStatement(context) {
|
|
|
19045
19245
|
tempTables,
|
|
19046
19246
|
variables,
|
|
19047
19247
|
relativeDateVariables,
|
|
19048
|
-
clock
|
|
19248
|
+
clock,
|
|
19249
|
+
dialect
|
|
19049
19250
|
} = context;
|
|
19050
19251
|
if (stmt.type === "SET_VARIABLE") {
|
|
19051
19252
|
const resolvedStmt2 = resolveBatchVariableReferences(stmt, variables);
|
|
@@ -19117,6 +19318,18 @@ async function executeBatchStatement(context) {
|
|
|
19117
19318
|
assertApplyScope("phase15b", resolvedStmt);
|
|
19118
19319
|
assertApplyExecutionScope("phase15b", resolvedStmt);
|
|
19119
19320
|
validateStatementStatic(resolvedStmt);
|
|
19321
|
+
if (dialect === 1 && (resolvedStmt.type === "INSERT" || resolvedStmt.type === "UPDATE" || resolvedStmt.type === "DELETE") && resolvedStmt.subtableCode) {
|
|
19322
|
+
throw new Error(
|
|
19323
|
+
"ArgumentError: dialect 1 \u3067\u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u4EEE\u60F3\u30C6\u30FC\u30D6\u30EB\u3078\u306E DML \u306F\u3067\u304D\u307E\u305B\u3093\u3002SELECT \u306F\u53EF\u80FD\u3067\u3059\u3002\u89AA\u30A2\u30D7\u30EA\u3092\u5BFE\u8C61\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
19324
|
+
);
|
|
19325
|
+
}
|
|
19326
|
+
if (dialect === 1 && (resolvedStmt.type === "UPSERT" || resolvedStmt.type === "UPSERT_SELECT")) {
|
|
19327
|
+
const staticIssue = validateDialect1UpdateKey(resolvedStmt)[0];
|
|
19328
|
+
if (staticIssue) throw new Error(`ArgumentError: ${staticIssue.message}`);
|
|
19329
|
+
const fieldInfos = await getFieldsCached(resolvedStmt.appId, client, cacheContext);
|
|
19330
|
+
const schemaIssue = validateDialect1UpdateKey(resolvedStmt, fieldInfos)[0];
|
|
19331
|
+
if (schemaIssue) throw new Error(`ArgumentError: ${schemaIssue.message}`);
|
|
19332
|
+
}
|
|
19120
19333
|
await assertRelativeDateExecutionPlan(resolvedStmt, client, cacheContext);
|
|
19121
19334
|
if (resolvedStmt.type === "VALIDATE") {
|
|
19122
19335
|
const result = await executeExistingRecordValidationCore(
|
|
@@ -19377,6 +19590,8 @@ function evaluateScalarExpr(expr, evaluationContext = {}) {
|
|
|
19377
19590
|
}
|
|
19378
19591
|
return { type: "number", value, raw: String(value) };
|
|
19379
19592
|
}
|
|
19593
|
+
case "VARIABLE":
|
|
19594
|
+
throw new Error(`InternalError: unresolved variable @${expr.name} reached scalar evaluation.`);
|
|
19380
19595
|
}
|
|
19381
19596
|
}
|
|
19382
19597
|
function resolveBatchVariableReferences(node, variables) {
|
|
@@ -19412,7 +19627,7 @@ function resolveBatchVariableReferencesInternal(node, variables, numericArithmet
|
|
|
19412
19627
|
raw: numericArithmeticOperand === "AGG_ARITH" ? `@${obj["name"]}` : value.raw ?? String(value.value)
|
|
19413
19628
|
} : { type: "STRING", value: value.value, fromVariable: true };
|
|
19414
19629
|
}
|
|
19415
|
-
if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && typeof obj["alias"] === "string") {
|
|
19630
|
+
if (obj["type"] === "VARIABLE_COL" && typeof obj["name"] === "string" && (typeof obj["alias"] === "string" || obj["alias"] === null)) {
|
|
19416
19631
|
const value = variables.get(obj["name"]);
|
|
19417
19632
|
if (value === void 0) throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
|
|
19418
19633
|
if (value.type === "array") throw new Error(`ParseError: array variable @${obj["name"]} cannot be used as a SELECT column.`);
|
|
@@ -26894,16 +27109,7 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
26894
27109
|
});
|
|
26895
27110
|
const invocationCacheContext = createInvocationCacheContext(cacheContext);
|
|
26896
27111
|
try {
|
|
26897
|
-
const
|
|
26898
|
-
const headerError = header.diagnostics.find((diagnostic2) => diagnostic2.severity === "error");
|
|
26899
|
-
if (header.hasDirectives && headerError) {
|
|
26900
|
-
throw new Error(`${headerError.code}: ${headerError.message} (${headerError.line}:${headerError.column})`);
|
|
26901
|
-
}
|
|
26902
|
-
const statements = parseSqlBatch(
|
|
26903
|
-
header.hasDirectives ? sql.slice(header.headerEnd) : sql,
|
|
26904
|
-
enableImport,
|
|
26905
|
-
header.hasDirectives && header.meta.dialect === 1
|
|
26906
|
-
);
|
|
27112
|
+
const { statements, meta } = parseSqlStatementsForScript(sql, { import: enableImport });
|
|
26907
27113
|
const analysis = analyzeBatch(statements);
|
|
26908
27114
|
const normalizedInjectedVariables = validateDeclaredBatchVariables(statements, injectedVariables);
|
|
26909
27115
|
const relativeDateVariables = prepareRelativeDateVariables(statements, normalizedInjectedVariables);
|
|
@@ -26984,10 +27190,16 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
26984
27190
|
), cursorMaxActive)
|
|
26985
27191
|
];
|
|
26986
27192
|
const metadataPlan = explainMetadataLines(whereAnalysis);
|
|
27193
|
+
const dialect1Estimate = meta.dialect === 1 ? buildDialect1ApiEstimateLines(
|
|
27194
|
+
planStmt,
|
|
27195
|
+
analysis.statements[i],
|
|
27196
|
+
maxRecords,
|
|
27197
|
+
dmlMaxRows
|
|
27198
|
+
) : [];
|
|
26987
27199
|
plans.push({
|
|
26988
27200
|
index: i,
|
|
26989
27201
|
type: analysis.statements[i].statementType,
|
|
26990
|
-
plan: statementPlan.length === 0 ? metadataPlan : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1)]
|
|
27202
|
+
plan: statementPlan.length === 0 ? [...metadataPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...dialect1Estimate]
|
|
26991
27203
|
});
|
|
26992
27204
|
fetchStatements.push({
|
|
26993
27205
|
index: i,
|
|
@@ -27012,6 +27224,63 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
27012
27224
|
releaseMetadataCacheScope(invocationCacheContext);
|
|
27013
27225
|
}
|
|
27014
27226
|
}
|
|
27227
|
+
function buildDialect1ApiEstimateLines(statement, analysis, maxRecords, dmlMaxRows) {
|
|
27228
|
+
const lines = [" estimated API consumption (dialect 1):"];
|
|
27229
|
+
const sources = collectPhysicalExplainSources(statement);
|
|
27230
|
+
if ((statement.type === "UPDATE" || statement.type === "DELETE") && !sources.includes(`APP${statement.appId}`)) {
|
|
27231
|
+
sources.unshift(`APP${statement.appId}`);
|
|
27232
|
+
}
|
|
27233
|
+
const maxReadRequests = Math.ceil(maxRecords / 500);
|
|
27234
|
+
for (const source of sources) {
|
|
27235
|
+
lines.push(
|
|
27236
|
+
` read ${source}: \u4E0D\u660E\uFF08\u4E0A\u9650 maxRecords=${maxRecords} \u3068\u4EEE\u5B9A: \u6700\u5927 ${maxReadRequests} \u56DE\u3001500 \u4EF6/\u56DE\uFF09`
|
|
27237
|
+
);
|
|
27238
|
+
}
|
|
27239
|
+
const metadataApps = [.../* @__PURE__ */ new Set([
|
|
27240
|
+
...analysis.appIds,
|
|
27241
|
+
...analysis.targetAppId === null ? [] : [analysis.targetAppId]
|
|
27242
|
+
])];
|
|
27243
|
+
lines.push(
|
|
27244
|
+
` metadata: GET form fields \xD7 ${metadataApps.length} \u30A2\u30D7\u30EA\uFF08\u30AD\u30E3\u30C3\u30B7\u30E5\u6E08\u307F\u306F\u8FFD\u52A0 0 \u56DE\uFF09`
|
|
27245
|
+
);
|
|
27246
|
+
if (statement.type === "UPSERT" || statement.type === "UPSERT_SELECT") {
|
|
27247
|
+
if (statement.type === "UPSERT") {
|
|
27248
|
+
lines.push(
|
|
27249
|
+
` UPSERT pre-read: ${Math.ceil(statement.values.length / UPSERT_IN_CHUNK_SIZE)} \u56DE\uFF08${statement.values.length} \u884C\u3001${UPSERT_IN_CHUNK_SIZE} \u30AD\u30FC/\u56DE\uFF09`
|
|
27250
|
+
);
|
|
27251
|
+
} else {
|
|
27252
|
+
lines.push(
|
|
27253
|
+
` UPSERT pre-read: \u4E0D\u660E\uFF08\u4E0A\u9650 dmlMaxRows=${dmlMaxRows} \u3068\u4EEE\u5B9A: \u6700\u5927 ${Math.ceil(dmlMaxRows / UPSERT_IN_CHUNK_SIZE)} \u56DE\u3001${UPSERT_IN_CHUNK_SIZE} \u30AD\u30FC/\u56DE\uFF09`
|
|
27254
|
+
);
|
|
27255
|
+
}
|
|
27256
|
+
}
|
|
27257
|
+
const knownRows = statement.type === "INSERT" || statement.type === "UPSERT" ? statement.values.length : null;
|
|
27258
|
+
if (statement.type === "INSERT" || statement.type === "INSERT_SELECT" || statement.type === "UPSERT" || statement.type === "UPSERT_SELECT" || statement.type === "UPDATE" || statement.type === "DELETE") {
|
|
27259
|
+
lines.push(knownRows === null ? ` write: \u4E0D\u660E\uFF08\u4E0A\u9650 dmlMaxRows=${dmlMaxRows} \u3068\u4EEE\u5B9A: \u6700\u5927 ${Math.ceil(dmlMaxRows / 100)} \u56DE\u3001100 \u4EF6/HTTP \u30EA\u30AF\u30A8\u30B9\u30C8\uFF09` : ` write: ${Math.ceil(knownRows / 100)} \u56DE\uFF08${knownRows} \u884C\u3001100 \u4EF6/HTTP \u30EA\u30AF\u30A8\u30B9\u30C8\uFF09`);
|
|
27260
|
+
lines.push(" reference: bulkRequest \u306F\u672A\u5B9F\u88C5\u3002\u66F8\u8FBC\u30B5\u30D6\u30EA\u30AF\u30A8\u30B9\u30C8\u6570\u306F HTTP \u66F8\u8FBC\u56DE\u6570\u3068\u540C\u3058");
|
|
27261
|
+
}
|
|
27262
|
+
return lines;
|
|
27263
|
+
}
|
|
27264
|
+
function collectPhysicalExplainSources(statement) {
|
|
27265
|
+
const sources = [];
|
|
27266
|
+
const visit = (node) => {
|
|
27267
|
+
if (Array.isArray(node)) {
|
|
27268
|
+
node.forEach(visit);
|
|
27269
|
+
return;
|
|
27270
|
+
}
|
|
27271
|
+
if (node === null || typeof node !== "object") return;
|
|
27272
|
+
const value = node;
|
|
27273
|
+
if (typeof value["appId"] === "number" && Object.prototype.hasOwnProperty.call(value, "alias") && Object.prototype.hasOwnProperty.call(value, "cteName") && value["cteName"] === null && value["appId"] > 0) {
|
|
27274
|
+
const app = `APP${value["appId"]}`;
|
|
27275
|
+
const subtable = typeof value["subtableCode"] === "string" ? `$${value["subtableCode"]}` : "";
|
|
27276
|
+
const alias = typeof value["alias"] === "string" && value["alias"] !== app ? ` AS ${value["alias"]}` : "";
|
|
27277
|
+
sources.push(`${app}${subtable}${alias}`);
|
|
27278
|
+
}
|
|
27279
|
+
Object.values(value).forEach(visit);
|
|
27280
|
+
};
|
|
27281
|
+
visit(statement);
|
|
27282
|
+
return sources;
|
|
27283
|
+
}
|
|
27015
27284
|
function buildBatchStatementPlan(stmt, info, capabilities, orderPlans, plainGroupByPlans, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, collector = { sources: [] }, tempSchemaLedger = /* @__PURE__ */ new Map(), createdSchema, explainContext = defaultRecursiveExplainContext()) {
|
|
27016
27285
|
if (stmt.type === "CREATE_TEMP_TABLE") {
|
|
27017
27286
|
return [
|
|
@@ -28491,20 +28760,6 @@ var OperationCancelledError = class extends Error {
|
|
|
28491
28760
|
}
|
|
28492
28761
|
};
|
|
28493
28762
|
|
|
28494
|
-
// src/core/sql.ts
|
|
28495
|
-
function parseSqlStatement(sql, capabilities = {}) {
|
|
28496
|
-
const tokens = new Lexer(sql).tokenize();
|
|
28497
|
-
const stmt = new Parser(tokens, capabilities).parse();
|
|
28498
|
-
validateStatementStatic(stmt);
|
|
28499
|
-
return stmt;
|
|
28500
|
-
}
|
|
28501
|
-
function parseSqlStatements(sql, capabilities = {}) {
|
|
28502
|
-
const tokens = new Lexer(sql).tokenize();
|
|
28503
|
-
const statements = new Parser(tokens, capabilities).parseStatements();
|
|
28504
|
-
statements.forEach(validateStatementStatic);
|
|
28505
|
-
return statements;
|
|
28506
|
-
}
|
|
28507
|
-
|
|
28508
28763
|
// src/core/displayFormat.ts
|
|
28509
28764
|
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
28510
28765
|
var DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
|
|
@@ -30217,7 +30472,7 @@ function toParseInput(sql) {
|
|
|
30217
30472
|
}
|
|
30218
30473
|
function tryParseStatements(sql) {
|
|
30219
30474
|
try {
|
|
30220
|
-
const stmts =
|
|
30475
|
+
const { statements: stmts } = parseSqlStatementsForScript(toParseInput(sql));
|
|
30221
30476
|
return {
|
|
30222
30477
|
kind: "ok",
|
|
30223
30478
|
count: stmts.length,
|
|
@@ -30232,7 +30487,11 @@ function tryParseStatements(sql) {
|
|
|
30232
30487
|
if (e instanceof ParseError) {
|
|
30233
30488
|
return { kind: "fail", continuable: e.token.kind === "EOF" /* EOF */, message: e.message };
|
|
30234
30489
|
}
|
|
30235
|
-
|
|
30490
|
+
return {
|
|
30491
|
+
kind: "fail",
|
|
30492
|
+
continuable: false,
|
|
30493
|
+
message: e instanceof Error ? e.message : String(e)
|
|
30494
|
+
};
|
|
30236
30495
|
}
|
|
30237
30496
|
}
|
|
30238
30497
|
|
|
@@ -31421,7 +31680,7 @@ async function confirmDmlInConsole(sql, opts, queue, defaultProfile = "dev", res
|
|
|
31421
31680
|
if (!opts.allowDml || opts.yes || opts.dryRun) return true;
|
|
31422
31681
|
try {
|
|
31423
31682
|
const normalized = normalizeSqlAppProfiles(sql, defaultProfile, resolutionContext);
|
|
31424
|
-
const statements =
|
|
31683
|
+
const { statements } = parseSqlStatementsForScript(normalized.normalizedSql);
|
|
31425
31684
|
if (statements.length > 1) {
|
|
31426
31685
|
const analysis = analyzeBatch(statements);
|
|
31427
31686
|
if (!analysis.containsDml) return true;
|
|
@@ -31871,7 +32130,7 @@ async function run() {
|
|
|
31871
32130
|
}
|
|
31872
32131
|
const importEnabled = Object.keys(args.importCsv).length > 0 || Object.keys(args.importJson).length > 0;
|
|
31873
32132
|
try {
|
|
31874
|
-
const statements =
|
|
32133
|
+
const { statements } = parseSqlStatementsForScript(sql, { import: importEnabled });
|
|
31875
32134
|
parsedStatements = statements;
|
|
31876
32135
|
const hasApply = (statement) => statement.type === "UPDATE" || statement.type === "INSERT" ? (statement.applyBlocks?.length ?? 0) > 0 : statement.type === "UPSERT" ? (statement.onInsertApplyBlocks?.length ?? 0) > 0 || (statement.onUpdateApplyBlocks?.length ?? 0) > 0 : false;
|
|
31877
32136
|
containsApplyStatement = statements.some(hasApply);
|
|
@@ -31892,7 +32151,7 @@ async function run() {
|
|
|
31892
32151
|
isBatchSql = true;
|
|
31893
32152
|
batchContainsDml = batchAnalysis.containsDml;
|
|
31894
32153
|
} else {
|
|
31895
|
-
const stmt =
|
|
32154
|
+
const stmt = statements[0];
|
|
31896
32155
|
parsedStmt = stmt;
|
|
31897
32156
|
stmtType = getStatementType(stmt);
|
|
31898
32157
|
isDmlStatement = writesKintone(stmt);
|