@rex0220/kintone-sql-tools 3.2.0 → 3.4.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 +5 -4
- package/dist-cli/ksql.js +1236 -215
- package/dist-mcp/ksql-mcp.js +1239 -218
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -31034,6 +31034,9 @@ var KEYWORDS = /* @__PURE__ */ new Map([
|
|
|
31034
31034
|
["SUBSTR", "SUBSTR" /* SUBSTR */],
|
|
31035
31035
|
["CONCAT", "CONCAT" /* CONCAT */],
|
|
31036
31036
|
["REPLACE", "REPLACE" /* REPLACE */],
|
|
31037
|
+
["REGEXP_LIKE", "REGEXP_LIKE" /* REGEXP_LIKE */],
|
|
31038
|
+
["REGEXP_REPLACE", "REGEXP_REPLACE" /* REGEXP_REPLACE */],
|
|
31039
|
+
["REGEXP_SUBSTR", "REGEXP_SUBSTR" /* REGEXP_SUBSTR */],
|
|
31037
31040
|
["COALESCE", "COALESCE" /* COALESCE */],
|
|
31038
31041
|
["NULLIF", "NULLIF" /* NULLIF */],
|
|
31039
31042
|
["ISNULL", "ISNULL" /* ISNULL */],
|
|
@@ -31166,7 +31169,7 @@ var Lexer = class {
|
|
|
31166
31169
|
);
|
|
31167
31170
|
}
|
|
31168
31171
|
// ----------------------------------------------------------
|
|
31169
|
-
// 数値:
|
|
31172
|
+
// 数値: digits[.digits][e[+-]digits](先頭/末尾 dot は受理しない)
|
|
31170
31173
|
// ----------------------------------------------------------
|
|
31171
31174
|
readNumber(start) {
|
|
31172
31175
|
while (this.pos < this.input.length && isDigit(this.input[this.pos])) {
|
|
@@ -31178,6 +31181,16 @@ var Lexer = class {
|
|
|
31178
31181
|
this.pos++;
|
|
31179
31182
|
}
|
|
31180
31183
|
}
|
|
31184
|
+
if (this.pos < this.input.length && (this.input[this.pos] === "e" || this.input[this.pos] === "E")) {
|
|
31185
|
+
this.pos++;
|
|
31186
|
+
if (this.pos < this.input.length && (this.input[this.pos] === "+" || this.input[this.pos] === "-")) {
|
|
31187
|
+
this.pos++;
|
|
31188
|
+
}
|
|
31189
|
+
if (this.pos >= this.input.length || !isDigit(this.input[this.pos])) {
|
|
31190
|
+
throw new LexError("\u6307\u6570\u90E8\u306B\u306F\u6570\u5B57\u304C\u5FC5\u8981\u3067\u3059", start, this.input, this.pos >= this.input.length);
|
|
31191
|
+
}
|
|
31192
|
+
while (this.pos < this.input.length && isDigit(this.input[this.pos])) this.pos++;
|
|
31193
|
+
}
|
|
31181
31194
|
return this.makeToken(
|
|
31182
31195
|
"NUMBER" /* NUMBER */,
|
|
31183
31196
|
this.input.slice(start, this.pos),
|
|
@@ -31206,6 +31219,10 @@ var Lexer = class {
|
|
|
31206
31219
|
this.pos += 2;
|
|
31207
31220
|
return this.makeToken("<=" /* LTE */, "<=", start);
|
|
31208
31221
|
}
|
|
31222
|
+
if (ch === "|" && ch2 === "|") {
|
|
31223
|
+
this.pos += 2;
|
|
31224
|
+
return this.makeToken("||" /* CONCAT_OP */, "||", start);
|
|
31225
|
+
}
|
|
31209
31226
|
switch (ch) {
|
|
31210
31227
|
case "=":
|
|
31211
31228
|
this.pos++;
|
|
@@ -31377,8 +31394,94 @@ function isJapanese(cp) {
|
|
|
31377
31394
|
return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65281 && cp <= 65376;
|
|
31378
31395
|
}
|
|
31379
31396
|
|
|
31397
|
+
// src/core/exactDecimal.ts
|
|
31398
|
+
var DECIMAL_PATTERN = /^([+-]?)(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([+-]?)(\d+))?$/;
|
|
31399
|
+
function parseSafeExponent(sign, digits) {
|
|
31400
|
+
if (digits === void 0) return 0;
|
|
31401
|
+
let value = 0;
|
|
31402
|
+
for (const digit of digits) {
|
|
31403
|
+
value = value * 10 + (digit.charCodeAt(0) - 48);
|
|
31404
|
+
if (!Number.isSafeInteger(value)) return null;
|
|
31405
|
+
}
|
|
31406
|
+
return sign === "-" ? -value : value;
|
|
31407
|
+
}
|
|
31408
|
+
function parseExactDecimal(input) {
|
|
31409
|
+
const match = DECIMAL_PATTERN.exec(input.trim());
|
|
31410
|
+
if (match === null) return null;
|
|
31411
|
+
const exponent = parseSafeExponent(match[5], match[6]);
|
|
31412
|
+
if (exponent === null) return null;
|
|
31413
|
+
const fraction = match[3] ?? match[4] ?? "";
|
|
31414
|
+
let coefficient = `${match[2] ?? ""}${fraction}`.replace(/^0+/, "");
|
|
31415
|
+
if (coefficient === "") return { sign: 0, coefficient: "0", scale: 0 };
|
|
31416
|
+
let scale = fraction.length - exponent;
|
|
31417
|
+
if (!Number.isSafeInteger(scale)) return null;
|
|
31418
|
+
const trailingZeros = /0+$/.exec(coefficient)?.[0].length ?? 0;
|
|
31419
|
+
if (trailingZeros > 0) {
|
|
31420
|
+
coefficient = coefficient.slice(0, -trailingZeros);
|
|
31421
|
+
scale -= trailingZeros;
|
|
31422
|
+
if (!Number.isSafeInteger(scale)) return null;
|
|
31423
|
+
}
|
|
31424
|
+
if (!Number.isSafeInteger(coefficient.length - scale)) return null;
|
|
31425
|
+
const sign = match[1] === "-" ? -1 : 1;
|
|
31426
|
+
return { sign, coefficient, scale };
|
|
31427
|
+
}
|
|
31428
|
+
function formatPlainDecimal(dec) {
|
|
31429
|
+
if (dec.sign === 0) return "0";
|
|
31430
|
+
const digits = dec.coefficient;
|
|
31431
|
+
let magnitude;
|
|
31432
|
+
if (dec.scale <= 0) {
|
|
31433
|
+
magnitude = `${digits}${"0".repeat(-dec.scale)}`;
|
|
31434
|
+
} else if (digits.length > dec.scale) {
|
|
31435
|
+
const point = digits.length - dec.scale;
|
|
31436
|
+
magnitude = `${digits.slice(0, point)}.${digits.slice(point)}`;
|
|
31437
|
+
} else {
|
|
31438
|
+
magnitude = `0.${"0".repeat(dec.scale - digits.length)}${digits}`;
|
|
31439
|
+
}
|
|
31440
|
+
return dec.sign === -1 ? `-${magnitude}` : magnitude;
|
|
31441
|
+
}
|
|
31442
|
+
function toPlainDecimal(input) {
|
|
31443
|
+
const dec = parseExactDecimal(input);
|
|
31444
|
+
return dec === null ? null : formatPlainDecimal(dec);
|
|
31445
|
+
}
|
|
31446
|
+
function compareMagnitudes(left, right) {
|
|
31447
|
+
const leftPoint = left.coefficient.length - left.scale;
|
|
31448
|
+
const rightPoint = right.coefficient.length - right.scale;
|
|
31449
|
+
if (!Number.isSafeInteger(leftPoint) || !Number.isSafeInteger(rightPoint)) {
|
|
31450
|
+
throw new Error("ArgumentError: exact decimal scale is outside the supported range.");
|
|
31451
|
+
}
|
|
31452
|
+
if (leftPoint !== rightPoint) return leftPoint < rightPoint ? -1 : 1;
|
|
31453
|
+
const width = Math.max(left.coefficient.length, right.coefficient.length);
|
|
31454
|
+
for (let index = 0; index < width; index++) {
|
|
31455
|
+
const a = index < left.coefficient.length ? left.coefficient.charCodeAt(index) : 48;
|
|
31456
|
+
const b = index < right.coefficient.length ? right.coefficient.charCodeAt(index) : 48;
|
|
31457
|
+
if (a !== b) return a < b ? -1 : 1;
|
|
31458
|
+
}
|
|
31459
|
+
return 0;
|
|
31460
|
+
}
|
|
31461
|
+
function compareExactDecimal(left, right) {
|
|
31462
|
+
if (left.sign !== right.sign) return left.sign < right.sign ? -1 : 1;
|
|
31463
|
+
if (left.sign === 0) return 0;
|
|
31464
|
+
const magnitude = compareMagnitudes(left, right);
|
|
31465
|
+
return left.sign === -1 ? magnitude === 0 ? 0 : magnitude === -1 ? 1 : -1 : magnitude;
|
|
31466
|
+
}
|
|
31467
|
+
function compareDecimal(left, right) {
|
|
31468
|
+
const a = parseExactDecimal(left);
|
|
31469
|
+
const b = parseExactDecimal(right);
|
|
31470
|
+
if (a === null || b === null) {
|
|
31471
|
+
throw new Error("ArgumentError: compareDecimal requires finite decimal inputs.");
|
|
31472
|
+
}
|
|
31473
|
+
return compareExactDecimal(a, b);
|
|
31474
|
+
}
|
|
31475
|
+
|
|
31380
31476
|
// src/types/ast.ts
|
|
31381
31477
|
var NO_FROM_CTE_NAME = "__NO_FROM__";
|
|
31478
|
+
function makeNumberLiteral(raw) {
|
|
31479
|
+
return { type: "NUMBER", value: Number(raw), raw };
|
|
31480
|
+
}
|
|
31481
|
+
function numberLiteralText(node) {
|
|
31482
|
+
const source = node.raw ?? String(node.value);
|
|
31483
|
+
return toPlainDecimal(source) ?? source;
|
|
31484
|
+
}
|
|
31382
31485
|
|
|
31383
31486
|
// src/parser/parser.ts
|
|
31384
31487
|
var MAX_BATCH_STATEMENTS = 20;
|
|
@@ -31411,6 +31514,9 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
|
|
|
31411
31514
|
"COALESCE" /* COALESCE */,
|
|
31412
31515
|
"NULLIF" /* NULLIF */,
|
|
31413
31516
|
"ISNULL" /* ISNULL */,
|
|
31517
|
+
"REGEXP_LIKE" /* REGEXP_LIKE */,
|
|
31518
|
+
"REGEXP_REPLACE" /* REGEXP_REPLACE */,
|
|
31519
|
+
"REGEXP_SUBSTR" /* REGEXP_SUBSTR */,
|
|
31414
31520
|
"LEFT" /* LEFT */,
|
|
31415
31521
|
"RIGHT" /* RIGHT */,
|
|
31416
31522
|
"INSTR" /* INSTR */,
|
|
@@ -31460,6 +31566,8 @@ var Parser = class {
|
|
|
31460
31566
|
constructor(tokens) {
|
|
31461
31567
|
this.tokens = tokens;
|
|
31462
31568
|
this.allowUnaryPlusNumber = false;
|
|
31569
|
+
this.scalarAllowsAggregateArgs = true;
|
|
31570
|
+
this.scalarAllowsCase = true;
|
|
31463
31571
|
this.pos = 0;
|
|
31464
31572
|
/** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
|
|
31465
31573
|
this.cteNames = /* @__PURE__ */ new Set();
|
|
@@ -31628,17 +31736,19 @@ var Parser = class {
|
|
|
31628
31736
|
}
|
|
31629
31737
|
rejectNonScalarExpr(node, tok, context) {
|
|
31630
31738
|
if (node.type === "STRING" || node.type === "NUMBER") return;
|
|
31631
|
-
if (node.type === "FIELD_REF" || node.type === "AGG_REF") {
|
|
31739
|
+
if (node.type === "FIELD_REF" || node.type === "FIELD" || node.type === "VARIABLE" || node.type === "AGG_REF") {
|
|
31632
31740
|
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u30FB\u96C6\u8A08\u95A2\u6570\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
31633
31741
|
}
|
|
31634
|
-
if (node.type === "ARITH" || node.type === "AGG_ARITH") {
|
|
31742
|
+
if (node.type === "ARITH" || node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP" || node.type === "AGG_ARITH") {
|
|
31635
31743
|
this.rejectNonScalarExpr(node.left, tok, context);
|
|
31636
31744
|
this.rejectNonScalarExpr(node.right, tok, context);
|
|
31637
31745
|
return;
|
|
31638
31746
|
}
|
|
31639
31747
|
if (node.type === "STRING_FUNC") {
|
|
31640
31748
|
for (const arg of node.args) this.rejectNonScalarExpr(arg, tok, context);
|
|
31749
|
+
return;
|
|
31641
31750
|
}
|
|
31751
|
+
throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
|
|
31642
31752
|
}
|
|
31643
31753
|
// ----------------------------------------------------------
|
|
31644
31754
|
// CREATE TEMP TABLE / DROP TEMP TABLE(バッチ内一時テーブル)
|
|
@@ -32009,6 +32119,11 @@ var Parser = class {
|
|
|
32009
32119
|
if (this.consume("*" /* STAR */)) {
|
|
32010
32120
|
return { type: "WILDCARD" };
|
|
32011
32121
|
}
|
|
32122
|
+
if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
32123
|
+
const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
32124
|
+
const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
|
|
32125
|
+
return { type: "SCALAR_VALUE_COL", expr, alias: alias2 };
|
|
32126
|
+
}
|
|
32012
32127
|
const windowFunc = this.tryWindowFunc();
|
|
32013
32128
|
if (windowFunc !== null) {
|
|
32014
32129
|
return this.parseWindowColumn(windowFunc);
|
|
@@ -32124,13 +32239,25 @@ var Parser = class {
|
|
|
32124
32239
|
}
|
|
32125
32240
|
selectColumnHasAggregate(column) {
|
|
32126
32241
|
if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
|
|
32127
|
-
if (column.type
|
|
32128
|
-
|
|
32242
|
+
if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
32243
|
+
if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
|
|
32244
|
+
return false;
|
|
32129
32245
|
}
|
|
32130
32246
|
stringFuncArgHasAggregate(arg) {
|
|
32131
32247
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
32132
|
-
|
|
32133
|
-
|
|
32248
|
+
return this.scalarValueHasAggregate(arg);
|
|
32249
|
+
}
|
|
32250
|
+
scalarValueHasAggregate(expr) {
|
|
32251
|
+
if (expr.type === "STRING_FUNC") return expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
|
|
32252
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
32253
|
+
return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
|
|
32254
|
+
}
|
|
32255
|
+
if (expr.type === "CASE_WHEN") {
|
|
32256
|
+
const results = [...expr.branches.map((b) => b.result), ...expr.elseResult ? [expr.elseResult] : []];
|
|
32257
|
+
return results.some((result) => {
|
|
32258
|
+
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
32259
|
+
return this.scalarValueHasAggregate(result);
|
|
32260
|
+
});
|
|
32134
32261
|
}
|
|
32135
32262
|
return false;
|
|
32136
32263
|
}
|
|
@@ -32174,12 +32301,12 @@ var Parser = class {
|
|
|
32174
32301
|
if (this.peek().kind === "-" /* MINUS */) {
|
|
32175
32302
|
this.advance();
|
|
32176
32303
|
const operand = this.parseAggPrimary();
|
|
32177
|
-
if (operand.type === "NUMBER") return {
|
|
32178
|
-
return { type: "AGG_ARITH", left:
|
|
32304
|
+
if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
|
|
32305
|
+
return { type: "AGG_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
|
|
32179
32306
|
}
|
|
32180
32307
|
if (this.peek().kind === "NUMBER" /* NUMBER */) {
|
|
32181
32308
|
const tok = this.advance();
|
|
32182
|
-
return
|
|
32309
|
+
return makeNumberLiteral(tok.value);
|
|
32183
32310
|
}
|
|
32184
32311
|
const aggFunc = this.tryAggregateFunc();
|
|
32185
32312
|
if (aggFunc !== null) {
|
|
@@ -32188,6 +32315,105 @@ var Parser = class {
|
|
|
32188
32315
|
throw new ParseError("\u96C6\u8A08\u7B97\u8853\u5F0F\u306B\u306F\u96C6\u8A08\u95A2\u6570\u307E\u305F\u306F\u6570\u5024\u304C\u5FC5\u8981\u3067\u3059", this.peek());
|
|
32189
32316
|
}
|
|
32190
32317
|
// ──────────────────────────────────────────────────
|
|
32318
|
+
// 汎用スカラー値式パーサー(B38)
|
|
32319
|
+
// ──────────────────────────────────────────────────
|
|
32320
|
+
/** 比較・述語・集約・サブクエリを含まない値式の公開入口。 */
|
|
32321
|
+
parseScalarValueExpr(options = {}) {
|
|
32322
|
+
const previousAggregateArgs = this.scalarAllowsAggregateArgs;
|
|
32323
|
+
const previousCase = this.scalarAllowsCase;
|
|
32324
|
+
this.scalarAllowsAggregateArgs = options.allowAggregateArgs === true;
|
|
32325
|
+
this.scalarAllowsCase = options.allowCase !== false;
|
|
32326
|
+
let expr;
|
|
32327
|
+
try {
|
|
32328
|
+
expr = this.parseScalarAddSubConcat(this.scalarAllowsCase);
|
|
32329
|
+
} finally {
|
|
32330
|
+
this.scalarAllowsAggregateArgs = previousAggregateArgs;
|
|
32331
|
+
this.scalarAllowsCase = previousCase;
|
|
32332
|
+
}
|
|
32333
|
+
const next = this.peek();
|
|
32334
|
+
if (next.kind === "IS" /* IS */ || next.kind === "=" /* EQ */ || next.kind === "!=" /* NEQ */ || next.kind === "<>" /* LT_GT */ || next.kind === ">" /* GT */ || next.kind === "<" /* LT */ || next.kind === ">=" /* GTE */ || next.kind === "<=" /* LTE */ || next.kind === "LIKE" /* LIKE */ || next.kind === "KLIKE" /* KLIKE */ || next.kind === "IN" /* IN */ || next.kind === "BETWEEN" /* BETWEEN */) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u6BD4\u8F03\u30FB\u8FF0\u8A9E\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", next);
|
|
32335
|
+
return expr;
|
|
32336
|
+
}
|
|
32337
|
+
parseScalarAddSubConcat(allowCase) {
|
|
32338
|
+
let left = this.parseScalarMulDiv(allowCase);
|
|
32339
|
+
while (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */ || this.peek().kind === "||" /* CONCAT_OP */) {
|
|
32340
|
+
const token = this.advance();
|
|
32341
|
+
const right = this.parseScalarMulDiv(allowCase);
|
|
32342
|
+
left = token.kind === "||" /* CONCAT_OP */ ? { type: "CONCAT_OP", left, right } : { type: "SCALAR_ARITH", left, op: token.kind === "+" /* PLUS */ ? "+" : "-", right };
|
|
32343
|
+
}
|
|
32344
|
+
return left;
|
|
32345
|
+
}
|
|
32346
|
+
parseScalarMulDiv(allowCase) {
|
|
32347
|
+
let left = this.parseScalarPrimary(allowCase);
|
|
32348
|
+
while (this.peek().kind === "*" /* STAR */ || this.peek().kind === "/" /* SLASH */ || this.peek().kind === "%" /* PERCENT */) {
|
|
32349
|
+
const token = this.advance();
|
|
32350
|
+
const op = token.kind === "*" /* STAR */ ? "*" : token.kind === "/" /* SLASH */ ? "/" : "%";
|
|
32351
|
+
left = { type: "SCALAR_ARITH", left, op, right: this.parseScalarPrimary(allowCase) };
|
|
32352
|
+
}
|
|
32353
|
+
return left;
|
|
32354
|
+
}
|
|
32355
|
+
parseScalarPrimary(allowCase) {
|
|
32356
|
+
const tok = this.peek();
|
|
32357
|
+
if (tok.kind === "(" /* LPAREN */) {
|
|
32358
|
+
if (this.peekAt(1).kind === "SELECT" /* SELECT */) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
32359
|
+
this.advance();
|
|
32360
|
+
const expr = this.parseScalarAddSubConcat(allowCase);
|
|
32361
|
+
this.expect(")" /* RPAREN */);
|
|
32362
|
+
return expr;
|
|
32363
|
+
}
|
|
32364
|
+
if (tok.kind === "+" /* PLUS */ || tok.kind === "-" /* MINUS */) {
|
|
32365
|
+
this.advance();
|
|
32366
|
+
if (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */) {
|
|
32367
|
+
throw new ParseError("\u5358\u9805\u7B26\u53F7\u3092\u91CD\u306D\u3066\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
32368
|
+
}
|
|
32369
|
+
const operand = this.parseScalarPrimary(allowCase);
|
|
32370
|
+
if (operand.type === "NUMBER") {
|
|
32371
|
+
return makeNumberLiteral(`${tok.kind === "-" /* MINUS */ ? "-" : "+"}${numberLiteralText(operand)}`);
|
|
32372
|
+
}
|
|
32373
|
+
if (tok.kind === "+" /* PLUS */) throw new ParseError("\u5358\u9805 + \u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
32374
|
+
return { type: "SCALAR_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
|
|
32375
|
+
}
|
|
32376
|
+
if (tok.kind === "STRING" /* STRING */) {
|
|
32377
|
+
this.advance();
|
|
32378
|
+
return { type: "STRING", value: tok.value };
|
|
32379
|
+
}
|
|
32380
|
+
if (tok.kind === "NUMBER" /* NUMBER */) {
|
|
32381
|
+
this.advance();
|
|
32382
|
+
return makeNumberLiteral(tok.value);
|
|
32383
|
+
}
|
|
32384
|
+
if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
32385
|
+
this.advance();
|
|
32386
|
+
return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
|
|
32387
|
+
}
|
|
32388
|
+
if (tok.kind === "CASE" /* CASE */) {
|
|
32389
|
+
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);
|
|
32390
|
+
return this.parseCaseWhenExpr();
|
|
32391
|
+
}
|
|
32392
|
+
if (this.tryAggregateFunc() !== null) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u96C6\u7D04\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
|
|
32393
|
+
if (this.tryStringFuncName() !== null) return this.parseStringFuncExpr();
|
|
32394
|
+
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
32395
|
+
this.advance();
|
|
32396
|
+
if (this.consume("." /* DOT */)) return { type: "FIELD", tableAlias: tok.value, field: this.parseIdentifier() };
|
|
32397
|
+
return { type: "FIELD", tableAlias: null, field: tok.value };
|
|
32398
|
+
}
|
|
32399
|
+
throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306E\u30AA\u30DA\u30E9\u30F3\u30C9\u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
32400
|
+
}
|
|
32401
|
+
/** 現在の値の終端までに指定トークンがあるか(括弧内も対象)。 */
|
|
32402
|
+
hasTopLevelTokenBeforeValueEnd(target) {
|
|
32403
|
+
let depth = 0;
|
|
32404
|
+
for (let i = this.pos; i < this.tokens.length; i++) {
|
|
32405
|
+
const kind = this.tokens[i].kind;
|
|
32406
|
+
if (kind === "(" /* LPAREN */ || kind === "[" /* LBRACKET */) depth++;
|
|
32407
|
+
else if (kind === ")" /* RPAREN */ || kind === "]" /* RBRACKET */) {
|
|
32408
|
+
if (depth === 0) break;
|
|
32409
|
+
depth--;
|
|
32410
|
+
}
|
|
32411
|
+
if (kind === target) return true;
|
|
32412
|
+
if (depth === 0 && (kind === "," /* COMMA */ || kind === "AS" /* AS */ || kind === "FROM" /* FROM */ || kind === "WHERE" /* WHERE */ || kind === "WHEN" /* WHEN */ || kind === "THEN" /* THEN */ || kind === "ELSE" /* ELSE */ || kind === "END" /* END */ || kind === ";" /* SEMICOLON */ || kind === "EOF" /* EOF */)) break;
|
|
32413
|
+
}
|
|
32414
|
+
return false;
|
|
32415
|
+
}
|
|
32416
|
+
// ──────────────────────────────────────────────────
|
|
32191
32417
|
// 算術式パーサー(演算子優先順位: * / > + -)
|
|
32192
32418
|
//
|
|
32193
32419
|
// parseArithAddSub : + -(左結合・低優先度)
|
|
@@ -32231,7 +32457,7 @@ var Parser = class {
|
|
|
32231
32457
|
if (this.allowUnaryPlusNumber && this.peek().kind === "+" /* PLUS */) {
|
|
32232
32458
|
this.advance();
|
|
32233
32459
|
const number4 = this.expect("NUMBER" /* NUMBER */, "\u5358\u9805 + \u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
32234
|
-
return {
|
|
32460
|
+
return makeNumberLiteral(`+${number4.value}`);
|
|
32235
32461
|
}
|
|
32236
32462
|
if (this.peek().kind === "-" /* MINUS */) {
|
|
32237
32463
|
this.advance();
|
|
@@ -32239,8 +32465,8 @@ var Parser = class {
|
|
|
32239
32465
|
throw new ParseError("\u5358\u9805\u7B26\u53F7\u3092\u91CD\u306D\u3066\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093", this.peek());
|
|
32240
32466
|
}
|
|
32241
32467
|
const operand = this.parseArithPrimary();
|
|
32242
|
-
if (operand.type === "NUMBER") return {
|
|
32243
|
-
return { type: "ARITH", left:
|
|
32468
|
+
if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
|
|
32469
|
+
return { type: "ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
|
|
32244
32470
|
}
|
|
32245
32471
|
if (this.tryStringFuncName() !== null) {
|
|
32246
32472
|
return this.parseStringFuncExpr();
|
|
@@ -32248,7 +32474,7 @@ var Parser = class {
|
|
|
32248
32474
|
const tok = this.peek();
|
|
32249
32475
|
if (tok.kind === "NUMBER" /* NUMBER */) {
|
|
32250
32476
|
this.advance();
|
|
32251
|
-
return
|
|
32477
|
+
return makeNumberLiteral(tok.value);
|
|
32252
32478
|
}
|
|
32253
32479
|
if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
|
|
32254
32480
|
this.advance();
|
|
@@ -32309,12 +32535,15 @@ var Parser = class {
|
|
|
32309
32535
|
this.expect("END" /* END */);
|
|
32310
32536
|
return { type: "CASE_WHEN", branches, elseResult };
|
|
32311
32537
|
}
|
|
32312
|
-
/** THEN / ELSE
|
|
32538
|
+
/** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
|
|
32313
32539
|
parseCaseResult() {
|
|
32314
32540
|
const tok = this.peek();
|
|
32315
32541
|
if (tok.kind === "[" /* LBRACKET */) {
|
|
32316
32542
|
return this.parseArrayLiteral();
|
|
32317
32543
|
}
|
|
32544
|
+
if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
32545
|
+
return this.parseScalarValueExpr({ allowAggregateArgs: true });
|
|
32546
|
+
}
|
|
32318
32547
|
if (tok.kind === "STRING" /* STRING */) {
|
|
32319
32548
|
this.advance();
|
|
32320
32549
|
return { type: "STRING", value: tok.value };
|
|
@@ -32352,6 +32581,9 @@ var Parser = class {
|
|
|
32352
32581
|
["SUBSTR" /* SUBSTR */]: "SUBSTRING",
|
|
32353
32582
|
["CONCAT" /* CONCAT */]: "CONCAT",
|
|
32354
32583
|
["REPLACE" /* REPLACE */]: "REPLACE",
|
|
32584
|
+
["REGEXP_LIKE" /* REGEXP_LIKE */]: "REGEXP_LIKE",
|
|
32585
|
+
["REGEXP_REPLACE" /* REGEXP_REPLACE */]: "REGEXP_REPLACE",
|
|
32586
|
+
["REGEXP_SUBSTR" /* REGEXP_SUBSTR */]: "REGEXP_SUBSTR",
|
|
32355
32587
|
["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
|
|
32356
32588
|
["COALESCE" /* COALESCE */]: "COALESCE",
|
|
32357
32589
|
["NULLIF" /* NULLIF */]: "NULLIF",
|
|
@@ -32459,25 +32691,19 @@ var Parser = class {
|
|
|
32459
32691
|
}
|
|
32460
32692
|
return { type: "STRING", value: normalized };
|
|
32461
32693
|
}
|
|
32462
|
-
/** 文字列関数の引数:
|
|
32694
|
+
/** 文字列関数の引数: ScalarValueExpr / 集計算術式 */
|
|
32463
32695
|
parseStringFuncArg() {
|
|
32464
|
-
|
|
32465
|
-
|
|
32466
|
-
|
|
32467
|
-
|
|
32468
|
-
|
|
32469
|
-
|
|
32470
|
-
|
|
32471
|
-
|
|
32472
|
-
|
|
32473
|
-
try {
|
|
32474
|
-
const left = this.parseAggPrimary();
|
|
32475
|
-
const expr = this.continueAggArith(left);
|
|
32476
|
-
if (this.hasAggregateOperand(expr)) return expr;
|
|
32477
|
-
} catch {
|
|
32696
|
+
if (this.scalarAllowsAggregateArgs) {
|
|
32697
|
+
const startPos = this.pos;
|
|
32698
|
+
try {
|
|
32699
|
+
const left = this.parseAggPrimary();
|
|
32700
|
+
const expr = this.continueAggArith(left);
|
|
32701
|
+
if (this.hasAggregateOperand(expr)) return expr;
|
|
32702
|
+
} catch {
|
|
32703
|
+
}
|
|
32704
|
+
this.pos = startPos;
|
|
32478
32705
|
}
|
|
32479
|
-
this.
|
|
32480
|
-
return this.parseArithAddSub();
|
|
32706
|
+
return this.parseScalarAddSubConcat(this.scalarAllowsCase);
|
|
32481
32707
|
}
|
|
32482
32708
|
hasAggregateOperand(node) {
|
|
32483
32709
|
if (node.type === "AGG_REF") return true;
|
|
@@ -32565,6 +32791,7 @@ var Parser = class {
|
|
|
32565
32791
|
const k = this.peek().kind;
|
|
32566
32792
|
if (k === "IDENT" /* IDENT */ || k === "BIDENT" /* BIDENT */) {
|
|
32567
32793
|
if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "VALIDATE" && this.peekAt(1).kind === "IDENT" /* IDENT */ && this.peekAt(1).value.toUpperCase() === "ONLY") return null;
|
|
32794
|
+
if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "CHECK" && this.peekAt(1).kind === "WHEN" /* WHEN */) return null;
|
|
32568
32795
|
return this.parseTableAliasName();
|
|
32569
32796
|
}
|
|
32570
32797
|
return null;
|
|
@@ -32891,7 +33118,7 @@ var Parser = class {
|
|
|
32891
33118
|
}
|
|
32892
33119
|
if (tok.kind === "NUMBER" /* NUMBER */ || tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */ || tok.kind === "(" /* LPAREN */ || tok.kind === "-" /* MINUS */ || this.tryStringFuncName() !== null) {
|
|
32893
33120
|
const expr = this.parseArithAddSub();
|
|
32894
|
-
if (expr.type === "NUMBER") return
|
|
33121
|
+
if (expr.type === "NUMBER") return expr;
|
|
32895
33122
|
return { type: "ARITH_VALUE", expr };
|
|
32896
33123
|
}
|
|
32897
33124
|
throw new ParseError(
|
|
@@ -32918,15 +33145,15 @@ var Parser = class {
|
|
|
32918
33145
|
if (tok.kind === "STRING" /* STRING */) {
|
|
32919
33146
|
values.push({ type: "STRING", value: tok.value });
|
|
32920
33147
|
} else if (tok.kind === "NUMBER" /* NUMBER */) {
|
|
32921
|
-
values.push(
|
|
33148
|
+
values.push(makeNumberLiteral(tok.value));
|
|
32922
33149
|
} else if (tok.kind === "-" /* MINUS */ || tok.kind === "+" /* PLUS */) {
|
|
32923
33150
|
const number4 = this.peek();
|
|
32924
33151
|
if (number4.kind !== "NUMBER" /* NUMBER */) {
|
|
32925
33152
|
throw new ParseError(invalidValueMessage, tok);
|
|
32926
33153
|
}
|
|
32927
33154
|
this.advance();
|
|
32928
|
-
const sign = tok.kind === "-" /* MINUS */ ? -
|
|
32929
|
-
values.push({
|
|
33155
|
+
const sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
|
|
33156
|
+
values.push(makeNumberLiteral(`${sign}${number4.value}`));
|
|
32930
33157
|
} else if (tok.kind === "VARIABLE" /* VARIABLE */) {
|
|
32931
33158
|
values.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
|
|
32932
33159
|
} else {
|
|
@@ -33030,8 +33257,9 @@ var Parser = class {
|
|
|
33030
33257
|
if (subtableCode) {
|
|
33031
33258
|
throw new ParseError("INSERT INTO ... SELECT \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u4EEE\u60F3\u30C6\u30FC\u30D6\u30EB\u3067\u306F\u672A\u5BFE\u5FDC\u3067\u3059", this.prev());
|
|
33032
33259
|
}
|
|
33260
|
+
const checkGroups2 = this.parseCheckGroups();
|
|
33033
33261
|
const validation2 = this.parseDmlControlSuffix();
|
|
33034
|
-
return { type: "INSERT_SELECT", appId, fields, select, ...validation2 };
|
|
33262
|
+
return { type: "INSERT_SELECT", appId, fields, select, ...checkGroups2, ...validation2 };
|
|
33035
33263
|
}
|
|
33036
33264
|
this.expect("VALUES" /* VALUES */);
|
|
33037
33265
|
const values = [];
|
|
@@ -33041,11 +33269,15 @@ var Parser = class {
|
|
|
33041
33269
|
this.expect(")" /* RPAREN */);
|
|
33042
33270
|
values.push(row);
|
|
33043
33271
|
} while (this.consume("," /* COMMA */));
|
|
33272
|
+
const checkGroups = this.parseCheckGroups();
|
|
33044
33273
|
const validation = this.parseDmlControlSuffix();
|
|
33274
|
+
if (subtableCode && checkGroups.checkGroups) {
|
|
33275
|
+
throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB INSERT \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
|
|
33276
|
+
}
|
|
33045
33277
|
if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
|
|
33046
33278
|
throw new ParseError("VALIDATE ONLY / ON ERROR SKIP \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB INSERT \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
|
|
33047
33279
|
}
|
|
33048
|
-
return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...validation } : { type: "INSERT", appId, fields, values, ...validation };
|
|
33280
|
+
return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...checkGroups, ...validation } : { type: "INSERT", appId, fields, values, ...checkGroups, ...validation };
|
|
33049
33281
|
}
|
|
33050
33282
|
parseUpsert() {
|
|
33051
33283
|
this.expect("UPSERT" /* UPSERT */);
|
|
@@ -33062,8 +33294,9 @@ var Parser = class {
|
|
|
33062
33294
|
if (this.peek().kind === "SELECT" /* SELECT */) {
|
|
33063
33295
|
const select = this.parseSelect();
|
|
33064
33296
|
const keyFields2 = this.parseOnDuplicate();
|
|
33297
|
+
const checkGroups2 = this.parseCheckGroups();
|
|
33065
33298
|
const validation2 = this.parseDmlControlSuffix();
|
|
33066
|
-
return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...validation2 };
|
|
33299
|
+
return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...checkGroups2, ...validation2 };
|
|
33067
33300
|
}
|
|
33068
33301
|
this.expect("VALUES" /* VALUES */);
|
|
33069
33302
|
const values = [];
|
|
@@ -33073,8 +33306,9 @@ var Parser = class {
|
|
|
33073
33306
|
this.expect(")" /* RPAREN */);
|
|
33074
33307
|
} while (this.consume("," /* COMMA */));
|
|
33075
33308
|
const keyFields = this.parseOnDuplicate();
|
|
33309
|
+
const checkGroups = this.parseCheckGroups();
|
|
33076
33310
|
const validation = this.parseDmlControlSuffix();
|
|
33077
|
-
return { type: "UPSERT", appId, fields, values, keyFields, ...validation };
|
|
33311
|
+
return { type: "UPSERT", appId, fields, values, keyFields, ...checkGroups, ...validation };
|
|
33078
33312
|
}
|
|
33079
33313
|
parseOnDuplicate() {
|
|
33080
33314
|
this.expectKeyword("ON" /* ON */, "UPSERT \u306B\u306F ON DUPLICATE (\u30AD\u30FC\u30D5\u30A3\u30FC\u30EB\u30C9) \u304C\u5FC5\u8981\u3067\u3059");
|
|
@@ -33116,14 +33350,13 @@ var Parser = class {
|
|
|
33116
33350
|
} else if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
|
|
33117
33351
|
const sign = this.advance();
|
|
33118
33352
|
const number4 = this.expect("NUMBER" /* NUMBER */, "INSERT \u306E\u5358\u9805\u7B26\u53F7\u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
|
|
33119
|
-
|
|
33120
|
-
row.push({ type: "NUMBER", value: sign.kind === "-" /* MINUS */ ? -value : value });
|
|
33353
|
+
row.push(makeNumberLiteral(`${sign.kind === "-" /* MINUS */ ? "-" : "+"}${number4.value}`));
|
|
33121
33354
|
} else {
|
|
33122
33355
|
const tok = this.advance();
|
|
33123
33356
|
if (tok.kind === "STRING" /* STRING */) {
|
|
33124
33357
|
row.push({ type: "STRING", value: tok.value });
|
|
33125
33358
|
} else if (tok.kind === "NUMBER" /* NUMBER */) {
|
|
33126
|
-
row.push(
|
|
33359
|
+
row.push(makeNumberLiteral(tok.value));
|
|
33127
33360
|
} else {
|
|
33128
33361
|
throw new ParseError("INSERT \u306E\u5024\u306B\u306F\u6587\u5B57\u5217\u30FB\u6570\u5024\u30FB\u914D\u5217\u30EA\u30C6\u30E9\u30EB\u30FBCASE WHEN \u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
33129
33362
|
}
|
|
@@ -33207,12 +33440,33 @@ var Parser = class {
|
|
|
33207
33440
|
whereTok
|
|
33208
33441
|
);
|
|
33209
33442
|
}
|
|
33443
|
+
const checkGroups = this.parseCheckGroups();
|
|
33210
33444
|
const validation = this.parseDmlControlSuffix();
|
|
33445
|
+
if (subtableCode && checkGroups.checkGroups) {
|
|
33446
|
+
throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
|
|
33447
|
+
}
|
|
33211
33448
|
if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
|
|
33212
33449
|
throw new ParseError("VALIDATE ONLY / ON ERROR SKIP \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
|
|
33213
33450
|
}
|
|
33214
|
-
if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...validation };
|
|
33215
|
-
return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...validation } : { type: "UPDATE", appId, assignments, where, ...validation };
|
|
33451
|
+
if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...checkGroups, ...validation };
|
|
33452
|
+
return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...checkGroups, ...validation } : { type: "UPDATE", appId, assignments, where, ...checkGroups, ...validation };
|
|
33453
|
+
}
|
|
33454
|
+
/** CHECK WHEN ... THEN ... blocks. CHECK is a soft keyword. */
|
|
33455
|
+
parseCheckGroups() {
|
|
33456
|
+
const groups = [];
|
|
33457
|
+
while (this.isSoftKeyword("CHECK") && this.peekAt(1).kind === "WHEN" /* WHEN */) {
|
|
33458
|
+
const check2 = this.advance();
|
|
33459
|
+
const rules = [];
|
|
33460
|
+
while (this.consume("WHEN" /* WHEN */)) {
|
|
33461
|
+
const condition = this.parseWhereExpr();
|
|
33462
|
+
this.expect("THEN" /* THEN */, "CHECK WHEN \u306E\u6761\u4EF6\u306E\u5F8C\u306B\u306F THEN \u304C\u5FC5\u8981\u3067\u3059");
|
|
33463
|
+
const message = this.parseScalarValueExpr({ allowCase: false });
|
|
33464
|
+
rules.push({ condition, message });
|
|
33465
|
+
}
|
|
33466
|
+
if (rules.length === 0) throw new ParseError("CHECK \u306E\u5F8C\u306B\u306F WHEN \u304C\u6700\u4F4E 1 \u3064\u5FC5\u8981\u3067\u3059", check2);
|
|
33467
|
+
groups.push({ rules });
|
|
33468
|
+
}
|
|
33469
|
+
return groups.length > 0 ? { checkGroups: groups } : {};
|
|
33216
33470
|
}
|
|
33217
33471
|
/** DML末尾の VALIDATE ONLY または ON ERROR SKIP。各語はsoft keyword。 */
|
|
33218
33472
|
parseDmlControlSuffix() {
|
|
@@ -33401,6 +33655,12 @@ var Parser = class {
|
|
|
33401
33655
|
*/
|
|
33402
33656
|
parseAssignmentValue() {
|
|
33403
33657
|
const tok = this.peek();
|
|
33658
|
+
if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
|
|
33659
|
+
const expr = this.parseScalarValueExpr();
|
|
33660
|
+
if (expr.type === "CONCAT_OP" || expr.type === "SCALAR_ARITH" || expr.type === "STRING_FUNC") return expr;
|
|
33661
|
+
if (expr.type === "CASE_WHEN") return { type: "CASE_VALUE", expr };
|
|
33662
|
+
throw new ParseError("SET \u306E\u5024\u306B\u306F\u9023\u7D50\u3092\u542B\u3080\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u304C\u5FC5\u8981\u3067\u3059", tok);
|
|
33663
|
+
}
|
|
33404
33664
|
if (tok.kind === "VARIABLE" /* VARIABLE */) return this.parseSqlValue();
|
|
33405
33665
|
if (tok.kind === "STRING" /* STRING */) return this.parseSqlValue();
|
|
33406
33666
|
if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) return this.parseSqlValue();
|
|
@@ -33945,7 +34205,7 @@ function convertValue(value, op) {
|
|
|
33945
34205
|
case "STRING":
|
|
33946
34206
|
return convertString(value);
|
|
33947
34207
|
case "NUMBER":
|
|
33948
|
-
return
|
|
34208
|
+
return numberLiteralText(value);
|
|
33949
34209
|
case "KINTONE_FUNC":
|
|
33950
34210
|
return convertKintoneFunc(value);
|
|
33951
34211
|
case "IN_LIST":
|
|
@@ -33974,7 +34234,7 @@ function convertInList(v, op) {
|
|
|
33974
34234
|
}
|
|
33975
34235
|
assertResolvedInListValues(v.values);
|
|
33976
34236
|
const values = v.values.map(
|
|
33977
|
-
(item) => item.type === "STRING" ? convertString(item) :
|
|
34237
|
+
(item) => item.type === "STRING" ? convertString(item) : numberLiteralText(item)
|
|
33978
34238
|
).join(",");
|
|
33979
34239
|
return `(${values})`;
|
|
33980
34240
|
}
|
|
@@ -34012,7 +34272,7 @@ function resolveSelectMode(stmt) {
|
|
|
34012
34272
|
if (stmt.distinct) return "FULL_SCAN";
|
|
34013
34273
|
if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
|
|
34014
34274
|
if (stmt.columns.some(
|
|
34015
|
-
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
|
|
34275
|
+
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate(c.expr)
|
|
34016
34276
|
)) return "FULL_SCAN";
|
|
34017
34277
|
if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
|
|
34018
34278
|
if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
|
|
@@ -34107,6 +34367,8 @@ function extractFields(columns) {
|
|
|
34107
34367
|
collectArithNode(col.expr, fields);
|
|
34108
34368
|
} else if (col.type === "STRFUNC_COL") {
|
|
34109
34369
|
collectStringFuncFields(col.expr, fields);
|
|
34370
|
+
} else if (col.type === "SCALAR_VALUE_COL") {
|
|
34371
|
+
collectScalarValueFields(col.expr, fields);
|
|
34110
34372
|
}
|
|
34111
34373
|
}
|
|
34112
34374
|
return [...new Set(fields)];
|
|
@@ -34132,16 +34394,38 @@ function collectStringFuncFields(expr, out) {
|
|
|
34132
34394
|
}
|
|
34133
34395
|
}
|
|
34134
34396
|
function collectStringFuncArgFields(arg, out) {
|
|
34135
|
-
if (arg.type === "STRING") return;
|
|
34136
|
-
if (arg.type === "STRING_FUNC") {
|
|
34137
|
-
collectStringFuncFields(arg, out);
|
|
34138
|
-
return;
|
|
34139
|
-
}
|
|
34140
34397
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
34141
34398
|
collectAggOperandFields(arg, out);
|
|
34142
34399
|
return;
|
|
34143
34400
|
}
|
|
34144
|
-
|
|
34401
|
+
collectScalarValueFields(arg, out);
|
|
34402
|
+
}
|
|
34403
|
+
function collectScalarValueFields(expr, out) {
|
|
34404
|
+
if (expr.type === "FIELD") {
|
|
34405
|
+
out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
|
|
34406
|
+
return;
|
|
34407
|
+
}
|
|
34408
|
+
if (expr.type === "STRING_FUNC") {
|
|
34409
|
+
collectStringFuncFields(expr, out);
|
|
34410
|
+
return;
|
|
34411
|
+
}
|
|
34412
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
34413
|
+
collectScalarValueFields(expr.left, out);
|
|
34414
|
+
collectScalarValueFields(expr.right, out);
|
|
34415
|
+
return;
|
|
34416
|
+
}
|
|
34417
|
+
if (expr.type === "CASE_WHEN") {
|
|
34418
|
+
for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
|
|
34419
|
+
if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
|
|
34420
|
+
}
|
|
34421
|
+
}
|
|
34422
|
+
function collectCaseResultScalarFields(result, out) {
|
|
34423
|
+
if (result.type === "ARRAY") return;
|
|
34424
|
+
if (result.type === "FIELD_REF" || result.type === "ARITH") {
|
|
34425
|
+
collectArithNode(result, out);
|
|
34426
|
+
return;
|
|
34427
|
+
}
|
|
34428
|
+
collectScalarValueFields(result, out);
|
|
34145
34429
|
}
|
|
34146
34430
|
function collectAggOperandFields(node, out) {
|
|
34147
34431
|
if (node.type === "AGG_REF") {
|
|
@@ -34156,10 +34440,23 @@ function collectAggOperandFields(node, out) {
|
|
|
34156
34440
|
function hasAggregateInStringFuncExpr(expr) {
|
|
34157
34441
|
return expr.args.some((arg) => {
|
|
34158
34442
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
34159
|
-
|
|
34160
|
-
return false;
|
|
34443
|
+
return scalarValueHasAggregate(arg);
|
|
34161
34444
|
});
|
|
34162
34445
|
}
|
|
34446
|
+
function scalarValueHasAggregate(expr) {
|
|
34447
|
+
if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(expr);
|
|
34448
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
34449
|
+
return scalarValueHasAggregate(expr.left) || scalarValueHasAggregate(expr.right);
|
|
34450
|
+
}
|
|
34451
|
+
if (expr.type === "CASE_WHEN") {
|
|
34452
|
+
return expr.branches.some((b) => caseResultHasAggregate(b.result)) || expr.elseResult !== null && caseResultHasAggregate(expr.elseResult);
|
|
34453
|
+
}
|
|
34454
|
+
return false;
|
|
34455
|
+
}
|
|
34456
|
+
function caseResultHasAggregate(result) {
|
|
34457
|
+
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
34458
|
+
return scalarValueHasAggregate(result);
|
|
34459
|
+
}
|
|
34163
34460
|
function collectRequiredFieldsByTable(stmt) {
|
|
34164
34461
|
const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
|
|
34165
34462
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -34294,28 +34591,38 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
34294
34591
|
}
|
|
34295
34592
|
};
|
|
34296
34593
|
const walkStringArg = (arg, phase = "select") => {
|
|
34297
|
-
if (arg.type === "STRING") return;
|
|
34298
|
-
if (arg.type === "STRING_FUNC") {
|
|
34299
|
-
walkStringFunc(arg, phase);
|
|
34300
|
-
return;
|
|
34301
|
-
}
|
|
34302
34594
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
34303
34595
|
walkAgg(arg, phase);
|
|
34304
34596
|
return;
|
|
34305
34597
|
}
|
|
34306
|
-
|
|
34598
|
+
walkScalar(arg, phase);
|
|
34307
34599
|
};
|
|
34308
34600
|
const walkStringFunc = (expr, phase = "select") => {
|
|
34309
34601
|
for (const arg of expr.args) walkStringArg(arg, phase);
|
|
34310
34602
|
};
|
|
34603
|
+
const walkScalar = (expr, phase = "select") => {
|
|
34604
|
+
if (expr.type === "FIELD") {
|
|
34605
|
+
addFieldRef(expr.field, expr.tableAlias, phase);
|
|
34606
|
+
return;
|
|
34607
|
+
}
|
|
34608
|
+
if (expr.type === "STRING_FUNC") {
|
|
34609
|
+
walkStringFunc(expr, phase);
|
|
34610
|
+
return;
|
|
34611
|
+
}
|
|
34612
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
34613
|
+
walkScalar(expr.left, phase);
|
|
34614
|
+
walkScalar(expr.right, phase);
|
|
34615
|
+
return;
|
|
34616
|
+
}
|
|
34617
|
+
if (expr.type === "CASE_WHEN") walkCase(expr, phase);
|
|
34618
|
+
};
|
|
34311
34619
|
const walkCaseResult = (result, phase = "select") => {
|
|
34312
|
-
if (result.type === "STRING") return;
|
|
34313
34620
|
if (result.type === "ARRAY") return;
|
|
34314
|
-
if (result.type === "
|
|
34315
|
-
|
|
34621
|
+
if (result.type === "FIELD_REF" || result.type === "ARITH") {
|
|
34622
|
+
walkArith(result, phase);
|
|
34316
34623
|
return;
|
|
34317
34624
|
}
|
|
34318
|
-
|
|
34625
|
+
walkScalar(result, phase);
|
|
34319
34626
|
};
|
|
34320
34627
|
const walkCase = (expr, phase = "select") => {
|
|
34321
34628
|
for (const b of expr.branches) {
|
|
@@ -34421,6 +34728,9 @@ function collectRequiredFieldsByTable(stmt) {
|
|
|
34421
34728
|
case "STRFUNC_COL":
|
|
34422
34729
|
walkStringFunc(col.expr, "select");
|
|
34423
34730
|
break;
|
|
34731
|
+
case "SCALAR_VALUE_COL":
|
|
34732
|
+
walkScalar(col.expr, "select");
|
|
34733
|
+
break;
|
|
34424
34734
|
case "SCALAR_SUBQUERY_COL":
|
|
34425
34735
|
break;
|
|
34426
34736
|
case "WINDOW_COL":
|
|
@@ -34471,6 +34781,10 @@ function collectSelectOutputNames(columns) {
|
|
|
34471
34781
|
if (col.alias) names.add(col.alias);
|
|
34472
34782
|
continue;
|
|
34473
34783
|
}
|
|
34784
|
+
if (col.type === "SCALAR_VALUE_COL") {
|
|
34785
|
+
if (col.alias) names.add(col.alias);
|
|
34786
|
+
continue;
|
|
34787
|
+
}
|
|
34474
34788
|
if (col.type === "SCALAR_SUBQUERY_COL") {
|
|
34475
34789
|
names.add(col.alias ?? "(subquery)");
|
|
34476
34790
|
continue;
|
|
@@ -34487,20 +34801,38 @@ function aggregateSyntheticName(func, distinct, arg) {
|
|
|
34487
34801
|
}
|
|
34488
34802
|
function arithNodeLabel(node) {
|
|
34489
34803
|
if (node.type === "FIELD_REF") return node.field;
|
|
34490
|
-
if (node.type === "NUMBER") return
|
|
34804
|
+
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
34491
34805
|
if (node.type === "STRING_FUNC") return stringFuncLabel(node);
|
|
34492
34806
|
return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
|
|
34493
34807
|
}
|
|
34494
34808
|
function stringFuncLabel(expr) {
|
|
34495
34809
|
const args = expr.args.map((a) => {
|
|
34496
|
-
if (a.type === "STRING") return `'${a.value}'`;
|
|
34497
|
-
if (a.type === "STRING_FUNC") return stringFuncLabel(a);
|
|
34498
34810
|
if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
|
|
34499
34811
|
if (a.type === "AGG_ARITH") return "agg_arith";
|
|
34500
|
-
return
|
|
34812
|
+
return scalarValueLabel(a);
|
|
34501
34813
|
});
|
|
34502
34814
|
return `${expr.func}(${args.join(",")})`;
|
|
34503
34815
|
}
|
|
34816
|
+
function scalarValueLabel(expr) {
|
|
34817
|
+
switch (expr.type) {
|
|
34818
|
+
case "STRING":
|
|
34819
|
+
return `'${expr.value}'`;
|
|
34820
|
+
case "NUMBER":
|
|
34821
|
+
return numberLiteralText(expr);
|
|
34822
|
+
case "VARIABLE":
|
|
34823
|
+
return `@${expr.name}`;
|
|
34824
|
+
case "FIELD":
|
|
34825
|
+
return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
|
|
34826
|
+
case "STRING_FUNC":
|
|
34827
|
+
return stringFuncLabel(expr);
|
|
34828
|
+
case "CASE_WHEN":
|
|
34829
|
+
return "case";
|
|
34830
|
+
case "SCALAR_ARITH":
|
|
34831
|
+
return `(${scalarValueLabel(expr.left)}${expr.op}${scalarValueLabel(expr.right)})`;
|
|
34832
|
+
case "CONCAT_OP":
|
|
34833
|
+
return `(${scalarValueLabel(expr.left)}||${scalarValueLabel(expr.right)})`;
|
|
34834
|
+
}
|
|
34835
|
+
}
|
|
34504
34836
|
function isAggregateSyntheticName(name) {
|
|
34505
34837
|
return /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT)\(/i.test(name);
|
|
34506
34838
|
}
|
|
@@ -34644,7 +34976,7 @@ function isNumericCandidate(expr, options) {
|
|
|
34644
34976
|
if (!isTargetField(expr.left, options)) return false;
|
|
34645
34977
|
if (expr.right.type !== "NUMBER") return false;
|
|
34646
34978
|
if (expr.op === "=") return true;
|
|
34647
|
-
return (expr.op === "<" || expr.op === ">") && Number.isSafeInteger(expr.right.value);
|
|
34979
|
+
return (expr.op === "<" || expr.op === ">") && /^[+-]?\d+$/.test(numberLiteralText(expr.right)) && Number.isSafeInteger(expr.right.value);
|
|
34648
34980
|
}
|
|
34649
34981
|
function isSelectionInCandidate(expr, options) {
|
|
34650
34982
|
if (expr.left.type !== "FIELD" || expr.left.field === "$id") return false;
|
|
@@ -35249,9 +35581,10 @@ function triCompare(left, right) {
|
|
|
35249
35581
|
}
|
|
35250
35582
|
function numberKey(value) {
|
|
35251
35583
|
if (value === "") return { band: 0 };
|
|
35584
|
+
const decimal = parseExactDecimal(value);
|
|
35585
|
+
if (decimal !== null) return { band: 2, value: decimal };
|
|
35252
35586
|
const numeric = Number(value);
|
|
35253
35587
|
if (numeric === Number.NEGATIVE_INFINITY) return { band: 1 };
|
|
35254
|
-
if (Number.isFinite(numeric)) return { band: 2, value: numeric };
|
|
35255
35588
|
if (numeric === Number.POSITIVE_INFINITY) return { band: 3 };
|
|
35256
35589
|
if (value === "NaN") return { band: 4 };
|
|
35257
35590
|
return { band: 5, value };
|
|
@@ -35260,7 +35593,7 @@ function compareNumbers(left, right) {
|
|
|
35260
35593
|
const a = numberKey(left);
|
|
35261
35594
|
const b = numberKey(right);
|
|
35262
35595
|
if (a.band !== b.band) return a.band < b.band ? -1 : 1;
|
|
35263
|
-
if (a.band === 2 && b.band === 2) return
|
|
35596
|
+
if (a.band === 2 && b.band === 2) return compareExactDecimal(a.value, b.value);
|
|
35264
35597
|
if (a.band === 5 && b.band === 5) return compareCodePointStrings(a.value, b.value);
|
|
35265
35598
|
return 0;
|
|
35266
35599
|
}
|
|
@@ -35360,7 +35693,9 @@ function selectScalarExtreme(values, extreme) {
|
|
|
35360
35693
|
const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
|
|
35361
35694
|
const compare = (left, right) => {
|
|
35362
35695
|
if (numeric) {
|
|
35363
|
-
const
|
|
35696
|
+
const leftDecimal = parseExactDecimal(left);
|
|
35697
|
+
const rightDecimal = parseExactDecimal(right);
|
|
35698
|
+
const numericCmp = leftDecimal !== null && rightDecimal !== null ? compareExactDecimal(leftDecimal, rightDecimal) : triCompare(Number(left), Number(right));
|
|
35364
35699
|
if (numericCmp !== 0) return numericCmp;
|
|
35365
35700
|
}
|
|
35366
35701
|
return compareCodePointStrings(left, right);
|
|
@@ -35440,6 +35775,45 @@ function evalArithExpr(expr, row) {
|
|
|
35440
35775
|
return r !== 0 ? l % r : NaN;
|
|
35441
35776
|
}
|
|
35442
35777
|
}
|
|
35778
|
+
function evalScalarValueExpr(expr, row) {
|
|
35779
|
+
switch (expr.type) {
|
|
35780
|
+
case "STRING":
|
|
35781
|
+
return expr.value;
|
|
35782
|
+
case "NUMBER":
|
|
35783
|
+
return expr.value;
|
|
35784
|
+
case "FIELD":
|
|
35785
|
+
return resolveFieldRef(row, expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
|
|
35786
|
+
case "VARIABLE":
|
|
35787
|
+
throw new Error(`ArgumentError: unresolved variable @${expr.name} reached scalar evaluator.`);
|
|
35788
|
+
case "STRING_FUNC":
|
|
35789
|
+
return evalStringFunc(expr, row);
|
|
35790
|
+
case "CASE_WHEN":
|
|
35791
|
+
return evalCaseWhen(expr, row);
|
|
35792
|
+
case "CONCAT_OP": {
|
|
35793
|
+
return evalStringFunc({
|
|
35794
|
+
type: "STRING_FUNC",
|
|
35795
|
+
func: "CONCAT",
|
|
35796
|
+
args: [expr.left, expr.right]
|
|
35797
|
+
}, row);
|
|
35798
|
+
}
|
|
35799
|
+
case "SCALAR_ARITH": {
|
|
35800
|
+
const left = Number(evalScalarValueExpr(expr.left, row));
|
|
35801
|
+
const right = Number(evalScalarValueExpr(expr.right, row));
|
|
35802
|
+
switch (expr.op) {
|
|
35803
|
+
case "+":
|
|
35804
|
+
return left + right;
|
|
35805
|
+
case "-":
|
|
35806
|
+
return left - right;
|
|
35807
|
+
case "*":
|
|
35808
|
+
return left * right;
|
|
35809
|
+
case "/":
|
|
35810
|
+
return right !== 0 ? left / right : NaN;
|
|
35811
|
+
case "%":
|
|
35812
|
+
return right !== 0 ? left % right : NaN;
|
|
35813
|
+
}
|
|
35814
|
+
}
|
|
35815
|
+
}
|
|
35816
|
+
}
|
|
35443
35817
|
function applyRoundOp(op, num, digits) {
|
|
35444
35818
|
const factor = Math.pow(10, digits);
|
|
35445
35819
|
const raw = Math[op](num * factor) / factor;
|
|
@@ -35483,6 +35857,112 @@ function makeSafePadding(pad, gap) {
|
|
|
35483
35857
|
const repeated = pad.repeat(Math.ceil(gap / pad.length));
|
|
35484
35858
|
return sliceSafePrefix(repeated, gap);
|
|
35485
35859
|
}
|
|
35860
|
+
var REGEXP_CACHE_MAX = 200;
|
|
35861
|
+
var regexpCache = /* @__PURE__ */ new Map();
|
|
35862
|
+
function normalizeRegexpFlags(flags) {
|
|
35863
|
+
if (/[^ims]/.test(flags)) {
|
|
35864
|
+
throw new Error("ArgumentError: regular expression flags may contain only i, m, or s.");
|
|
35865
|
+
}
|
|
35866
|
+
if (new Set(flags).size !== flags.length) {
|
|
35867
|
+
throw new Error("ArgumentError: regular expression flags must not contain duplicates.");
|
|
35868
|
+
}
|
|
35869
|
+
return `${flags}u`;
|
|
35870
|
+
}
|
|
35871
|
+
function compileRegexp(pattern, flags, global = false) {
|
|
35872
|
+
const normalizedFlags = normalizeRegexpFlags(flags) + (global ? "g" : "");
|
|
35873
|
+
const key = `${pattern}\0${normalizedFlags}`;
|
|
35874
|
+
const cached2 = regexpCache.get(key);
|
|
35875
|
+
if (cached2 !== void 0) {
|
|
35876
|
+
cached2.lastIndex = 0;
|
|
35877
|
+
return cached2;
|
|
35878
|
+
}
|
|
35879
|
+
let regexp;
|
|
35880
|
+
try {
|
|
35881
|
+
regexp = new RegExp(pattern, normalizedFlags);
|
|
35882
|
+
} catch (error51) {
|
|
35883
|
+
const detail = error51 instanceof Error ? error51.message : String(error51);
|
|
35884
|
+
throw new Error(`ArgumentError: invalid regular expression: ${detail}`);
|
|
35885
|
+
}
|
|
35886
|
+
if (regexpCache.size >= REGEXP_CACHE_MAX) {
|
|
35887
|
+
const oldest = regexpCache.keys().next().value;
|
|
35888
|
+
if (oldest !== void 0) regexpCache.delete(oldest);
|
|
35889
|
+
}
|
|
35890
|
+
regexpCache.set(key, regexp);
|
|
35891
|
+
return regexp;
|
|
35892
|
+
}
|
|
35893
|
+
function assertRegexpReplacement(replacement) {
|
|
35894
|
+
if (replacement.includes("$`") || replacement.includes("$'")) {
|
|
35895
|
+
throw new Error("ArgumentError: REGEXP_REPLACE replacement must not contain $` or $'.");
|
|
35896
|
+
}
|
|
35897
|
+
}
|
|
35898
|
+
function parseRegexpOccurrence(arg) {
|
|
35899
|
+
if (arg === void 0) return 0;
|
|
35900
|
+
if (!/^\d+$/.test(arg)) {
|
|
35901
|
+
throw new Error("ArgumentError: REGEXP_REPLACE occurrence must be a non-negative integer.");
|
|
35902
|
+
}
|
|
35903
|
+
return Number(arg);
|
|
35904
|
+
}
|
|
35905
|
+
function expandRegexpReplacement(replacement, match, captures, namedGroups) {
|
|
35906
|
+
let result = "";
|
|
35907
|
+
for (let i = 0; i < replacement.length; i += 1) {
|
|
35908
|
+
const char = replacement[i];
|
|
35909
|
+
if (char !== "$" || i + 1 >= replacement.length) {
|
|
35910
|
+
result += char;
|
|
35911
|
+
continue;
|
|
35912
|
+
}
|
|
35913
|
+
const next = replacement[i + 1];
|
|
35914
|
+
if (next === "$") {
|
|
35915
|
+
result += "$";
|
|
35916
|
+
i += 1;
|
|
35917
|
+
continue;
|
|
35918
|
+
}
|
|
35919
|
+
if (next === "&") {
|
|
35920
|
+
result += match;
|
|
35921
|
+
i += 1;
|
|
35922
|
+
continue;
|
|
35923
|
+
}
|
|
35924
|
+
if (next === "<" && namedGroups !== void 0) {
|
|
35925
|
+
const end = replacement.indexOf(">", i + 2);
|
|
35926
|
+
if (end >= 0) {
|
|
35927
|
+
result += namedGroups[replacement.slice(i + 2, end)] ?? "";
|
|
35928
|
+
i = end;
|
|
35929
|
+
continue;
|
|
35930
|
+
}
|
|
35931
|
+
}
|
|
35932
|
+
if (/\d/.test(next)) {
|
|
35933
|
+
const secondDigit = replacement[i + 2];
|
|
35934
|
+
if (secondDigit !== void 0 && /\d/.test(secondDigit)) {
|
|
35935
|
+
const twoDigitIndex = Number(next + secondDigit);
|
|
35936
|
+
if (twoDigitIndex >= 1 && twoDigitIndex <= captures.length) {
|
|
35937
|
+
result += captures[twoDigitIndex - 1] ?? "";
|
|
35938
|
+
i += 2;
|
|
35939
|
+
continue;
|
|
35940
|
+
}
|
|
35941
|
+
}
|
|
35942
|
+
const oneDigitIndex = Number(next);
|
|
35943
|
+
if (oneDigitIndex >= 1 && oneDigitIndex <= captures.length) {
|
|
35944
|
+
result += captures[oneDigitIndex - 1] ?? "";
|
|
35945
|
+
i += 1;
|
|
35946
|
+
continue;
|
|
35947
|
+
}
|
|
35948
|
+
}
|
|
35949
|
+
result += "$";
|
|
35950
|
+
}
|
|
35951
|
+
return result;
|
|
35952
|
+
}
|
|
35953
|
+
function replaceNthMatch(input, globalRe, replacement, n) {
|
|
35954
|
+
let matchCount = 0;
|
|
35955
|
+
return input.replace(globalRe, (match, ...callbackArgs) => {
|
|
35956
|
+
matchCount += 1;
|
|
35957
|
+
if (matchCount !== n) return match;
|
|
35958
|
+
const lastArg = callbackArgs[callbackArgs.length - 1];
|
|
35959
|
+
const hasNamedGroups = typeof lastArg === "object" && lastArg !== null;
|
|
35960
|
+
const capturesEnd = callbackArgs.length - (hasNamedGroups ? 3 : 2);
|
|
35961
|
+
const captures = callbackArgs.slice(0, capturesEnd);
|
|
35962
|
+
const namedGroups = hasNamedGroups ? lastArg : void 0;
|
|
35963
|
+
return expandRegexpReplacement(replacement, match, captures, namedGroups);
|
|
35964
|
+
});
|
|
35965
|
+
}
|
|
35486
35966
|
function evalStringFunc(expr, row) {
|
|
35487
35967
|
const args = expr.args.map((a) => evalStringFuncArg(a, row));
|
|
35488
35968
|
switch (expr.func) {
|
|
@@ -35546,6 +36026,21 @@ function evalStringFunc(expr, row) {
|
|
|
35546
36026
|
const to = args[2] ?? "";
|
|
35547
36027
|
return from === "" ? str : str.split(from).join(to);
|
|
35548
36028
|
}
|
|
36029
|
+
case "REGEXP_LIKE": {
|
|
36030
|
+
assertArity("REGEXP_LIKE", args, 2, 3);
|
|
36031
|
+
return compileRegexp(args[1], args[2] ?? "").test(args[0]) ? "1" : "0";
|
|
36032
|
+
}
|
|
36033
|
+
case "REGEXP_REPLACE": {
|
|
36034
|
+
assertArity("REGEXP_REPLACE", args, 3, 5);
|
|
36035
|
+
assertRegexpReplacement(args[2]);
|
|
36036
|
+
const occurrence = parseRegexpOccurrence(args[4]);
|
|
36037
|
+
const regexp = compileRegexp(args[1], args[3] ?? "", true);
|
|
36038
|
+
return occurrence === 0 ? args[0].replace(regexp, args[2]) : replaceNthMatch(args[0], regexp, args[2], occurrence);
|
|
36039
|
+
}
|
|
36040
|
+
case "REGEXP_SUBSTR": {
|
|
36041
|
+
assertArity("REGEXP_SUBSTR", args, 2, 3);
|
|
36042
|
+
return compileRegexp(args[1], args[2] ?? "").exec(args[0])?.[0] ?? "";
|
|
36043
|
+
}
|
|
35549
36044
|
case "TRANSLATE": {
|
|
35550
36045
|
assertArity("TRANSLATE", args, 3, 3);
|
|
35551
36046
|
const from = [...args[1]];
|
|
@@ -35721,12 +36216,9 @@ function formatWithComma(num, digits) {
|
|
|
35721
36216
|
return decStr ? `${intFmt}.${decStr}` : intFmt;
|
|
35722
36217
|
}
|
|
35723
36218
|
function evalStringFuncArg(arg, row) {
|
|
35724
|
-
if (arg.type === "STRING") return arg.value;
|
|
35725
|
-
if (arg.type === "STRING_FUNC") return evalStringFunc(arg, row);
|
|
35726
|
-
if (arg.type === "FIELD_REF") return resolveFieldRef(row, arg.field);
|
|
35727
|
-
if (arg.type === "NUMBER") return String(arg.value);
|
|
35728
36219
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
|
|
35729
|
-
|
|
36220
|
+
if (arg.type === "NUMBER") return numberLiteralText(arg);
|
|
36221
|
+
return String(evalScalarValueExpr(arg, row));
|
|
35730
36222
|
}
|
|
35731
36223
|
function resolveFieldRef(row, field) {
|
|
35732
36224
|
const direct = row[field];
|
|
@@ -35773,7 +36265,7 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics
|
|
|
35773
36265
|
let values = null;
|
|
35774
36266
|
if (right.type === "IN_LIST") {
|
|
35775
36267
|
assertResolvedInListValues2(right.values);
|
|
35776
|
-
values = new Set(right.values.map((v) => String(v.value)));
|
|
36268
|
+
values = new Set(right.values.map((v) => v.type === "NUMBER" ? fieldType === "NUMBER" ? numberLiteralText(v) : String(v.value) : v.value));
|
|
35777
36269
|
}
|
|
35778
36270
|
if (right.type === "SUBQUERY_IN_LIST") {
|
|
35779
36271
|
values = right.resolved;
|
|
@@ -35853,6 +36345,10 @@ var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"])
|
|
|
35853
36345
|
function typedInContains(leftStr, values, fieldType) {
|
|
35854
36346
|
const fallback = () => values.has(leftStr);
|
|
35855
36347
|
if (fieldType === void 0) return fallback();
|
|
36348
|
+
if (fieldType === "NUMBER") {
|
|
36349
|
+
const semantics = syntheticSemantics("number");
|
|
36350
|
+
return [...values].some((value) => compareScalarValues("=", leftStr, value, semantics));
|
|
36351
|
+
}
|
|
35856
36352
|
let parsed;
|
|
35857
36353
|
if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
|
|
35858
36354
|
try {
|
|
@@ -35911,7 +36407,7 @@ function resolveValue(value, row, resolveFieldType, resolveFieldSemantics2) {
|
|
|
35911
36407
|
case "STRING":
|
|
35912
36408
|
return value.value;
|
|
35913
36409
|
case "NUMBER":
|
|
35914
|
-
return
|
|
36410
|
+
return numberLiteralText(value);
|
|
35915
36411
|
case "KINTONE_FUNC":
|
|
35916
36412
|
return resolveKintoneFunc(value.name);
|
|
35917
36413
|
case "IN_LIST":
|
|
@@ -35945,10 +36441,13 @@ function evalCaseWhen(expr, row, resolveFieldType, resolveFieldSemantics2) {
|
|
|
35945
36441
|
}
|
|
35946
36442
|
function evalCaseResult(result, row) {
|
|
35947
36443
|
if (result.type === "ARRAY") return result.elements.map((e) => e.value).join(",");
|
|
35948
|
-
if (result.type === "
|
|
35949
|
-
|
|
35950
|
-
|
|
35951
|
-
|
|
36444
|
+
if (result.type === "FIELD_REF") {
|
|
36445
|
+
return row[result.field] ?? "";
|
|
36446
|
+
}
|
|
36447
|
+
if (result.type === "ARITH") {
|
|
36448
|
+
return String(evalArithExpr(result, row));
|
|
36449
|
+
}
|
|
36450
|
+
return String(evalScalarValueExpr(result, row));
|
|
35952
36451
|
}
|
|
35953
36452
|
function resolveKintoneFunc(name) {
|
|
35954
36453
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -35992,6 +36491,63 @@ function matchLike(value, pattern) {
|
|
|
35992
36491
|
return regex.test(value);
|
|
35993
36492
|
}
|
|
35994
36493
|
|
|
36494
|
+
// src/core/dmlCustomCheck.ts
|
|
36495
|
+
function collectCheckFieldRefs(groups) {
|
|
36496
|
+
return collectRefs2(groups);
|
|
36497
|
+
}
|
|
36498
|
+
function collectCheckComparisonFieldRefs(groups) {
|
|
36499
|
+
return collectRefs2(groups.flatMap((group) => group.rules.map((rule) => rule.condition)));
|
|
36500
|
+
}
|
|
36501
|
+
function collectRefs2(root) {
|
|
36502
|
+
const refs = [];
|
|
36503
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36504
|
+
const visit = (node) => {
|
|
36505
|
+
if (Array.isArray(node)) {
|
|
36506
|
+
node.forEach(visit);
|
|
36507
|
+
return;
|
|
36508
|
+
}
|
|
36509
|
+
if (node === null || typeof node !== "object") return;
|
|
36510
|
+
const obj = node;
|
|
36511
|
+
if (obj.type === "EXISTS" || obj.type === "SUBQUERY_IN_LIST" || obj.type === "SCALAR_SUBQUERY") {
|
|
36512
|
+
throw customCheckParseError("CHECK \u306B\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
|
|
36513
|
+
}
|
|
36514
|
+
if (obj.type === "FIELD" && typeof obj.field === "string") {
|
|
36515
|
+
add(typeof obj.tableAlias === "string" ? obj.tableAlias : null, obj.field);
|
|
36516
|
+
} else if (obj.type === "FIELD_REF" && typeof obj.field === "string") {
|
|
36517
|
+
const dot = obj.field.indexOf(".");
|
|
36518
|
+
add(dot > 0 ? obj.field.slice(0, dot) : null, dot > 0 ? obj.field.slice(dot + 1) : obj.field);
|
|
36519
|
+
}
|
|
36520
|
+
for (const value of Object.values(obj)) visit(value);
|
|
36521
|
+
};
|
|
36522
|
+
const add = (tableAlias, field) => {
|
|
36523
|
+
if (/^(COUNT|SUM|AVG|MIN|MAX|GROUP_CONCAT)\(/i.test(field)) {
|
|
36524
|
+
throw customCheckParseError("CHECK \u306B\u96C6\u7D04\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
|
|
36525
|
+
}
|
|
36526
|
+
const key = `${tableAlias ?? ""}\0${field}`;
|
|
36527
|
+
if (!seen.has(key)) {
|
|
36528
|
+
seen.add(key);
|
|
36529
|
+
refs.push({ tableAlias, field });
|
|
36530
|
+
}
|
|
36531
|
+
};
|
|
36532
|
+
visit(root);
|
|
36533
|
+
return refs;
|
|
36534
|
+
}
|
|
36535
|
+
function customCheckParseError(message) {
|
|
36536
|
+
return new ParseError(message, { kind: "EOF" /* EOF */, value: "CHECK", pos: 0 });
|
|
36537
|
+
}
|
|
36538
|
+
function evaluateCustomChecks(groups, row, resolveFieldType) {
|
|
36539
|
+
const errors = [];
|
|
36540
|
+
groups.forEach((group, groupIndex) => {
|
|
36541
|
+
for (const rule of group.rules) {
|
|
36542
|
+
if (!evalWhere(rule.condition, row, resolveFieldType)) continue;
|
|
36543
|
+
const value = evalScalarValueExpr(rule.message, row);
|
|
36544
|
+
errors.push({ groupIndex, message: value == null ? "" : String(value) });
|
|
36545
|
+
break;
|
|
36546
|
+
}
|
|
36547
|
+
});
|
|
36548
|
+
return errors;
|
|
36549
|
+
}
|
|
36550
|
+
|
|
35995
36551
|
// src/converter/dmlToKintone.ts
|
|
35996
36552
|
function assertDmlWhereIsSafe(where) {
|
|
35997
36553
|
if (whereHasKlike(where)) {
|
|
@@ -36029,10 +36585,11 @@ function buildInsertRecord(fields, row, fieldTypes) {
|
|
|
36029
36585
|
}
|
|
36030
36586
|
function updateToGetQuery(stmt) {
|
|
36031
36587
|
assertDmlWhereIsSafe(stmt.where);
|
|
36588
|
+
const checkFields = collectUpdateCheckTargetFields(stmt);
|
|
36032
36589
|
return {
|
|
36033
36590
|
app: stmt.appId,
|
|
36034
36591
|
query: whereToKintone(stmt.where),
|
|
36035
|
-
fields: ["$id"],
|
|
36592
|
+
fields: ["$id", ...checkFields],
|
|
36036
36593
|
totalCount: false
|
|
36037
36594
|
};
|
|
36038
36595
|
}
|
|
@@ -36046,19 +36603,19 @@ function updateToPutBatches(stmt, ids, fieldTypes = /* @__PURE__ */ new Map()) {
|
|
|
36046
36603
|
function buildUpdateRecord(assignments, fieldTypes) {
|
|
36047
36604
|
const record2 = {};
|
|
36048
36605
|
for (const { field, value } of assignments) {
|
|
36049
|
-
if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
|
|
36606
|
+
if (value.type === "ARITH" || value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
|
|
36050
36607
|
record2[field] = { value: toKintoneValue(value, fieldTypes.get(field)) };
|
|
36051
36608
|
}
|
|
36052
36609
|
return record2;
|
|
36053
36610
|
}
|
|
36054
36611
|
function hasArithAssignment(stmt) {
|
|
36055
36612
|
return stmt.assignments.some(
|
|
36056
|
-
(a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE"
|
|
36613
|
+
(a) => a.value.type === "ARITH" || a.value.type === "SCALAR_ARITH" || a.value.type === "CONCAT_OP" || a.value.type === "CASE_VALUE"
|
|
36057
36614
|
);
|
|
36058
36615
|
}
|
|
36059
36616
|
function hasRowDependentAssignment(stmt) {
|
|
36060
36617
|
return stmt.assignments.some(
|
|
36061
|
-
(a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
|
|
36618
|
+
(a) => a.value.type === "ARITH" || a.value.type === "SCALAR_ARITH" || a.value.type === "CONCAT_OP" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
|
|
36062
36619
|
);
|
|
36063
36620
|
}
|
|
36064
36621
|
function updateToGetQueryForArith(stmt) {
|
|
@@ -36067,12 +36624,15 @@ function updateToGetQueryForArith(stmt) {
|
|
|
36067
36624
|
for (const { value } of stmt.assignments) {
|
|
36068
36625
|
if (value.type === "ARITH") {
|
|
36069
36626
|
collectArithFields2(value, refFields);
|
|
36627
|
+
} else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
|
|
36628
|
+
collectScalarValueFields2(value, refFields);
|
|
36070
36629
|
} else if (value.type === "STRING_FUNC") {
|
|
36071
36630
|
collectStringFuncFields2(value, refFields);
|
|
36072
36631
|
} else if (value.type === "CASE_VALUE") {
|
|
36073
36632
|
collectCaseFields(value.expr, refFields);
|
|
36074
36633
|
}
|
|
36075
36634
|
}
|
|
36635
|
+
collectUpdateCheckTargetFields(stmt).forEach((field) => refFields.add(field));
|
|
36076
36636
|
return {
|
|
36077
36637
|
app: stmt.appId,
|
|
36078
36638
|
query: whereToKintone(stmt.where),
|
|
@@ -36093,16 +36653,27 @@ function collectStringFuncFields2(expr, out) {
|
|
|
36093
36653
|
for (const arg of expr.args) collectStringFuncArgFields2(arg, out);
|
|
36094
36654
|
}
|
|
36095
36655
|
function collectStringFuncArgFields2(arg, out) {
|
|
36096
|
-
if (arg.type === "STRING") return;
|
|
36097
|
-
if (arg.type === "STRING_FUNC") {
|
|
36098
|
-
collectStringFuncFields2(arg, out);
|
|
36099
|
-
return;
|
|
36100
|
-
}
|
|
36101
36656
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
36102
36657
|
collectAggOperandFields2(arg, out);
|
|
36103
36658
|
return;
|
|
36104
36659
|
}
|
|
36105
|
-
|
|
36660
|
+
collectScalarValueFields2(arg, out);
|
|
36661
|
+
}
|
|
36662
|
+
function collectScalarValueFields2(expr, out) {
|
|
36663
|
+
if (expr.type === "FIELD") {
|
|
36664
|
+
out.add(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
|
|
36665
|
+
return;
|
|
36666
|
+
}
|
|
36667
|
+
if (expr.type === "STRING_FUNC") {
|
|
36668
|
+
collectStringFuncFields2(expr, out);
|
|
36669
|
+
return;
|
|
36670
|
+
}
|
|
36671
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
36672
|
+
collectScalarValueFields2(expr.left, out);
|
|
36673
|
+
collectScalarValueFields2(expr.right, out);
|
|
36674
|
+
return;
|
|
36675
|
+
}
|
|
36676
|
+
if (expr.type === "CASE_WHEN") collectCaseFields(expr, out);
|
|
36106
36677
|
}
|
|
36107
36678
|
function collectAggOperandFields2(node, out) {
|
|
36108
36679
|
if (node.type === "AGG_REF") {
|
|
@@ -36115,9 +36686,12 @@ function collectAggOperandFields2(node, out) {
|
|
|
36115
36686
|
}
|
|
36116
36687
|
}
|
|
36117
36688
|
function collectCaseResultFields(result, out) {
|
|
36118
|
-
if (result.type === "STRING") return;
|
|
36119
36689
|
if (result.type === "ARRAY") return;
|
|
36120
|
-
|
|
36690
|
+
if (result.type === "FIELD_REF" || result.type === "ARITH") {
|
|
36691
|
+
collectArithNode2(result, out);
|
|
36692
|
+
return;
|
|
36693
|
+
}
|
|
36694
|
+
collectScalarValueFields2(result, out);
|
|
36121
36695
|
}
|
|
36122
36696
|
function collectCaseFields(expr, out) {
|
|
36123
36697
|
for (const branch of expr.branches) {
|
|
@@ -36155,6 +36729,8 @@ function updateToPutBatchesArith(stmt, records, fieldTypes = /* @__PURE__ */ new
|
|
|
36155
36729
|
for (const { field, value } of stmt.assignments) {
|
|
36156
36730
|
if (value.type === "ARITH") {
|
|
36157
36731
|
record2[field] = { value: String(evalArith(value, raw)) };
|
|
36732
|
+
} else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
|
|
36733
|
+
record2[field] = { value: String(evalScalarValueExpr(value, row)) };
|
|
36158
36734
|
} else if (value.type === "STRING_FUNC") {
|
|
36159
36735
|
record2[field] = { value: evalStringFunc(value, row) };
|
|
36160
36736
|
} else if (value.type === "CASE_VALUE") {
|
|
@@ -36209,6 +36785,8 @@ function updateFromToPutBatches(stmt, matched, fieldTypes = /* @__PURE__ */ new
|
|
|
36209
36785
|
throw new DmlConvertError("UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
|
|
36210
36786
|
} else if (value.type === "ARITH") {
|
|
36211
36787
|
record2[field] = { value: String(evalArith(value, target)) };
|
|
36788
|
+
} else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
|
|
36789
|
+
record2[field] = { value: String(evalScalarValueExpr(value, targetRow)) };
|
|
36212
36790
|
} else if (value.type === "CASE_VALUE") {
|
|
36213
36791
|
record2[field] = { value: evalCaseWhenValue(value.expr, targetRow, fieldType) };
|
|
36214
36792
|
} else {
|
|
@@ -36319,7 +36897,15 @@ function evalCaseResultValue(result, row, fieldType) {
|
|
|
36319
36897
|
if (result.type === "STRING_FUNC") {
|
|
36320
36898
|
return evalStringFunc(result, row);
|
|
36321
36899
|
}
|
|
36322
|
-
|
|
36900
|
+
if (result.type === "FIELD_REF" || result.type === "ARITH") {
|
|
36901
|
+
return String(evalArithExpr(result, row));
|
|
36902
|
+
}
|
|
36903
|
+
return String(evalScalarValueExpr(result, row));
|
|
36904
|
+
}
|
|
36905
|
+
function collectUpdateCheckTargetFields(stmt) {
|
|
36906
|
+
if (!stmt.checkGroups) return [];
|
|
36907
|
+
const targetAlias = `app${stmt.appId}`.toLowerCase();
|
|
36908
|
+
return [...new Set(collectCheckFieldRefs(stmt.checkGroups).filter((ref) => ref.tableAlias === null || ref.tableAlias.toLowerCase() === targetAlias).map((ref) => ref.field).filter((field) => field !== "$id"))];
|
|
36323
36909
|
}
|
|
36324
36910
|
function evalCaseWhenValue(expr, row, fieldType) {
|
|
36325
36911
|
for (const branch of expr.branches) {
|
|
@@ -36351,7 +36937,7 @@ function convertDmlSqlValue(value, fieldType) {
|
|
|
36351
36937
|
case "STRING":
|
|
36352
36938
|
return convertString2(value.value, fieldType);
|
|
36353
36939
|
case "NUMBER":
|
|
36354
|
-
return
|
|
36940
|
+
return numberLiteralText(value);
|
|
36355
36941
|
case "ARRAY":
|
|
36356
36942
|
return convertArray(value.elements.map((e) => e.value), fieldType);
|
|
36357
36943
|
case "KINTONE_FUNC":
|
|
@@ -36872,7 +37458,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
|
|
|
36872
37458
|
}
|
|
36873
37459
|
function hasAggregateColumns(columns) {
|
|
36874
37460
|
return columns.some(
|
|
36875
|
-
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr)
|
|
37461
|
+
(c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
|
|
36876
37462
|
);
|
|
36877
37463
|
}
|
|
36878
37464
|
function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
|
|
@@ -36909,6 +37495,10 @@ function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
|
|
|
36909
37495
|
const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
|
|
36910
37496
|
const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
|
|
36911
37497
|
outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
|
|
37498
|
+
} else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
|
|
37499
|
+
const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
|
|
37500
|
+
const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
|
|
37501
|
+
outRow[outputKey] = String(evalScalarValueExpr(resolvedExpr, outRow));
|
|
36912
37502
|
}
|
|
36913
37503
|
}
|
|
36914
37504
|
result.push(outRow);
|
|
@@ -36983,7 +37573,7 @@ function evalAggArithExpr(node, rows, resolveAggSortKind) {
|
|
|
36983
37573
|
}
|
|
36984
37574
|
}
|
|
36985
37575
|
function aggArithDefaultKey(node) {
|
|
36986
|
-
if (node.type === "NUMBER") return
|
|
37576
|
+
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
36987
37577
|
if (node.type === "AGG_REF") return aggregateSyntheticName2(node.func, node.distinct, node.arg);
|
|
36988
37578
|
return `${aggArithDefaultKey(node.left)}${node.op}${aggArithDefaultKey(node.right)}`;
|
|
36989
37579
|
}
|
|
@@ -37239,6 +37829,13 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
|
|
|
37239
37829
|
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
37240
37830
|
break;
|
|
37241
37831
|
}
|
|
37832
|
+
case "SCALAR_VALUE_COL": {
|
|
37833
|
+
const key = outputKeys?.[colIdx] ?? col.alias ?? scalarValueDefaultKey(col.expr);
|
|
37834
|
+
const srcKey = scalarValueDefaultKey(col.expr);
|
|
37835
|
+
out[key] = scalarValueHasAggregate2(col.expr) ? row[col.alias ?? srcKey] ?? row[srcKey] ?? "" : String(evalScalarValueExpr(col.expr, row));
|
|
37836
|
+
if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
|
|
37837
|
+
break;
|
|
37838
|
+
}
|
|
37242
37839
|
case "SCALAR_SUBQUERY_COL": {
|
|
37243
37840
|
const key = outputKeys?.[colIdx] ?? col.alias ?? "(subquery)";
|
|
37244
37841
|
out[key] = scalarCache?.get(colIdx) ?? "";
|
|
@@ -37289,6 +37886,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
|
|
|
37289
37886
|
return col.alias ?? "case";
|
|
37290
37887
|
case "STRFUNC_COL":
|
|
37291
37888
|
return col.alias ?? stringFuncDefaultKey(col.expr);
|
|
37889
|
+
case "SCALAR_VALUE_COL":
|
|
37890
|
+
return col.alias ?? scalarValueDefaultKey(col.expr);
|
|
37292
37891
|
case "SCALAR_SUBQUERY_COL":
|
|
37293
37892
|
return col.alias ?? "(subquery)";
|
|
37294
37893
|
case "WINDOW_COL":
|
|
@@ -37333,7 +37932,7 @@ function stripParentShortcutColumns(row) {
|
|
|
37333
37932
|
function arithColDefaultKey(expr) {
|
|
37334
37933
|
const nodeLabel = (n) => {
|
|
37335
37934
|
if (n.type === "FIELD_REF") return n.field;
|
|
37336
|
-
if (n.type === "NUMBER") return
|
|
37935
|
+
if (n.type === "NUMBER") return numberLiteralText(n);
|
|
37337
37936
|
if (n.type === "STRING_FUNC") return stringFuncDefaultKey(n);
|
|
37338
37937
|
return `(${nodeLabel(n.left)}${n.op}${nodeLabel(n.right)})`;
|
|
37339
37938
|
};
|
|
@@ -37344,33 +37943,76 @@ function arithColDefaultKey(expr) {
|
|
|
37344
37943
|
}
|
|
37345
37944
|
function stringFuncDefaultKey(expr) {
|
|
37346
37945
|
const argStrs = expr.args.map((a) => {
|
|
37347
|
-
if (a.type === "STRING") return `'${a.value}'`;
|
|
37348
|
-
if (a.type === "STRING_FUNC") return stringFuncDefaultKey(a);
|
|
37349
37946
|
if (a.type === "AGG_REF" || a.type === "AGG_ARITH") return aggArithDefaultKey(a);
|
|
37350
|
-
return
|
|
37947
|
+
return scalarValueDefaultKey(a);
|
|
37351
37948
|
});
|
|
37352
37949
|
return `${expr.func}(${argStrs.join(",")})`;
|
|
37353
37950
|
}
|
|
37951
|
+
function scalarValueDefaultKey(expr) {
|
|
37952
|
+
switch (expr.type) {
|
|
37953
|
+
case "STRING":
|
|
37954
|
+
return `'${expr.value}'`;
|
|
37955
|
+
case "NUMBER":
|
|
37956
|
+
return numberLiteralText(expr);
|
|
37957
|
+
case "VARIABLE":
|
|
37958
|
+
return `@${expr.name}`;
|
|
37959
|
+
case "FIELD":
|
|
37960
|
+
return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
|
|
37961
|
+
case "STRING_FUNC":
|
|
37962
|
+
return stringFuncDefaultKey(expr);
|
|
37963
|
+
case "CASE_WHEN":
|
|
37964
|
+
return "case";
|
|
37965
|
+
case "SCALAR_ARITH":
|
|
37966
|
+
return `${scalarValueDefaultKey(expr.left)}${expr.op}${scalarValueDefaultKey(expr.right)}`;
|
|
37967
|
+
case "CONCAT_OP":
|
|
37968
|
+
return `${scalarValueDefaultKey(expr.left)}||${scalarValueDefaultKey(expr.right)}`;
|
|
37969
|
+
}
|
|
37970
|
+
}
|
|
37354
37971
|
function hasAggregateInStringFuncArg(arg) {
|
|
37355
37972
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
37356
|
-
|
|
37973
|
+
return scalarValueHasAggregate2(arg);
|
|
37974
|
+
}
|
|
37975
|
+
function scalarValueHasAggregate2(expr) {
|
|
37976
|
+
if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(expr);
|
|
37977
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
37978
|
+
return scalarValueHasAggregate2(expr.left) || scalarValueHasAggregate2(expr.right);
|
|
37979
|
+
}
|
|
37980
|
+
if (expr.type === "CASE_WHEN") {
|
|
37981
|
+
return expr.branches.some((branch) => caseResultHasAggregate2(branch.result)) || expr.elseResult !== null && caseResultHasAggregate2(expr.elseResult);
|
|
37982
|
+
}
|
|
37357
37983
|
return false;
|
|
37358
37984
|
}
|
|
37985
|
+
function caseResultHasAggregate2(result) {
|
|
37986
|
+
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
37987
|
+
return scalarValueHasAggregate2(result);
|
|
37988
|
+
}
|
|
37359
37989
|
function hasAggregateInStringFuncExpr2(expr) {
|
|
37360
37990
|
return expr.args.some((arg) => hasAggregateInStringFuncArg(arg));
|
|
37361
37991
|
}
|
|
37362
37992
|
function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
|
|
37363
37993
|
if (arg.type === "AGG_REF") {
|
|
37364
37994
|
const value = evalAggregate(arg.func, arg.distinct, arg.arg, arg.separator, rows, resolveAggSortKind);
|
|
37365
|
-
return typeof value === "number" ? { type: "NUMBER", value } : { type: "STRING", value };
|
|
37995
|
+
return typeof value === "number" ? { type: "NUMBER", value, raw: String(value) } : { type: "STRING", value };
|
|
37366
37996
|
}
|
|
37367
37997
|
if (arg.type === "AGG_ARITH") {
|
|
37368
|
-
|
|
37998
|
+
const value = evalAggArithExpr(arg, rows, resolveAggSortKind);
|
|
37999
|
+
return { type: "NUMBER", value, raw: String(value) };
|
|
37369
38000
|
}
|
|
37370
38001
|
if (arg.type === "STRING_FUNC") {
|
|
37371
38002
|
return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
|
|
37372
38003
|
}
|
|
37373
|
-
return arg;
|
|
38004
|
+
return resolveAggInScalarValue(arg, rows, resolveAggSortKind);
|
|
38005
|
+
}
|
|
38006
|
+
function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
|
|
38007
|
+
if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
|
|
38008
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
38009
|
+
return {
|
|
38010
|
+
...expr,
|
|
38011
|
+
left: resolveAggInScalarValue(expr.left, rows, resolveAggSortKind),
|
|
38012
|
+
right: resolveAggInScalarValue(expr.right, rows, resolveAggSortKind)
|
|
38013
|
+
};
|
|
38014
|
+
}
|
|
38015
|
+
return expr;
|
|
37374
38016
|
}
|
|
37375
38017
|
function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
|
|
37376
38018
|
return {
|
|
@@ -37391,7 +38033,7 @@ function deriveOutputOrderSemantics(columns) {
|
|
|
37391
38033
|
} else if (column.func === "GROUP_CONCAT") {
|
|
37392
38034
|
result.set(column.alias, syntheticSemantics("string"));
|
|
37393
38035
|
}
|
|
37394
|
-
} else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL") {
|
|
38036
|
+
} else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "SCALAR_VALUE_COL") {
|
|
37395
38037
|
result.set(column.alias, syntheticSemantics("string"));
|
|
37396
38038
|
} else if (column.type === "STRFUNC_COL") {
|
|
37397
38039
|
result.set(column.alias, syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(column.expr.func) ? "number" : "string"));
|
|
@@ -37483,10 +38125,43 @@ function toFlatString(value) {
|
|
|
37483
38125
|
}
|
|
37484
38126
|
}
|
|
37485
38127
|
|
|
38128
|
+
// src/core/numberPrecision.ts
|
|
38129
|
+
function parseIntegerSetting(value, name, min, max) {
|
|
38130
|
+
if (typeof value !== "string" || !/^\d+$/.test(value)) {
|
|
38131
|
+
throw new Error(`SettingsError: numberPrecision.${name} must be an integer string.`);
|
|
38132
|
+
}
|
|
38133
|
+
let parsed = 0;
|
|
38134
|
+
for (const digit of value) parsed = parsed * 10 + digit.charCodeAt(0) - 48;
|
|
38135
|
+
if (parsed < min || parsed > max) {
|
|
38136
|
+
throw new Error(`SettingsError: numberPrecision.${name} must be between ${min} and ${max}.`);
|
|
38137
|
+
}
|
|
38138
|
+
return parsed;
|
|
38139
|
+
}
|
|
38140
|
+
function parseNumberPrecisionSettings(response) {
|
|
38141
|
+
const raw = response.numberPrecision;
|
|
38142
|
+
if (raw === void 0 || raw === null || typeof raw !== "object") {
|
|
38143
|
+
throw new Error("SettingsError: numberPrecision is missing from app settings.");
|
|
38144
|
+
}
|
|
38145
|
+
const digits = parseIntegerSetting(raw.digits, "digits", 1, 30);
|
|
38146
|
+
const decimalPlaces = parseIntegerSetting(raw.decimalPlaces, "decimalPlaces", 0, 10);
|
|
38147
|
+
const roundingMode = raw.roundingMode;
|
|
38148
|
+
if (roundingMode !== "HALF_EVEN" && roundingMode !== "UP" && roundingMode !== "DOWN") {
|
|
38149
|
+
throw new Error("SettingsError: numberPrecision.roundingMode is unsupported.");
|
|
38150
|
+
}
|
|
38151
|
+
return { digits, decimalPlaces, roundingMode };
|
|
38152
|
+
}
|
|
38153
|
+
function exactDecimalDigitCounts(value) {
|
|
38154
|
+
if (value.sign === 0) return { integerDigits: 0, fractionDigits: 0 };
|
|
38155
|
+
return {
|
|
38156
|
+
integerDigits: Math.max(value.coefficient.length - value.scale, 0),
|
|
38157
|
+
fractionDigits: Math.max(value.scale, 0)
|
|
38158
|
+
};
|
|
38159
|
+
}
|
|
38160
|
+
|
|
37486
38161
|
// src/core/dmlValidation.ts
|
|
37487
38162
|
var ARRAY_TYPES2 = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
|
|
37488
38163
|
var CHOICE_TYPES = /* @__PURE__ */ new Set(["DROP_DOWN", "RADIO_BUTTON", "CHECK_BOX", "MULTI_SELECT"]);
|
|
37489
|
-
function validateAndNormalizeDmlValue(raw, field) {
|
|
38164
|
+
function validateAndNormalizeDmlValue(raw, field, numberPrecision) {
|
|
37490
38165
|
if (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME") {
|
|
37491
38166
|
const original = rawScalarText(raw);
|
|
37492
38167
|
if (original !== "" && !isValidTemporalInput(original, field.fieldType)) {
|
|
@@ -37505,7 +38180,8 @@ function validateAndNormalizeDmlValue(raw, field) {
|
|
|
37505
38180
|
}
|
|
37506
38181
|
if (!isEmpty(value) && field.fieldType === "NUMBER") {
|
|
37507
38182
|
const text = String(value);
|
|
37508
|
-
|
|
38183
|
+
const decimal = parseExactDecimal(text);
|
|
38184
|
+
if (decimal === null) {
|
|
37509
38185
|
return { ok: false, code: "ERR_TYPE_NUMBER", message: `${field.code} \u306F\u6570\u5024\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044` };
|
|
37510
38186
|
}
|
|
37511
38187
|
if (field.minValue != null && compareDecimal(text, field.minValue) < 0) {
|
|
@@ -37514,6 +38190,17 @@ function validateAndNormalizeDmlValue(raw, field) {
|
|
|
37514
38190
|
if (field.maxValue != null && compareDecimal(text, field.maxValue) > 0) {
|
|
37515
38191
|
return { ok: false, code: "ERR_RANGE_MAX", message: `${field.code} \u306F ${field.maxValue} \u4EE5\u4E0B\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044` };
|
|
37516
38192
|
}
|
|
38193
|
+
if (numberPrecision !== void 0) {
|
|
38194
|
+
const { integerDigits } = exactDecimalDigitCounts(decimal);
|
|
38195
|
+
const integerBudget = numberPrecision.digits - numberPrecision.decimalPlaces;
|
|
38196
|
+
if (integerDigits > integerBudget) {
|
|
38197
|
+
return {
|
|
38198
|
+
ok: false,
|
|
38199
|
+
code: "ERR_NUMBER_INTEGER_DIGITS",
|
|
38200
|
+
message: `${field.code} \u306E\u6574\u6570\u90E8\u306F ${integerDigits} \u6841\u3067\u3059\u3002\u8A31\u5BB9\u306F ${integerBudget} \u6841\u307E\u3067\u3067\u3059 (digits=${numberPrecision.digits}, decimalPlaces=${numberPrecision.decimalPlaces})`
|
|
38201
|
+
};
|
|
38202
|
+
}
|
|
38203
|
+
}
|
|
37517
38204
|
}
|
|
37518
38205
|
if (!isEmpty(value) && (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME")) {
|
|
37519
38206
|
if (!isValidTemporal(String(value), field.fieldType)) {
|
|
@@ -37541,7 +38228,8 @@ function validateAndNormalizeDmlValue(raw, field) {
|
|
|
37541
38228
|
}
|
|
37542
38229
|
function rawScalarText(raw) {
|
|
37543
38230
|
if (raw == null) return "";
|
|
37544
|
-
if (isSqlValue(raw) &&
|
|
38231
|
+
if (isSqlValue(raw) && raw.type === "NUMBER") return numberLiteralText(raw);
|
|
38232
|
+
if (isSqlValue(raw) && raw.type === "STRING") return raw.value;
|
|
37545
38233
|
return typeof raw === "string" || typeof raw === "number" ? String(raw) : "";
|
|
37546
38234
|
}
|
|
37547
38235
|
function isValidTemporalInput(value, type) {
|
|
@@ -37591,34 +38279,6 @@ function isEmpty(value) {
|
|
|
37591
38279
|
function typeCode(type) {
|
|
37592
38280
|
return type === "NUMBER" ? "ERR_TYPE_NUMBER" : "ERR_TYPE_DATE";
|
|
37593
38281
|
}
|
|
37594
|
-
function isFiniteDecimal(value) {
|
|
37595
|
-
return /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(value.trim());
|
|
37596
|
-
}
|
|
37597
|
-
function compareDecimal(left, right) {
|
|
37598
|
-
const normalize = (input) => {
|
|
37599
|
-
let s = input.trim();
|
|
37600
|
-
let sign = 1;
|
|
37601
|
-
if (s.startsWith("-")) {
|
|
37602
|
-
sign = -1;
|
|
37603
|
-
s = s.slice(1);
|
|
37604
|
-
} else if (s.startsWith("+")) s = s.slice(1);
|
|
37605
|
-
let [whole, fraction = ""] = s.split(".");
|
|
37606
|
-
whole = (whole || "0").replace(/^0+(?=\d)/, "");
|
|
37607
|
-
fraction = fraction.replace(/0+$/, "");
|
|
37608
|
-
if (/^0*$/.test(whole) && fraction === "") sign = 1;
|
|
37609
|
-
return { sign, whole, fraction };
|
|
37610
|
-
};
|
|
37611
|
-
const a = normalize(left);
|
|
37612
|
-
const b = normalize(right);
|
|
37613
|
-
if (a.sign !== b.sign) return a.sign < b.sign ? -1 : 1;
|
|
37614
|
-
const direction = a.sign;
|
|
37615
|
-
if (a.whole.length !== b.whole.length) return a.whole.length < b.whole.length ? -direction : direction;
|
|
37616
|
-
if (a.whole !== b.whole) return a.whole < b.whole ? -direction : direction;
|
|
37617
|
-
const width = Math.max(a.fraction.length, b.fraction.length);
|
|
37618
|
-
const af = a.fraction.padEnd(width, "0");
|
|
37619
|
-
const bf = b.fraction.padEnd(width, "0");
|
|
37620
|
-
return af === bf ? 0 : af < bf ? -direction : direction;
|
|
37621
|
-
}
|
|
37622
38282
|
function isValidTemporal(value, type) {
|
|
37623
38283
|
if (type === "TIME") {
|
|
37624
38284
|
const m2 = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
|
|
@@ -37646,32 +38306,33 @@ var VALIDATION_META_COLUMNS = [
|
|
|
37646
38306
|
"$err_code",
|
|
37647
38307
|
"$err_message"
|
|
37648
38308
|
];
|
|
37649
|
-
function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber) {
|
|
38309
|
+
function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true) {
|
|
37650
38310
|
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
37651
38311
|
const errors = [];
|
|
37652
38312
|
const invalid = /* @__PURE__ */ new Set();
|
|
38313
|
+
let firstEvaluationError;
|
|
37653
38314
|
for (const candidate of candidates) {
|
|
37654
38315
|
candidate.record ??= {};
|
|
37655
|
-
const rowErrors = [...candidate.preErrors];
|
|
38316
|
+
const rowErrors = includePreErrors ? [...candidate.preErrors] : [];
|
|
37656
38317
|
for (const code of targetFields) {
|
|
37657
|
-
const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code));
|
|
38318
|
+
const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
|
|
37658
38319
|
if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
|
|
37659
38320
|
else candidate.record[code] = { value: result.value };
|
|
37660
38321
|
}
|
|
37661
|
-
if (candidate.mode === "create") {
|
|
38322
|
+
if (validateMissingCreateFields && candidate.mode === "create") {
|
|
37662
38323
|
for (const info of fieldInfos) {
|
|
37663
38324
|
if (info.inSubtable) continue;
|
|
37664
38325
|
if (candidate.payload.has(info.code)) continue;
|
|
37665
38326
|
const emptyDefault = isEmptyDmlValue(info.defaultValue);
|
|
37666
38327
|
if (!emptyDefault) {
|
|
37667
|
-
const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info);
|
|
38328
|
+
const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info, numberPrecision);
|
|
37668
38329
|
if (!defaultResult.ok) rowErrors.push({
|
|
37669
38330
|
field: info.code,
|
|
37670
38331
|
code: defaultResult.code,
|
|
37671
38332
|
message: `\u65E2\u5B9A\u5024: ${defaultResult.message}`
|
|
37672
38333
|
});
|
|
37673
38334
|
} else {
|
|
37674
|
-
const emptyResult = validateAndNormalizeDmlValue("", info);
|
|
38335
|
+
const emptyResult = validateAndNormalizeDmlValue("", info, numberPrecision);
|
|
37675
38336
|
if (!emptyResult.ok) {
|
|
37676
38337
|
rowErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
|
|
37677
38338
|
} else if (info.required) {
|
|
@@ -37680,6 +38341,23 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
37680
38341
|
}
|
|
37681
38342
|
}
|
|
37682
38343
|
}
|
|
38344
|
+
if (checkGroups.length > 0) {
|
|
38345
|
+
const row = candidate.evaluationRow ?? Object.fromEntries(
|
|
38346
|
+
[...candidate.payload].map(([field, value]) => [field, renderValidationValue(value)])
|
|
38347
|
+
);
|
|
38348
|
+
const types = candidate.evaluationFieldTypes;
|
|
38349
|
+
const resolveType = (field) => {
|
|
38350
|
+
const qualified = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
|
|
38351
|
+
return types?.get(qualified) ?? types?.get(field.field);
|
|
38352
|
+
};
|
|
38353
|
+
try {
|
|
38354
|
+
for (const custom2 of evaluateCustomChecks(checkGroups, row, resolveType)) {
|
|
38355
|
+
rowErrors.push({ field: "", code: "ERR_CHECK", message: custom2.message });
|
|
38356
|
+
}
|
|
38357
|
+
} catch (error51) {
|
|
38358
|
+
firstEvaluationError ??= error51;
|
|
38359
|
+
}
|
|
38360
|
+
}
|
|
37683
38361
|
if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
|
|
37684
38362
|
for (const error51 of rowErrors) {
|
|
37685
38363
|
const row = {};
|
|
@@ -37693,13 +38371,15 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
37693
38371
|
errors.push(row);
|
|
37694
38372
|
}
|
|
37695
38373
|
}
|
|
38374
|
+
if (firstEvaluationError !== void 0) throw firstEvaluationError;
|
|
37696
38375
|
return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid };
|
|
37697
38376
|
}
|
|
37698
38377
|
function renderValidationValue(value) {
|
|
37699
38378
|
if (value == null) return "";
|
|
37700
38379
|
if (typeof value === "object" && "type" in value) {
|
|
37701
38380
|
const sql = value;
|
|
37702
|
-
if (sql.type === "
|
|
38381
|
+
if (sql.type === "NUMBER") return sql.raw ?? String(sql.value ?? "");
|
|
38382
|
+
if (sql.type === "STRING") return String(sql.value ?? "");
|
|
37703
38383
|
if (sql.type === "ARRAY") return JSON.stringify(sql.elements?.map((e) => e.value) ?? []);
|
|
37704
38384
|
}
|
|
37705
38385
|
if (Array.isArray(value)) return JSON.stringify(value);
|
|
@@ -37941,6 +38621,7 @@ function createEmptyMetrics() {
|
|
|
37941
38621
|
putCalls: 0,
|
|
37942
38622
|
deleteCalls: 0,
|
|
37943
38623
|
fieldCalls: 0,
|
|
38624
|
+
numberPrecisionCalls: 0,
|
|
37944
38625
|
appsCalls: 0,
|
|
37945
38626
|
processStatusCalls: 0,
|
|
37946
38627
|
cursorCreateCalls: 0,
|
|
@@ -38026,6 +38707,10 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
38026
38707
|
metrics.fieldCalls += 1;
|
|
38027
38708
|
return client.getFields(appId);
|
|
38028
38709
|
},
|
|
38710
|
+
getNumberPrecision: (appId) => {
|
|
38711
|
+
metrics.numberPrecisionCalls += 1;
|
|
38712
|
+
return client.getNumberPrecision(appId);
|
|
38713
|
+
},
|
|
38029
38714
|
getProcessStatuses: (appId) => {
|
|
38030
38715
|
metrics.processStatusCalls += 1;
|
|
38031
38716
|
return client.getProcessStatuses(appId);
|
|
@@ -38293,7 +38978,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
38293
38978
|
const first = resolvedStmt2.expr.query.columns[0];
|
|
38294
38979
|
const numeric = first?.type === "ARITH_COL" || first?.type === "ARITH_AGG_COL" || first?.type === "WINDOW_COL" || first?.type === "AGGREGATE" && (first.func === "COUNT" || first.func === "SUM" || first.func === "AVG");
|
|
38295
38980
|
const numberValue = numeric ? Number(value) : Number.NaN;
|
|
38296
|
-
variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue } : { type: "string", value });
|
|
38981
|
+
variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue, raw: value } : { type: "string", value });
|
|
38297
38982
|
} catch (e) {
|
|
38298
38983
|
if (e instanceof ScalarSubqueryError) {
|
|
38299
38984
|
throw new Error(`ArgumentError: ${e.message}`);
|
|
@@ -38311,7 +38996,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
|
|
|
38311
38996
|
variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
|
|
38312
38997
|
} else {
|
|
38313
38998
|
const value = evaluateScalarExpr(stmt.default);
|
|
38314
|
-
variables.set(stmt.name, {
|
|
38999
|
+
variables.set(stmt.name, {
|
|
39000
|
+
type: "string",
|
|
39001
|
+
value: value.type === "number" ? value.raw ?? String(value.value) : value.value
|
|
39002
|
+
});
|
|
38315
39003
|
}
|
|
38316
39004
|
return {};
|
|
38317
39005
|
}
|
|
@@ -38487,7 +39175,7 @@ function evaluateScalarExpr(expr) {
|
|
|
38487
39175
|
case "STRING":
|
|
38488
39176
|
return { type: "string", value: expr.value };
|
|
38489
39177
|
case "NUMBER":
|
|
38490
|
-
return { type: "number", value: expr.value };
|
|
39178
|
+
return { type: "number", value: expr.value, raw: numberLiteralText(expr) };
|
|
38491
39179
|
case "KINTONE_FUNC":
|
|
38492
39180
|
return { type: "string", value: resolveKintoneFunc(expr.name) };
|
|
38493
39181
|
case "STRING_FUNC":
|
|
@@ -38497,7 +39185,7 @@ function evaluateScalarExpr(expr) {
|
|
|
38497
39185
|
if (!Number.isFinite(value)) {
|
|
38498
39186
|
throw new Error("ArgumentError: SET scalar arithmetic produced a non-finite number.");
|
|
38499
39187
|
}
|
|
38500
|
-
return { type: "number", value };
|
|
39188
|
+
return { type: "number", value, raw: String(value) };
|
|
38501
39189
|
}
|
|
38502
39190
|
}
|
|
38503
39191
|
}
|
|
@@ -38512,7 +39200,7 @@ function resolveVariableRefs(node, variables) {
|
|
|
38512
39200
|
if (value === void 0) {
|
|
38513
39201
|
throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
|
|
38514
39202
|
}
|
|
38515
|
-
return value.type === "number" ? { type: "NUMBER", value: value.value } : { type: "STRING", value: value.value };
|
|
39203
|
+
return value.type === "number" ? { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) } : { type: "STRING", value: value.value };
|
|
38516
39204
|
}
|
|
38517
39205
|
return Object.fromEntries(
|
|
38518
39206
|
Object.entries(obj).map(([key, value]) => [key, resolveVariableRefs(value, variables)])
|
|
@@ -38578,7 +39266,7 @@ async function evalAssertOperand(operand, client, options, cacheContext, tempTab
|
|
|
38578
39266
|
case "VARIABLE":
|
|
38579
39267
|
throw new Error(`ParseError: unresolved batch variable @${operand.name}.`);
|
|
38580
39268
|
case "NUMBER":
|
|
38581
|
-
return
|
|
39269
|
+
return numberLiteralText(operand);
|
|
38582
39270
|
case "STRING":
|
|
38583
39271
|
return operand.value;
|
|
38584
39272
|
case "ARITH":
|
|
@@ -38740,7 +39428,7 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
|
|
|
38740
39428
|
}
|
|
38741
39429
|
} else if (column.type === "STRFUNC_COL") {
|
|
38742
39430
|
semantics = stringFunctionColumnMeta(column.expr).semantics;
|
|
38743
|
-
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL") {
|
|
39431
|
+
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL" || column.type === "SCALAR_VALUE_COL") {
|
|
38744
39432
|
semantics = syntheticSemantics("string");
|
|
38745
39433
|
}
|
|
38746
39434
|
if (semantics) aliases.set(column.alias, semantics);
|
|
@@ -38855,10 +39543,19 @@ function arithHasFieldRef(node) {
|
|
|
38855
39543
|
return false;
|
|
38856
39544
|
}
|
|
38857
39545
|
function stringFuncArgHasFieldRef(arg) {
|
|
38858
|
-
if (arg.type === "FIELD_REF") return true;
|
|
38859
|
-
if (arg.type === "ARITH") return arithHasFieldRef(arg);
|
|
38860
|
-
if (arg.type === "STRING_FUNC") return stringFuncHasFieldRef(arg);
|
|
38861
39546
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
|
|
39547
|
+
return scalarValueHasFieldRef(arg);
|
|
39548
|
+
}
|
|
39549
|
+
function scalarValueHasFieldRef(expr) {
|
|
39550
|
+
if (expr.type === "FIELD") return true;
|
|
39551
|
+
if (expr.type === "STRING_FUNC") return stringFuncHasFieldRef(expr);
|
|
39552
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
39553
|
+
return scalarValueHasFieldRef(expr.left) || scalarValueHasFieldRef(expr.right);
|
|
39554
|
+
}
|
|
39555
|
+
if (expr.type === "CASE_WHEN") {
|
|
39556
|
+
const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
|
|
39557
|
+
return results.some((result) => result.type !== "ARRAY" && (result.type === "FIELD_REF" || result.type === "ARITH" ? arithHasFieldRef(result) : scalarValueHasFieldRef(result)));
|
|
39558
|
+
}
|
|
38862
39559
|
return false;
|
|
38863
39560
|
}
|
|
38864
39561
|
function stringFuncHasFieldRef(expr) {
|
|
@@ -38879,6 +39576,11 @@ function validateNoFromColumns(stmt) {
|
|
|
38879
39576
|
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
38880
39577
|
}
|
|
38881
39578
|
break;
|
|
39579
|
+
case "SCALAR_VALUE_COL":
|
|
39580
|
+
if (scalarValueHasFieldRef(col.expr)) {
|
|
39581
|
+
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
39582
|
+
}
|
|
39583
|
+
break;
|
|
38882
39584
|
case "WINDOW_COL":
|
|
38883
39585
|
if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
|
|
38884
39586
|
throw new Error("ArgumentError: field reference is not allowed without FROM.");
|
|
@@ -39165,8 +39867,26 @@ function collectStringFuncAggregateRefs(expr, out) {
|
|
|
39165
39867
|
for (const arg of expr.args) {
|
|
39166
39868
|
if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
|
|
39167
39869
|
collectAggregateOperandRefs(arg, out);
|
|
39168
|
-
} else
|
|
39169
|
-
|
|
39870
|
+
} else {
|
|
39871
|
+
collectScalarAggregateRefs(arg, out);
|
|
39872
|
+
}
|
|
39873
|
+
}
|
|
39874
|
+
}
|
|
39875
|
+
function collectScalarAggregateRefs(expr, out) {
|
|
39876
|
+
if (expr.type === "STRING_FUNC") {
|
|
39877
|
+
collectStringFuncAggregateRefs(expr, out);
|
|
39878
|
+
return;
|
|
39879
|
+
}
|
|
39880
|
+
if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
|
|
39881
|
+
collectScalarAggregateRefs(expr.left, out);
|
|
39882
|
+
collectScalarAggregateRefs(expr.right, out);
|
|
39883
|
+
return;
|
|
39884
|
+
}
|
|
39885
|
+
if (expr.type === "CASE_WHEN") {
|
|
39886
|
+
const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
|
|
39887
|
+
for (const result of results) {
|
|
39888
|
+
if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
|
|
39889
|
+
else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
|
|
39170
39890
|
}
|
|
39171
39891
|
}
|
|
39172
39892
|
}
|
|
@@ -39179,6 +39899,8 @@ function collectSelectAggregateSortRefs(columns) {
|
|
|
39179
39899
|
collectAggregateOperandRefs(column.expr, refs);
|
|
39180
39900
|
} else if (column.type === "STRFUNC_COL") {
|
|
39181
39901
|
collectStringFuncAggregateRefs(column.expr, refs);
|
|
39902
|
+
} else if (column.type === "SCALAR_VALUE_COL") {
|
|
39903
|
+
collectScalarAggregateRefs(column.expr, refs);
|
|
39182
39904
|
}
|
|
39183
39905
|
}
|
|
39184
39906
|
return refs;
|
|
@@ -39344,10 +40066,11 @@ function stringFunctionColumnMeta(expr) {
|
|
|
39344
40066
|
function caseResultColumnMeta(result, resolveField2) {
|
|
39345
40067
|
if (result.type === "STRING") return syntheticColumnMeta("string");
|
|
39346
40068
|
if (result.type === "ARRAY") return unsupportedColumnMeta();
|
|
39347
|
-
if (result.type === "NUMBER" || result.type === "ARITH") return syntheticColumnMeta("number");
|
|
40069
|
+
if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
|
|
39348
40070
|
if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
|
|
39349
|
-
|
|
39350
|
-
return
|
|
40071
|
+
if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();
|
|
40072
|
+
if (result.type === "FIELD") return resolveField2(result) ?? unknownStringColumnMeta();
|
|
40073
|
+
return unknownStringColumnMeta();
|
|
39351
40074
|
}
|
|
39352
40075
|
function mergeExpressionColumnMeta(candidates) {
|
|
39353
40076
|
if (candidates.length === 0) return unknownStringColumnMeta();
|
|
@@ -39449,7 +40172,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
|
|
|
39449
40172
|
}
|
|
39450
40173
|
} else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
|
|
39451
40174
|
meta3 = syntheticColumnMeta("number");
|
|
39452
|
-
} else if (column.type === "LITERAL_COL") {
|
|
40175
|
+
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") {
|
|
39453
40176
|
meta3 = syntheticColumnMeta("string");
|
|
39454
40177
|
} else if (column.type === "STRFUNC_COL") {
|
|
39455
40178
|
meta3 = stringFunctionColumnMeta(column.expr);
|
|
@@ -39861,8 +40584,8 @@ async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, pa
|
|
|
39861
40584
|
}
|
|
39862
40585
|
var UPSERT_IN_CHUNK_SIZE = 50;
|
|
39863
40586
|
function normalizeKeyPart(v) {
|
|
39864
|
-
const
|
|
39865
|
-
if (
|
|
40587
|
+
const decimal = parseExactDecimal(v);
|
|
40588
|
+
if (decimal !== null) return JSON.stringify(decimal);
|
|
39866
40589
|
return v;
|
|
39867
40590
|
}
|
|
39868
40591
|
function upsertCompositeKey(parts) {
|
|
@@ -40014,6 +40737,7 @@ var optionOrderCache = /* @__PURE__ */ new Map();
|
|
|
40014
40737
|
var sortKindCache = /* @__PURE__ */ new Map();
|
|
40015
40738
|
var fieldInfoCache = /* @__PURE__ */ new Map();
|
|
40016
40739
|
var processStatusCache = /* @__PURE__ */ new Map();
|
|
40740
|
+
var numberPrecisionCache = /* @__PURE__ */ new Map();
|
|
40017
40741
|
function getScopedCacheValue(root, cacheContext, appId) {
|
|
40018
40742
|
return root.get(cacheContext)?.get(appId);
|
|
40019
40743
|
}
|
|
@@ -40035,6 +40759,13 @@ async function getFieldsCached(appId, client, cacheContext) {
|
|
|
40035
40759
|
setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
|
|
40036
40760
|
return loading;
|
|
40037
40761
|
}
|
|
40762
|
+
async function getNumberPrecisionCached(appId, client, cacheContext) {
|
|
40763
|
+
const cached2 = getScopedCacheValue(numberPrecisionCache, cacheContext, appId);
|
|
40764
|
+
if (cached2) return cached2;
|
|
40765
|
+
const loading = client.getNumberPrecision(appId);
|
|
40766
|
+
setScopedCacheValue(numberPrecisionCache, cacheContext, appId, loading);
|
|
40767
|
+
return loading;
|
|
40768
|
+
}
|
|
40038
40769
|
async function getProcessStatusesCached(appId, client, cacheContext) {
|
|
40039
40770
|
const cached2 = getScopedCacheValue(processStatusCache, cacheContext, appId);
|
|
40040
40771
|
if (cached2) return cached2;
|
|
@@ -40148,7 +40879,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
|
|
|
40148
40879
|
if (column.type === "FIELD") meta3 = resolveField2(aggregateFieldRef(column.field));
|
|
40149
40880
|
else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
|
|
40150
40881
|
meta3 = syntheticColumnMeta("number");
|
|
40151
|
-
} else if (column.type === "LITERAL_COL") meta3 = syntheticColumnMeta("string");
|
|
40882
|
+
} else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta3 = syntheticColumnMeta("string");
|
|
40152
40883
|
else if (column.type === "STRFUNC_COL") meta3 = stringFunctionColumnMeta(column.expr);
|
|
40153
40884
|
else if (column.type === "SCALAR_SUBQUERY_COL") meta3 = unknownStringColumnMeta();
|
|
40154
40885
|
else if (column.type === "CASE_COL") {
|
|
@@ -40309,6 +41040,23 @@ async function loadWritableTopLevelDmlFields(appId, targetFields, client, cacheC
|
|
|
40309
41040
|
assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos);
|
|
40310
41041
|
return fieldInfos;
|
|
40311
41042
|
}
|
|
41043
|
+
async function loadNumberPrecisionForTargets(appId, targetFields, fieldInfos, client, cacheContext) {
|
|
41044
|
+
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
41045
|
+
return targetFields.some((code) => infoByCode.get(code)?.fieldType === "NUMBER") ? getNumberPrecisionCached(appId, client, cacheContext) : void 0;
|
|
41046
|
+
}
|
|
41047
|
+
function assertValidDmlRecords(records, targetFields, fieldInfos, numberPrecision) {
|
|
41048
|
+
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
41049
|
+
records.forEach((record2, rowIndex) => {
|
|
41050
|
+
for (const code of targetFields) {
|
|
41051
|
+
const info = infoByCode.get(code);
|
|
41052
|
+
const result = validateAndNormalizeDmlValue(record2[code]?.value ?? "", info, numberPrecision);
|
|
41053
|
+
if (!result.ok) {
|
|
41054
|
+
throw new Error(`DmlValidationError: ${result.code} ${result.message} (row=${rowIndex + 1}, field=${code})`);
|
|
41055
|
+
}
|
|
41056
|
+
record2[code] = { value: result.value };
|
|
41057
|
+
}
|
|
41058
|
+
});
|
|
41059
|
+
}
|
|
40312
41060
|
async function executeDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
40313
41061
|
return (await prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber)).result;
|
|
40314
41062
|
}
|
|
@@ -40319,7 +41067,7 @@ var RejectLimitExceededError = class extends Error {
|
|
|
40319
41067
|
this.name = "RejectLimitExceededError";
|
|
40320
41068
|
}
|
|
40321
41069
|
};
|
|
40322
|
-
async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
|
|
41070
|
+
async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber, validateMissingCreateFields = true, includePreErrors = true) {
|
|
40323
41071
|
const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
|
|
40324
41072
|
const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
|
|
40325
41073
|
if (new Set(payloadFields).size !== payloadFields.length) {
|
|
@@ -40336,6 +41084,13 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
40336
41084
|
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40337
41085
|
}
|
|
40338
41086
|
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
41087
|
+
const numberPrecision = await loadNumberPrecisionForTargets(
|
|
41088
|
+
stmt.appId,
|
|
41089
|
+
targetFields,
|
|
41090
|
+
fieldInfos,
|
|
41091
|
+
client,
|
|
41092
|
+
cacheContext
|
|
41093
|
+
);
|
|
40339
41094
|
const candidates = await materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode);
|
|
40340
41095
|
const { errors, invalidRows, invalidRowNumbers } = validateDmlCandidates(
|
|
40341
41096
|
candidates,
|
|
@@ -40343,7 +41098,11 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
40343
41098
|
payloadFields,
|
|
40344
41099
|
targetFields,
|
|
40345
41100
|
fieldInfos,
|
|
40346
|
-
statementNumber
|
|
41101
|
+
statementNumber,
|
|
41102
|
+
numberPrecision,
|
|
41103
|
+
stmt.checkGroups ?? [],
|
|
41104
|
+
validateMissingCreateFields,
|
|
41105
|
+
includePreErrors
|
|
40347
41106
|
);
|
|
40348
41107
|
const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
|
|
40349
41108
|
const result = {
|
|
@@ -40453,15 +41212,33 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
|
|
|
40453
41212
|
async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode) {
|
|
40454
41213
|
if (stmt.type === "UPDATE") return materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables);
|
|
40455
41214
|
let rows;
|
|
41215
|
+
let sourceRows;
|
|
41216
|
+
let evaluationTypes;
|
|
40456
41217
|
if (stmt.type === "INSERT" || stmt.type === "UPSERT") {
|
|
41218
|
+
assertInsertCheckRefs(stmt, stmt.fields);
|
|
41219
|
+
evaluationTypes = new Map(stmt.fields.map((field) => [field, infoByCode.get(field)?.fieldType ?? ""]));
|
|
41220
|
+
assertCheckComparisonTypes(stmt, evaluationTypes);
|
|
40457
41221
|
rows = stmt.values.map((row) => row.map(
|
|
40458
41222
|
(value, i) => value.type === "CASE_VALUE" ? evalCaseWhenValue(value.expr, {}, infoByCode.get(stmt.fields[i])?.fieldType) : value
|
|
40459
41223
|
));
|
|
40460
41224
|
} else {
|
|
40461
|
-
const selectResult = tempTables && tempTables.size > 0 ? await executeQueryWithCte(stmt.select, client, { ...options, onLimitReached: "error" }, tempTables, cacheContext) : await executeSelect(stmt.select, client, { ...options, onLimitReached: "error" }, cacheContext);
|
|
40462
|
-
|
|
41225
|
+
const selectResult = tempTables && tempTables.size > 0 ? await executeQueryWithCte(stmt.select, client, { ...options, onLimitReached: "error" }, tempTables, cacheContext) : await executeSelect(stmt.select, client, { ...options, onLimitReached: "error" }, cacheContext, void 0, true);
|
|
41226
|
+
const hasChecks = (stmt.checkGroups?.length ?? 0) > 0;
|
|
41227
|
+
if (selectResult.columns.length < stmt.fields.length || !hasChecks && selectResult.columns.length !== stmt.fields.length) {
|
|
40463
41228
|
throw new Error(`SELECT \u306E\u5217\u6570\uFF08${selectResult.columns.length}\uFF09\u3068 DML \u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u6570\uFF08${stmt.fields.length}\uFF09\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093`);
|
|
40464
41229
|
}
|
|
41230
|
+
if (hasChecks && new Set(selectResult.columns).size !== selectResult.columns.length) {
|
|
41231
|
+
throw customCheckParseError("CHECK \u4ED8\u304D DML \u30BD\u30FC\u30B9 SELECT \u306E\u51FA\u529B\u540D\u306F\u4E00\u610F\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
41232
|
+
}
|
|
41233
|
+
assertInsertCheckRefs(stmt, selectResult.columns);
|
|
41234
|
+
sourceRows = selectResult.rows;
|
|
41235
|
+
const meta3 = materializedMetaBySelectResult.get(selectResult);
|
|
41236
|
+
evaluationTypes = new Map(selectResult.columns.map((column) => {
|
|
41237
|
+
const columnMeta = meta3?.get(column);
|
|
41238
|
+
const type = columnMeta?.fieldType ?? (columnMeta?.semantics?.compareMode === "number" || columnMeta?.sortKind === "number" ? "NUMBER" : "SINGLE_LINE_TEXT");
|
|
41239
|
+
return [column, type];
|
|
41240
|
+
}));
|
|
41241
|
+
assertCheckComparisonTypes(stmt, evaluationTypes);
|
|
40465
41242
|
rows = selectResult.rows.map((row) => selectResult.columns.map((column) => row[column] ?? ""));
|
|
40466
41243
|
}
|
|
40467
41244
|
const candidates = rows.map((values, index) => ({
|
|
@@ -40470,7 +41247,11 @@ async function materializeValidationCandidates(stmt, operation, client, options,
|
|
|
40470
41247
|
mode: "create",
|
|
40471
41248
|
payload: new Map(stmt.fields.map((field, i) => [field, values[i]])),
|
|
40472
41249
|
preErrors: [],
|
|
40473
|
-
record: {}
|
|
41250
|
+
record: {},
|
|
41251
|
+
evaluationRow: sourceRows?.[index] ?? Object.fromEntries(
|
|
41252
|
+
stmt.fields.map((field, i) => [field, renderValidationValue(values[i])])
|
|
41253
|
+
),
|
|
41254
|
+
evaluationFieldTypes: evaluationTypes
|
|
40474
41255
|
}));
|
|
40475
41256
|
if (stmt.type !== "UPSERT" && stmt.type !== "UPSERT_SELECT") return candidates;
|
|
40476
41257
|
for (const key of stmt.keyFields) {
|
|
@@ -40499,26 +41280,74 @@ async function materializeValidationCandidates(stmt, operation, client, options,
|
|
|
40499
41280
|
});
|
|
40500
41281
|
return candidates;
|
|
40501
41282
|
}
|
|
41283
|
+
function checkRefs(stmt) {
|
|
41284
|
+
return stmt.checkGroups ? collectCheckFieldRefs(stmt.checkGroups) : [];
|
|
41285
|
+
}
|
|
41286
|
+
function assertInsertCheckRefs(stmt, available) {
|
|
41287
|
+
const names = new Set(available);
|
|
41288
|
+
for (const ref of checkRefs(stmt)) {
|
|
41289
|
+
if (ref.tableAlias !== null) {
|
|
41290
|
+
throw customCheckParseError(`CHECK \u306E\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.tableAlias}.${ref.field} \u306F\u3053\u306E\u8A55\u4FA1\u884C\u3067\u306F\u4FEE\u98FE\u3067\u304D\u307E\u305B\u3093`);
|
|
41291
|
+
}
|
|
41292
|
+
if (!names.has(ref.field)) {
|
|
41293
|
+
throw customCheckParseError(`CHECK \u306E\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u8A55\u4FA1\u884C\u306B\u5B58\u5728\u3057\u307E\u305B\u3093`);
|
|
41294
|
+
}
|
|
41295
|
+
}
|
|
41296
|
+
}
|
|
41297
|
+
var CHECK_UNSUPPORTED_COMPARISON_TYPES = /* @__PURE__ */ new Set([
|
|
41298
|
+
"CHECK_BOX",
|
|
41299
|
+
"MULTI_SELECT",
|
|
41300
|
+
"USER_SELECT",
|
|
41301
|
+
"ORGANIZATION_SELECT",
|
|
41302
|
+
"GROUP_SELECT",
|
|
41303
|
+
"FILE",
|
|
41304
|
+
"KSQL_ARRAY"
|
|
41305
|
+
]);
|
|
41306
|
+
function assertCheckComparisonTypes(stmt, types) {
|
|
41307
|
+
if (!stmt.checkGroups) return;
|
|
41308
|
+
for (const ref of collectCheckComparisonFieldRefs(stmt.checkGroups)) {
|
|
41309
|
+
const key = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
|
|
41310
|
+
const type = types.get(key) ?? types.get(ref.field);
|
|
41311
|
+
if (CHECK_UNSUPPORTED_COMPARISON_TYPES.has(type ?? "")) {
|
|
41312
|
+
throw customCheckParseError(`CHECK \u306E\u6BD4\u8F03\u3067\u306F ${type} \u30D5\u30A3\u30FC\u30EB\u30C9 ${key} \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
|
|
41313
|
+
}
|
|
41314
|
+
}
|
|
41315
|
+
}
|
|
40502
41316
|
async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables) {
|
|
40503
41317
|
if (stmt.from) return materializeUpdateFromValidationCandidates(stmt, stmt.from, client, options, cacheContext, tempTables);
|
|
40504
41318
|
await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
|
|
40505
41319
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
41320
|
+
const checkTargetFields = assertUpdateCheckRefs(stmt, fieldTypes);
|
|
41321
|
+
assertCheckComparisonTypes(stmt, updateEvaluationTypes(fieldTypes, stmt.appId));
|
|
40506
41322
|
let records;
|
|
41323
|
+
let evaluationById = /* @__PURE__ */ new Map();
|
|
40507
41324
|
if (hasRowDependentAssignment(stmt)) {
|
|
40508
41325
|
const getParams = updateToGetQueryForArith(stmt);
|
|
40509
|
-
const
|
|
41326
|
+
const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields])];
|
|
41327
|
+
const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
|
|
40510
41328
|
maxRecords: options.maxRecords ?? 1e4,
|
|
40511
41329
|
parallel: options.fetchParallel ?? 1,
|
|
40512
41330
|
onLimit: "error"
|
|
40513
41331
|
});
|
|
41332
|
+
evaluationById = new Map(resolved.records.map((record2) => [Number(record2["$id"]?.value), record2]));
|
|
40514
41333
|
records = updateToPutBatchesArith(stmt, resolved.records, fieldTypes).flatMap((batch) => batch.records);
|
|
40515
41334
|
} else {
|
|
40516
41335
|
const getParams = updateToGetQuery(stmt);
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
|
|
40520
|
-
|
|
40521
|
-
|
|
41336
|
+
if (checkTargetFields.length > 0) {
|
|
41337
|
+
const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields])], {
|
|
41338
|
+
maxRecords: options.maxRecords ?? 1e4,
|
|
41339
|
+
parallel: options.fetchParallel ?? 1,
|
|
41340
|
+
onLimit: "error"
|
|
41341
|
+
});
|
|
41342
|
+
evaluationById = new Map(resolved.records.map((record2) => [Number(record2["$id"]?.value), record2]));
|
|
41343
|
+
records = updateToPutBatches(stmt, [...evaluationById.keys()], fieldTypes).flatMap((batch) => batch.records);
|
|
41344
|
+
} else {
|
|
41345
|
+
const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
|
|
41346
|
+
maxRecords: options.maxRecords ?? 1e4,
|
|
41347
|
+
parallel: options.fetchParallel ?? 1
|
|
41348
|
+
});
|
|
41349
|
+
records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
|
|
41350
|
+
}
|
|
40522
41351
|
}
|
|
40523
41352
|
return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
|
|
40524
41353
|
rowNumber: index + 1,
|
|
@@ -40527,13 +41356,48 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
|
|
|
40527
41356
|
payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
|
|
40528
41357
|
preErrors: [],
|
|
40529
41358
|
record: entry.record,
|
|
40530
|
-
targetId: entry.id
|
|
41359
|
+
targetId: entry.id,
|
|
41360
|
+
evaluationRow: updateEvaluationRow(evaluationById.get(entry.id), stmt.appId),
|
|
41361
|
+
evaluationFieldTypes: updateEvaluationTypes(fieldTypes, stmt.appId)
|
|
40531
41362
|
}));
|
|
40532
41363
|
}
|
|
41364
|
+
function assertUpdateCheckRefs(stmt, targetTypes) {
|
|
41365
|
+
if (stmt.from) return [];
|
|
41366
|
+
const fields = /* @__PURE__ */ new Set();
|
|
41367
|
+
for (const ref of checkRefs(stmt)) {
|
|
41368
|
+
if (ref.tableAlias !== null && ref.tableAlias.toLowerCase() !== `app${stmt.appId}`.toLowerCase()) {
|
|
41369
|
+
throw customCheckParseError(`CHECK \u306E\u4FEE\u98FE\u5B50 ${ref.tableAlias} \u306F\u66F4\u65B0\u5148 APP${stmt.appId} \u3067\u306F\u3042\u308A\u307E\u305B\u3093`);
|
|
41370
|
+
}
|
|
41371
|
+
if (ref.field !== "$id" && !targetTypes.has(ref.field)) {
|
|
41372
|
+
throw customCheckParseError(`CHECK \u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
|
|
41373
|
+
}
|
|
41374
|
+
fields.add(ref.field);
|
|
41375
|
+
}
|
|
41376
|
+
return [...fields];
|
|
41377
|
+
}
|
|
41378
|
+
function updateEvaluationRow(record2, appId) {
|
|
41379
|
+
if (!record2) return {};
|
|
41380
|
+
const plain = flatten(record2, null);
|
|
41381
|
+
return Object.fromEntries([
|
|
41382
|
+
...Object.entries(plain),
|
|
41383
|
+
...Object.entries(plain).map(([field, value]) => [`APP${appId}.${field}`, value])
|
|
41384
|
+
]);
|
|
41385
|
+
}
|
|
41386
|
+
function updateEvaluationTypes(types, appId) {
|
|
41387
|
+
return new Map([
|
|
41388
|
+
...types,
|
|
41389
|
+
...[...types].map(([field, type]) => [`APP${appId}.${field}`, type]),
|
|
41390
|
+
["$id", "RECORD_NUMBER"],
|
|
41391
|
+
[`APP${appId}.$id`, "RECORD_NUMBER"]
|
|
41392
|
+
]);
|
|
41393
|
+
}
|
|
40533
41394
|
async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables) {
|
|
41395
|
+
const scope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
|
|
41396
|
+
assertCheckComparisonTypes(stmt, scope.evaluationTypes);
|
|
40534
41397
|
const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
|
|
40535
41398
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40536
41399
|
const records = updateFromToPutBatches(stmt, matched, fieldTypes).flatMap((batch) => batch.records);
|
|
41400
|
+
const matchedById = new Map(matched.map((pair) => [Number(pair.target["$id"]?.value), pair]));
|
|
40537
41401
|
return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
|
|
40538
41402
|
rowNumber: index + 1,
|
|
40539
41403
|
operation: "UPDATE",
|
|
@@ -40541,7 +41405,9 @@ async function materializeUpdateFromValidationCandidates(stmt, from, client, opt
|
|
|
40541
41405
|
payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
|
|
40542
41406
|
preErrors: [],
|
|
40543
41407
|
record: entry.record,
|
|
40544
|
-
targetId: entry.id
|
|
41408
|
+
targetId: entry.id,
|
|
41409
|
+
evaluationRow: updateFromEvaluationRow(matchedById.get(entry.id), stmt.appId, from.alias),
|
|
41410
|
+
evaluationFieldTypes: scope.evaluationTypes
|
|
40545
41411
|
}));
|
|
40546
41412
|
}
|
|
40547
41413
|
var UPDATE_FROM_KEY_CHUNK_SIZE = UPSERT_IN_CHUNK_SIZE;
|
|
@@ -40555,7 +41421,8 @@ var UPDATE_FROM_UNSUPPORTED_SOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
|
40555
41421
|
]);
|
|
40556
41422
|
async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables) {
|
|
40557
41423
|
const joinKind = await resolveUpdateFromTargetJoinKind(stmt, from, client, cacheContext);
|
|
40558
|
-
const
|
|
41424
|
+
const checkScope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
|
|
41425
|
+
const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : "").concat(checkScope.sourceFields))];
|
|
40559
41426
|
const requiredSourceFields = [.../* @__PURE__ */ new Set([from.joinKeyField, ...sourceFields])];
|
|
40560
41427
|
const sourceRows = await loadUpdateFromSourceRows(
|
|
40561
41428
|
from,
|
|
@@ -40567,6 +41434,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
|
|
|
40567
41434
|
tempTables
|
|
40568
41435
|
);
|
|
40569
41436
|
const sourceByKey = /* @__PURE__ */ new Map();
|
|
41437
|
+
const sourceQueryByKey = /* @__PURE__ */ new Map();
|
|
40570
41438
|
for (const row of sourceRows) {
|
|
40571
41439
|
if (!Object.prototype.hasOwnProperty.call(row, from.joinKeyField)) {
|
|
40572
41440
|
throw new Error(`ArgumentError: UPDATE ... FROM source column ${from.joinKeyField} does not exist.`);
|
|
@@ -40576,15 +41444,16 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
|
|
|
40576
41444
|
throw new Error(`ArgumentError: UPDATE ... FROM source has multiple rows for normalized key ${key}.`);
|
|
40577
41445
|
}
|
|
40578
41446
|
sourceByKey.set(key, row);
|
|
41447
|
+
sourceQueryByKey.set(key, String(row[from.joinKeyField]).trim());
|
|
40579
41448
|
}
|
|
40580
41449
|
if (sourceByKey.size === 0) return [];
|
|
40581
41450
|
const maxRecords2 = options.maxRecords ?? 1e4;
|
|
40582
|
-
const targetFields = collectUpdateFromTargetFields(stmt);
|
|
40583
|
-
const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter }).query;
|
|
41451
|
+
const targetFields = [.../* @__PURE__ */ new Set([...collectUpdateFromTargetFields(stmt), ...checkScope.targetFields])];
|
|
41452
|
+
const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter, checkGroups: void 0 }).query;
|
|
40584
41453
|
const targetRecords = [];
|
|
40585
41454
|
const seenTargetIds = /* @__PURE__ */ new Set();
|
|
40586
41455
|
let fetchedTargetCount = 0;
|
|
40587
|
-
for (const keys of splitChunks([...
|
|
41456
|
+
for (const keys of splitChunks([...sourceQueryByKey.values()], UPDATE_FROM_KEY_CHUNK_SIZE)) {
|
|
40588
41457
|
const keyQuery = `${from.targetJoinField} in (${keys.map(sqlQuote).join(",")})`;
|
|
40589
41458
|
const query = filterQuery ? `(${keyQuery}) and (${filterQuery})` : keyQuery;
|
|
40590
41459
|
const resolved = await fetchRecordsForSharedPlan(
|
|
@@ -40685,37 +41554,75 @@ function normalizeUpdateFromJoinKey(raw, kind, side) {
|
|
|
40685
41554
|
}
|
|
40686
41555
|
if (kind === "number" && side === "target" && raw === "") return null;
|
|
40687
41556
|
if (kind === "id") {
|
|
40688
|
-
const
|
|
40689
|
-
const id = Number(
|
|
40690
|
-
if (
|
|
41557
|
+
const text = raw.trim();
|
|
41558
|
+
const id = Number(text);
|
|
41559
|
+
if (text === "" || !Number.isSafeInteger(id) || id <= 0) {
|
|
40691
41560
|
throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a positive safe integer: ${raw}`);
|
|
40692
41561
|
}
|
|
40693
41562
|
return String(id);
|
|
40694
41563
|
}
|
|
40695
|
-
const
|
|
40696
|
-
if (
|
|
41564
|
+
const decimal = parseExactDecimal(raw);
|
|
41565
|
+
if (decimal === null) {
|
|
40697
41566
|
throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a finite decimal: ${raw}`);
|
|
40698
41567
|
}
|
|
40699
|
-
|
|
40700
|
-
|
|
40701
|
-
|
|
40702
|
-
|
|
40703
|
-
|
|
41568
|
+
return JSON.stringify(decimal);
|
|
41569
|
+
}
|
|
41570
|
+
async function executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables) {
|
|
41571
|
+
const prepared = await prepareDmlValidation(
|
|
41572
|
+
stmt,
|
|
41573
|
+
client,
|
|
41574
|
+
options,
|
|
41575
|
+
cacheContext,
|
|
41576
|
+
tempTables,
|
|
41577
|
+
1,
|
|
41578
|
+
false,
|
|
41579
|
+
false
|
|
41580
|
+
);
|
|
41581
|
+
if (prepared.result.errors.length > 0) {
|
|
41582
|
+
const first = prepared.result.errors[0];
|
|
41583
|
+
throw new Error(
|
|
41584
|
+
`DmlValidationError: ${first["$err_code"]} ${first["$err_message"]} (row=${first["$err_row"]}, field=${first["$err_field"]})`
|
|
41585
|
+
);
|
|
41586
|
+
}
|
|
41587
|
+
const candidates = prepared.candidates;
|
|
41588
|
+
const confirmOperation = stmt.type.startsWith("INSERT") ? "INSERT" : "UPDATE";
|
|
41589
|
+
if (options.confirm && candidates.length > 0) {
|
|
41590
|
+
const ok = await options.confirm(candidates.length, confirmOperation);
|
|
41591
|
+
if (!ok) throw new OperationCancelledError(confirmOperation, candidates.length);
|
|
40704
41592
|
}
|
|
40705
|
-
|
|
40706
|
-
|
|
40707
|
-
|
|
40708
|
-
|
|
40709
|
-
|
|
40710
|
-
|
|
41593
|
+
if (stmt.type === "INSERT" || stmt.type === "INSERT_SELECT") {
|
|
41594
|
+
const createdIds = [];
|
|
41595
|
+
for (let i = 0; i < candidates.length; i += 100) {
|
|
41596
|
+
const response = await client.postRecords({ app: stmt.appId, records: candidates.slice(i, i + 100).map((c) => c.record) });
|
|
41597
|
+
createdIds.push(response.ids);
|
|
41598
|
+
}
|
|
41599
|
+
return { type: "INSERT", createdIds, insertedCount: createdIds.flat().length };
|
|
41600
|
+
}
|
|
41601
|
+
if (stmt.type === "UPDATE") {
|
|
41602
|
+
const updates2 = candidates.map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
|
|
41603
|
+
for (let i = 0; i < updates2.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates2.slice(i, i + 100) });
|
|
41604
|
+
return { type: "UPDATE", updatedCount: updates2.length };
|
|
41605
|
+
}
|
|
41606
|
+
const inserts = candidates.filter((candidate) => candidate.mode === "create");
|
|
41607
|
+
const updates = candidates.filter((candidate) => candidate.mode === "update").map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
|
|
41608
|
+
let insertedCount = 0;
|
|
41609
|
+
for (let i = 0; i < inserts.length; i += 100) {
|
|
41610
|
+
const response = await client.postRecords({ app: stmt.appId, records: inserts.slice(i, i + 100).map((c) => c.record) });
|
|
41611
|
+
insertedCount += response.ids.length;
|
|
41612
|
+
}
|
|
41613
|
+
for (let i = 0; i < updates.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates.slice(i, i + 100) });
|
|
41614
|
+
return { type: "UPSERT", insertedCount, updatedCount: updates.length };
|
|
40711
41615
|
}
|
|
40712
41616
|
async function executeInsert(stmt, client, options, cacheContext) {
|
|
41617
|
+
if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
|
|
40713
41618
|
if (stmt.subtableCode) {
|
|
40714
41619
|
return executeInsertSubtable(stmt, client, options, cacheContext);
|
|
40715
41620
|
}
|
|
40716
|
-
await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
41621
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
41622
|
+
const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
|
|
40717
41623
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40718
41624
|
const batches = insertToPostBatches(stmt, fieldTypes);
|
|
41625
|
+
assertValidDmlRecords(batches.flatMap((batch) => batch.records), stmt.fields, fieldInfos, numberPrecision);
|
|
40719
41626
|
const createdIds = [];
|
|
40720
41627
|
for (const batch of batches) {
|
|
40721
41628
|
const res = await client.postRecords(batch);
|
|
@@ -40728,7 +41635,9 @@ async function executeInsert(stmt, client, options, cacheContext) {
|
|
|
40728
41635
|
};
|
|
40729
41636
|
}
|
|
40730
41637
|
async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
|
|
40731
|
-
|
|
41638
|
+
if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
|
|
41639
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
41640
|
+
const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
|
|
40732
41641
|
const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
|
|
40733
41642
|
const { rows, columns } = selectResult;
|
|
40734
41643
|
if (columns.length !== stmt.fields.length) {
|
|
@@ -40750,6 +41659,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
40750
41659
|
});
|
|
40751
41660
|
return record2;
|
|
40752
41661
|
});
|
|
41662
|
+
assertValidDmlRecords(allRecords, stmt.fields, fieldInfos, numberPrecision);
|
|
40753
41663
|
const createdIds = [];
|
|
40754
41664
|
for (let i = 0; i < allRecords.length; i += 100) {
|
|
40755
41665
|
const batch = allRecords.slice(i, i + 100);
|
|
@@ -40763,16 +41673,25 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
40763
41673
|
};
|
|
40764
41674
|
}
|
|
40765
41675
|
async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
41676
|
+
if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables);
|
|
40766
41677
|
if (stmt.subtableCode) {
|
|
40767
41678
|
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40768
41679
|
return executeUpdateSubtable(stmt, client, options, cacheContext);
|
|
40769
41680
|
}
|
|
40770
|
-
await loadWritableTopLevelDmlFields(
|
|
41681
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(
|
|
40771
41682
|
stmt.appId,
|
|
40772
41683
|
stmt.assignments.map((assignment) => assignment.field),
|
|
40773
41684
|
client,
|
|
40774
41685
|
cacheContext
|
|
40775
41686
|
);
|
|
41687
|
+
const targetFields = stmt.assignments.map((assignment) => assignment.field);
|
|
41688
|
+
const numberPrecision = await loadNumberPrecisionForTargets(
|
|
41689
|
+
stmt.appId,
|
|
41690
|
+
targetFields,
|
|
41691
|
+
fieldInfos,
|
|
41692
|
+
client,
|
|
41693
|
+
cacheContext
|
|
41694
|
+
);
|
|
40776
41695
|
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
40777
41696
|
if (stmt.from != null) {
|
|
40778
41697
|
return executeUpdateFrom(stmt, stmt.from, client, options, cacheContext, tempTables);
|
|
@@ -40790,11 +41709,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
|
40790
41709
|
{ maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
|
|
40791
41710
|
);
|
|
40792
41711
|
const records = resolved2.records;
|
|
41712
|
+
const batches2 = updateToPutBatchesArith(stmt, records, fieldTypes);
|
|
41713
|
+
assertValidDmlRecords(batches2.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
|
|
40793
41714
|
if (options.confirm) {
|
|
40794
41715
|
const ok = await options.confirm(records.length, "UPDATE");
|
|
40795
41716
|
if (!ok) throw new OperationCancelledError("UPDATE", records.length);
|
|
40796
41717
|
}
|
|
40797
|
-
const batches2 = updateToPutBatchesArith(stmt, records, fieldTypes);
|
|
40798
41718
|
for (const batch of batches2) {
|
|
40799
41719
|
await client.putRecords(batch);
|
|
40800
41720
|
}
|
|
@@ -40808,11 +41728,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
|
40808
41728
|
{ maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
|
|
40809
41729
|
);
|
|
40810
41730
|
const ids = resolved.ids;
|
|
41731
|
+
const batches = updateToPutBatches(stmt, ids, fieldTypes);
|
|
41732
|
+
assertValidDmlRecords(batches.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
|
|
40811
41733
|
if (options.confirm) {
|
|
40812
41734
|
const ok = await options.confirm(ids.length, "UPDATE");
|
|
40813
41735
|
if (!ok) throw new OperationCancelledError("UPDATE", ids.length);
|
|
40814
41736
|
}
|
|
40815
|
-
const batches = updateToPutBatches(stmt, ids, fieldTypes);
|
|
40816
41737
|
for (const batch of batches) {
|
|
40817
41738
|
await client.putRecords(batch);
|
|
40818
41739
|
}
|
|
@@ -40820,12 +41741,16 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
|
|
|
40820
41741
|
}
|
|
40821
41742
|
async function executeUpdateFrom(stmt, from, client, options, cacheContext, tempTables) {
|
|
40822
41743
|
const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
|
|
41744
|
+
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
41745
|
+
const batches = updateFromToPutBatches(stmt, matched, fieldTypes);
|
|
41746
|
+
const targetFields = stmt.assignments.map((assignment) => assignment.field);
|
|
41747
|
+
const fieldInfos = await getFieldsCached(stmt.appId, client, cacheContext);
|
|
41748
|
+
const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, targetFields, fieldInfos, client, cacheContext);
|
|
41749
|
+
assertValidDmlRecords(batches.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
|
|
40823
41750
|
if (options.confirm) {
|
|
40824
41751
|
const ok = await options.confirm(matched.length, "UPDATE");
|
|
40825
41752
|
if (!ok) throw new OperationCancelledError("UPDATE", matched.length);
|
|
40826
41753
|
}
|
|
40827
|
-
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
40828
|
-
const batches = updateFromToPutBatches(stmt, matched, fieldTypes);
|
|
40829
41754
|
for (const batch of batches) await client.putRecords(batch);
|
|
40830
41755
|
return { type: "UPDATE", updatedCount: matched.length };
|
|
40831
41756
|
}
|
|
@@ -40874,7 +41799,9 @@ async function executeDelete(stmt, client, options, cacheContext) {
|
|
|
40874
41799
|
return { type: "DELETE", deletedCount: ids.length };
|
|
40875
41800
|
}
|
|
40876
41801
|
async function executeUpsert(stmt, client, options, cacheContext) {
|
|
40877
|
-
|
|
41802
|
+
if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
|
|
41803
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
41804
|
+
const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
|
|
40878
41805
|
const toInsert = [];
|
|
40879
41806
|
const toUpdate = [];
|
|
40880
41807
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
@@ -40883,7 +41810,7 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
40883
41810
|
const idx = stmt.fields.indexOf(key);
|
|
40884
41811
|
if (idx === -1) throw new Error(`ON DUPLICATE \u306E\u30AD\u30FC\u300C${key}\u300D\u304C INSERT \u30D5\u30A3\u30FC\u30EB\u30C9\u306B\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093`);
|
|
40885
41812
|
const val = row[idx];
|
|
40886
|
-
return val.type === "STRING" ? val.value : val.type === "NUMBER" ?
|
|
41813
|
+
return val.type === "STRING" ? val.value : val.type === "NUMBER" ? numberLiteralText(val) : val.type === "CASE_VALUE" ? evalCaseWhen(val.expr, {}) : val.elements.map((e) => e.value).join(",");
|
|
40887
41814
|
})
|
|
40888
41815
|
);
|
|
40889
41816
|
const targetIndex = await resolveUpsertTargets(stmt.appId, stmt.keyFields, rowKeyValues, client, options, fieldTypes);
|
|
@@ -40904,6 +41831,12 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
40904
41831
|
toInsert.push(record2);
|
|
40905
41832
|
}
|
|
40906
41833
|
});
|
|
41834
|
+
assertValidDmlRecords(
|
|
41835
|
+
[...toInsert, ...toUpdate.map((entry) => entry.record)],
|
|
41836
|
+
stmt.fields,
|
|
41837
|
+
fieldInfos,
|
|
41838
|
+
numberPrecision
|
|
41839
|
+
);
|
|
40907
41840
|
if (options.confirm && toInsert.length + toUpdate.length > 0) {
|
|
40908
41841
|
const total = toInsert.length + toUpdate.length;
|
|
40909
41842
|
const ok = await options.confirm(total, "UPDATE");
|
|
@@ -41179,14 +42112,14 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
|
|
|
41179
42112
|
}
|
|
41180
42113
|
function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
|
|
41181
42114
|
if (value.type === "STRING") return value.value;
|
|
41182
|
-
if (value.type === "NUMBER") return
|
|
42115
|
+
if (value.type === "NUMBER") return numberLiteralText(value);
|
|
41183
42116
|
if (value.type === "ARITH") return String(evalArithExpr(value, row));
|
|
41184
42117
|
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
|
|
41185
42118
|
throw new Error(`${value.type} \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306E\u5024\u3068\u3057\u3066\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
|
|
41186
42119
|
}
|
|
41187
42120
|
function valueToString(value) {
|
|
41188
42121
|
if (value.type === "STRING") return value.value;
|
|
41189
|
-
if (value.type === "NUMBER") return
|
|
42122
|
+
if (value.type === "NUMBER") return numberLiteralText(value);
|
|
41190
42123
|
if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, {});
|
|
41191
42124
|
return value.elements.map((e) => e.value).join(",");
|
|
41192
42125
|
}
|
|
@@ -41301,7 +42234,9 @@ function evalOrderKeyForRow(key, row) {
|
|
|
41301
42234
|
}
|
|
41302
42235
|
}
|
|
41303
42236
|
async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
|
|
41304
|
-
|
|
42237
|
+
if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
|
|
42238
|
+
const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
|
|
42239
|
+
const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
|
|
41305
42240
|
const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
|
|
41306
42241
|
const { rows, columns } = selectResult;
|
|
41307
42242
|
if (columns.length !== stmt.fields.length) {
|
|
@@ -41324,6 +42259,7 @@ async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
41324
42259
|
});
|
|
41325
42260
|
return record2;
|
|
41326
42261
|
});
|
|
42262
|
+
assertValidDmlRecords(records, stmt.fields, fieldInfos, numberPrecision);
|
|
41327
42263
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
41328
42264
|
const rowKeyValues = records.map(
|
|
41329
42265
|
(record2) => stmt.keyFields.map((key) => String(record2[key]?.value ?? ""))
|
|
@@ -42046,6 +42982,7 @@ function collectArithRefFields(stmt) {
|
|
|
42046
42982
|
for (const { value } of stmt.assignments) {
|
|
42047
42983
|
if (value.type === "ARITH") collectArithNodeRefs(value, refs);
|
|
42048
42984
|
if (value.type === "STRING_FUNC") collectArithNodeRefs(value, refs);
|
|
42985
|
+
if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") collectScalarNodeRefs(value, refs);
|
|
42049
42986
|
}
|
|
42050
42987
|
return [...refs];
|
|
42051
42988
|
}
|
|
@@ -42060,10 +42997,74 @@ function collectArithNodeRefs(node, out) {
|
|
|
42060
42997
|
}
|
|
42061
42998
|
if (node.type === "STRING_FUNC") {
|
|
42062
42999
|
for (const arg of node.args) {
|
|
42063
|
-
if (arg.type !== "
|
|
42064
|
-
|
|
43000
|
+
if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
|
|
43001
|
+
}
|
|
43002
|
+
}
|
|
43003
|
+
}
|
|
43004
|
+
async function resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables) {
|
|
43005
|
+
const refs = checkRefs(stmt);
|
|
43006
|
+
const targetTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
43007
|
+
const sourceTableName = from.cteName;
|
|
43008
|
+
const sourceTypes = sourceTableName !== null ? new Map((tempTables?.get(sourceTableName)?.columns ?? []).map((column) => [
|
|
43009
|
+
column,
|
|
43010
|
+
tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.fieldType ?? (tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.semantics?.compareMode === "number" ? "NUMBER" : "SINGLE_LINE_TEXT")
|
|
43011
|
+
])) : await getFieldTypeMap(from.appId, client, cacheContext);
|
|
43012
|
+
const targetFields = /* @__PURE__ */ new Set();
|
|
43013
|
+
const sourceFields = /* @__PURE__ */ new Set();
|
|
43014
|
+
for (const ref of refs) {
|
|
43015
|
+
if (ref.tableAlias !== null) {
|
|
43016
|
+
if (ref.tableAlias.toLowerCase() === `app${stmt.appId}`.toLowerCase()) {
|
|
43017
|
+
if (ref.field !== "$id" && !targetTypes.has(ref.field)) throw customCheckParseError(`CHECK \u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
|
|
43018
|
+
targetFields.add(ref.field);
|
|
43019
|
+
} else if (ref.tableAlias.toLowerCase() === from.alias.toLowerCase()) {
|
|
43020
|
+
if (ref.field !== "$id" && !sourceTypes.has(ref.field)) throw customCheckParseError(`CHECK \u306E\u30BD\u30FC\u30B9\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
|
|
43021
|
+
sourceFields.add(ref.field);
|
|
43022
|
+
} else {
|
|
43023
|
+
throw customCheckParseError(`CHECK \u306E\u4FEE\u98FE\u5B50 ${ref.tableAlias} \u306F\u66F4\u65B0\u5148\u307E\u305F\u306F FROM alias \u3067\u306F\u3042\u308A\u307E\u305B\u3093`);
|
|
42065
43024
|
}
|
|
43025
|
+
continue;
|
|
42066
43026
|
}
|
|
43027
|
+
const inTarget = ref.field === "$id" || targetTypes.has(ref.field);
|
|
43028
|
+
const inSource = ref.field === "$id" || sourceTypes.has(ref.field);
|
|
43029
|
+
if (!inTarget) {
|
|
43030
|
+
throw customCheckParseError(`UPDATE FROM \u306E CHECK \u3067\u306F\u30BD\u30FC\u30B9\u5217 ${ref.field} \u3092\u4FEE\u98FE\u3057\u3066\u304F\u3060\u3055\u3044`);
|
|
43031
|
+
}
|
|
43032
|
+
if (inSource) {
|
|
43033
|
+
throw customCheckParseError(`UPDATE FROM \u306E CHECK \u306E\u975E\u4FEE\u98FE\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u66D6\u6627\u3067\u3059`);
|
|
43034
|
+
}
|
|
43035
|
+
targetFields.add(ref.field);
|
|
43036
|
+
}
|
|
43037
|
+
const evaluationTypes = /* @__PURE__ */ new Map();
|
|
43038
|
+
for (const [field, type] of targetTypes) {
|
|
43039
|
+
evaluationTypes.set(field, type);
|
|
43040
|
+
evaluationTypes.set(`APP${stmt.appId}.${field}`, type);
|
|
43041
|
+
}
|
|
43042
|
+
evaluationTypes.set("$id", "RECORD_NUMBER");
|
|
43043
|
+
evaluationTypes.set(`APP${stmt.appId}.$id`, "RECORD_NUMBER");
|
|
43044
|
+
for (const [field, type] of sourceTypes) evaluationTypes.set(`${from.alias}.${field}`, type);
|
|
43045
|
+
return { targetFields: [...targetFields], sourceFields: [...sourceFields], evaluationTypes };
|
|
43046
|
+
}
|
|
43047
|
+
function updateFromEvaluationRow(pair, appId, sourceAlias) {
|
|
43048
|
+
if (!pair) return {};
|
|
43049
|
+
const target = flatten(pair.target, null);
|
|
43050
|
+
return Object.fromEntries([
|
|
43051
|
+
...Object.entries(target),
|
|
43052
|
+
...Object.entries(target).map(([field, value]) => [`APP${appId}.${field}`, value]),
|
|
43053
|
+
...Object.entries(pair.source).map(([field, value]) => [`${sourceAlias}.${field}`, value])
|
|
43054
|
+
]);
|
|
43055
|
+
}
|
|
43056
|
+
function collectScalarNodeRefs(node, out) {
|
|
43057
|
+
if (node.type === "FIELD") {
|
|
43058
|
+
out.add(node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field);
|
|
43059
|
+
return;
|
|
43060
|
+
}
|
|
43061
|
+
if (node.type === "STRING_FUNC") {
|
|
43062
|
+
for (const arg of node.args) if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
|
|
43063
|
+
return;
|
|
43064
|
+
}
|
|
43065
|
+
if (node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP") {
|
|
43066
|
+
collectScalarNodeRefs(node.left, out);
|
|
43067
|
+
collectScalarNodeRefs(node.right, out);
|
|
42067
43068
|
}
|
|
42068
43069
|
}
|
|
42069
43070
|
function formatAssignment(a) {
|
|
@@ -42082,7 +43083,7 @@ function formatArithExprStr(expr) {
|
|
|
42082
43083
|
}
|
|
42083
43084
|
function formatArithNodeStr(node) {
|
|
42084
43085
|
if (node.type === "FIELD_REF") return node.field;
|
|
42085
|
-
if (node.type === "NUMBER") return
|
|
43086
|
+
if (node.type === "NUMBER") return numberLiteralText(node);
|
|
42086
43087
|
if (node.type === "ARITH") return `(${formatArithExprStr(node)})`;
|
|
42087
43088
|
return "...";
|
|
42088
43089
|
}
|
|
@@ -42544,6 +43545,7 @@ function withRequestGate(client, gate) {
|
|
|
42544
43545
|
},
|
|
42545
43546
|
getApps: () => gate.runReadOnly(() => client.getApps()),
|
|
42546
43547
|
getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
|
|
43548
|
+
getNumberPrecision: (appId) => gate.runReadOnly(() => client.getNumberPrecision(appId)),
|
|
42547
43549
|
getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
|
|
42548
43550
|
postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
|
|
42549
43551
|
putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
|
|
@@ -43105,6 +44107,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
43105
44107
|
);
|
|
43106
44108
|
return flattenFormFieldProperties(res.properties);
|
|
43107
44109
|
},
|
|
44110
|
+
async getNumberPrecision(appId) {
|
|
44111
|
+
const qs = new URLSearchParams();
|
|
44112
|
+
qs.set("app", String(appId));
|
|
44113
|
+
const res = await requestJson(
|
|
44114
|
+
`${apiBasePath}/app/settings.json?${qs.toString()}`,
|
|
44115
|
+
{ method: "GET" },
|
|
44116
|
+
appId
|
|
44117
|
+
);
|
|
44118
|
+
return parseNumberPrecisionSettings(res);
|
|
44119
|
+
},
|
|
43108
44120
|
async getProcessStatuses(appId) {
|
|
43109
44121
|
const qs = new URLSearchParams();
|
|
43110
44122
|
qs.set("app", String(appId));
|
|
@@ -43633,6 +44645,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
43633
44645
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
43634
44646
|
return routed.getFields(binding.appId);
|
|
43635
44647
|
},
|
|
44648
|
+
getNumberPrecision: (appId) => {
|
|
44649
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
|
|
44650
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
44651
|
+
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
44652
|
+
return routed.getNumberPrecision(binding.appId);
|
|
44653
|
+
},
|
|
43636
44654
|
getProcessStatuses: (appId) => {
|
|
43637
44655
|
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
|
|
43638
44656
|
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
@@ -43868,6 +44886,9 @@ function noOpClient() {
|
|
|
43868
44886
|
getFields: fail,
|
|
43869
44887
|
async getProcessStatuses() {
|
|
43870
44888
|
return { enable: false, states: [] };
|
|
44889
|
+
},
|
|
44890
|
+
async getNumberPrecision() {
|
|
44891
|
+
return { digits: 30, decimalPlaces: 10, roundingMode: "HALF_EVEN" };
|
|
43871
44892
|
}
|
|
43872
44893
|
};
|
|
43873
44894
|
}
|
|
@@ -44667,7 +45688,7 @@ Options:
|
|
|
44667
45688
|
-h, --help Show help
|
|
44668
45689
|
`);
|
|
44669
45690
|
}
|
|
44670
|
-
var SERVER_VERSION = true ? "3.
|
|
45691
|
+
var SERVER_VERSION = true ? "3.4.0" : "0.0.0-dev";
|
|
44671
45692
|
function createServer(args) {
|
|
44672
45693
|
const server = new McpServer({
|
|
44673
45694
|
name: "ksql-mcp",
|
|
@@ -44689,12 +45710,12 @@ function createServer(args) {
|
|
|
44689
45710
|
}, tools.explainTool);
|
|
44690
45711
|
server.registerTool("ksql_query", {
|
|
44691
45712
|
title: "Run read-only kSQL",
|
|
44692
|
-
description: "Execute read-only kSQL: SELECT, WITH, UNION, EXPLAIN, SHOW APPS, DESCRIBE, ASSERT, and INSERT/UPSERT/UPDATE ... VALIDATE ONLY. ASSERT failure always stops the batch. Local ORDER BY plans require complete input and fail instead of returning a truncated top-N; REST top-N and KORDER_NATIVE do not fetch a partial candidate set. VALIDATE ONLY always treats onLimit=truncate as error. VALIDATE ONLY performs local Tier-0 validation with zero write API calls. Supports multi-statement batches with temp tables, including VALIDATE ONLY INTO #err for later SELECT. Mutating DML is rejected.",
|
|
45713
|
+
description: "Execute read-only kSQL: SELECT, WITH, UNION, EXPLAIN, SHOW APPS, DESCRIBE, ASSERT, and INSERT/UPSERT/UPDATE ... VALIDATE ONLY. ASSERT failure always stops the batch. Local ORDER BY plans require complete input and fail instead of returning a truncated top-N; REST top-N and KORDER_NATIVE do not fetch a partial candidate set. VALIDATE ONLY always treats onLimit=truncate as error. VALIDATE ONLY performs local Tier-0 validation with zero write API calls; NUMBER targets use the app numberPrecision settings for integer-digit validation and fail closed if settings cannot be read. Excess fractional digits pass through for kintone to round automatically. Supports multi-statement batches with temp tables, including VALIDATE ONLY INTO #err for later SELECT. Mutating DML is rejected.",
|
|
44693
45714
|
inputSchema: queryInputShape
|
|
44694
45715
|
}, tools.queryTool);
|
|
44695
45716
|
server.registerTool("ksql_mutate", {
|
|
44696
45717
|
title: "Run mutating kSQL",
|
|
44697
|
-
description: "Execute DML kSQL with explicit allowDml, confirmText, and dmlMaxRows safety controls. Supports multi-statement DML batches with temp tables. ON ERROR SKIP INTO #err optionally isolates local Tier-0 validation failures and writes only valid rows; REJECT LIMIT stops with zero writes while returning diagnostics. INSERT/UPSERT INTO app ... SELECT supports app sources, temp tables, or joins of both. UPDATE ... FROM supports copying scalar fields from an app or temp table by matching target $id or a single-line-text/number business key to one source key. For UPSERT, dmlMaxRows counts inserts + updates. dmlMaxRows caps affected rows only, not source reads: source SELECT, ON ERROR SKIP candidates, and UPDATE ... FROM app reads use the runtime maxRecords (KSQL_MAX_RECORDS / profile query.maxRecords, default 500); temp tables hold at most 10000 rows by default (adjustable via tempTableMaxRows).",
|
|
45718
|
+
description: "Execute DML kSQL with explicit allowDml, confirmText, and dmlMaxRows safety controls. Supports multi-statement DML batches with temp tables. ON ERROR SKIP INTO #err optionally isolates local Tier-0 validation failures and writes only valid rows; REJECT LIMIT stops with zero writes while returning diagnostics. NUMBER targets use the destination app numberPrecision settings for integer-digit validation in normal, validation-only, and skip paths; settings failures are fail-closed. Excess fractional digits pass through for kintone to round automatically. INSERT/UPSERT INTO app ... SELECT supports app sources, temp tables, or joins of both. UPDATE ... FROM supports copying scalar fields from an app or temp table by matching target $id or a single-line-text/number business key to one source key. For UPSERT, dmlMaxRows counts inserts + updates. dmlMaxRows caps affected rows only, not source reads: source SELECT, ON ERROR SKIP candidates, and UPDATE ... FROM app reads use the runtime maxRecords (KSQL_MAX_RECORDS / profile query.maxRecords, default 500); temp tables hold at most 10000 rows by default (adjustable via tempTableMaxRows).",
|
|
44698
45719
|
inputSchema: mutateInputShape
|
|
44699
45720
|
}, tools.mutateTool);
|
|
44700
45721
|
server.registerTool("ksql_describe_app", {
|