@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.
@@ -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
- // 数値: 整数 or 小数(123 / 3.14)
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 !== "STRFUNC_COL") return false;
32128
- return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
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
- if (arg.type === "STRING_FUNC") {
32133
- return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
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 { type: "NUMBER", value: -operand.value };
32178
- return { type: "AGG_ARITH", left: { type: "NUMBER", value: 0 }, op: "-", right: operand };
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 { type: "NUMBER", value: Number(tok.value) };
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 { type: "NUMBER", value: Number(number4.value) };
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 { type: "NUMBER", value: -operand.value };
32243
- return { type: "ARITH", left: { type: "NUMBER", value: 0 }, op: "-", right: operand };
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 { type: "NUMBER", value: Number(tok.value) };
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
- const tok = this.peek();
32465
- if (tok.kind === "STRING" /* STRING */) {
32466
- this.advance();
32467
- return { type: "STRING", value: tok.value };
32468
- }
32469
- if (this.tryStringFuncName() !== null) {
32470
- return this.parseStringFuncExpr();
32471
- }
32472
- const startPos = this.pos;
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.pos = startPos;
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 { type: "NUMBER", value: expr.value };
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({ type: "NUMBER", value: Number(tok.value) });
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 */ ? -1 : 1;
32929
- values.push({ type: "NUMBER", value: sign * Number(number4.value) });
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
- const value = Number(number4.value);
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({ type: "NUMBER", value: Number(tok.value) });
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 String(value.value);
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) : String(item.value)
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
- collectArithNode(arg, out);
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
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(arg);
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
- walkArith(arg, phase);
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 === "STRING_FUNC") {
34315
- walkStringFunc(result, phase);
34621
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
34622
+ walkArith(result, phase);
34316
34623
  return;
34317
34624
  }
34318
- walkArith(result, phase);
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 String(node.value);
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 arithNodeLabel(a);
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 triCompare(a.value, b.value);
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 numericCmp = triCompare(Number(left), Number(right));
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
- return String(evalArithExpr(arg, row));
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 String(value.value);
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 === "STRING") return result.value;
35949
- if (result.type === "STRING_FUNC") return evalStringFunc(result, row);
35950
- if (result.type === "FIELD_REF") return row[result.field] ?? "";
35951
- return String(evalArithExpr(result, row));
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
- collectArithNode2(arg, out);
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
- collectArithNode2(result, out);
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
- return String(evalArithExpr(result, row));
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 String(value.value);
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 String(node.value);
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 String(n.value);
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 arithColDefaultKey(a);
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
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(arg);
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
- return { type: "NUMBER", value: evalAggArithExpr(arg, rows, resolveAggSortKind) };
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
- if (!isFiniteDecimal(text)) {
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) && (raw.type === "STRING" || raw.type === "NUMBER")) return String(raw.value);
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 === "STRING" || sql.type === "NUMBER") return String(sql.value ?? "");
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, { type: "string", value: String(value.value) });
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 String(operand.value);
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 if (arg.type === "STRING_FUNC") {
39169
- collectStringFuncAggregateRefs(arg, out);
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
- const source = resolveField2(aggregateFieldRef(result.field));
39350
- return source ?? unknownStringColumnMeta();
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 t = v.trim();
39865
- if (t !== "" && !Number.isNaN(Number(t))) return String(Number(t));
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
- if (selectResult.columns.length !== stmt.fields.length) {
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 resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [...getParams.fields], {
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
- const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
40518
- maxRecords: options.maxRecords ?? 1e4,
40519
- parallel: options.fetchParallel ?? 1
40520
- });
40521
- records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
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 sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : ""))];
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([...sourceByKey.keys()], UPDATE_FROM_KEY_CHUNK_SIZE)) {
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 text2 = raw.trim();
40689
- const id = Number(text2);
40690
- if (text2 === "" || !Number.isSafeInteger(id) || id <= 0) {
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 text = raw.trim();
40696
- if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(text)) {
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
- let unsigned = text;
40700
- let negative = false;
40701
- if (unsigned.startsWith("-") || unsigned.startsWith("+")) {
40702
- negative = unsigned[0] === "-";
40703
- unsigned = unsigned.slice(1);
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
- let [whole, fraction = ""] = unsigned.split(".");
40706
- whole = (whole || "0").replace(/^0+(?=\d)/, "");
40707
- fraction = fraction.replace(/0+$/, "");
40708
- const zero = /^0*$/.test(whole) && fraction === "";
40709
- const canonical = fraction === "" ? whole : `${whole}.${fraction}`;
40710
- return negative && !zero ? `-${canonical}` : canonical;
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
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
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
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
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" ? String(val.value) : val.type === "CASE_VALUE" ? evalCaseWhen(val.expr, {}) : val.elements.map((e) => e.value).join(",");
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 String(value.value);
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 String(value.value);
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
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
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 !== "STRING" && arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") {
42064
- collectArithNodeRefs(arg, out);
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 String(node.value);
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.2.0" : "0.0.0-dev";
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", {