@rex0220/kintone-sql-tools 3.1.0 → 3.3.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.
@@ -31029,10 +31029,14 @@ var KEYWORDS = /* @__PURE__ */ new Map([
31029
31029
  ["LTRIM", "LTRIM" /* LTRIM */],
31030
31030
  ["RTRIM", "RTRIM" /* RTRIM */],
31031
31031
  ["LENGTH", "LENGTH" /* LENGTH */],
31032
+ ["LENGTH_CHAR", "LENGTH_CHAR" /* LENGTH_CHAR */],
31032
31033
  ["SUBSTRING", "SUBSTRING" /* SUBSTRING */],
31033
31034
  ["SUBSTR", "SUBSTR" /* SUBSTR */],
31034
31035
  ["CONCAT", "CONCAT" /* CONCAT */],
31035
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 */],
31036
31040
  ["COALESCE", "COALESCE" /* COALESCE */],
31037
31041
  ["NULLIF", "NULLIF" /* NULLIF */],
31038
31042
  ["ISNULL", "ISNULL" /* ISNULL */],
@@ -31041,6 +31045,7 @@ var KEYWORDS = /* @__PURE__ */ new Map([
31041
31045
  ["LEAST", "LEAST" /* LEAST */],
31042
31046
  ["LPAD", "LPAD" /* LPAD */],
31043
31047
  ["RPAD", "RPAD" /* RPAD */],
31048
+ ["TRANSLATE", "TRANSLATE" /* TRANSLATE */],
31044
31049
  ["CAST", "CAST" /* CAST */],
31045
31050
  ["CONVERT", "CONVERT" /* CONVERT */],
31046
31051
  ["FORMAT", "FORMAT" /* FORMAT */],
@@ -31164,7 +31169,7 @@ var Lexer = class {
31164
31169
  );
31165
31170
  }
31166
31171
  // ----------------------------------------------------------
31167
- // 数値: 整数 or 小数(123 / 3.14)
31172
+ // 数値: digits[.digits][e[+-]digits](先頭/末尾 dot は受理しない)
31168
31173
  // ----------------------------------------------------------
31169
31174
  readNumber(start) {
31170
31175
  while (this.pos < this.input.length && isDigit(this.input[this.pos])) {
@@ -31176,6 +31181,16 @@ var Lexer = class {
31176
31181
  this.pos++;
31177
31182
  }
31178
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
+ }
31179
31194
  return this.makeToken(
31180
31195
  "NUMBER" /* NUMBER */,
31181
31196
  this.input.slice(start, this.pos),
@@ -31375,8 +31390,94 @@ function isJapanese(cp) {
31375
31390
  return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65281 && cp <= 65376;
31376
31391
  }
31377
31392
 
31393
+ // src/core/exactDecimal.ts
31394
+ var DECIMAL_PATTERN = /^([+-]?)(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([+-]?)(\d+))?$/;
31395
+ function parseSafeExponent(sign, digits) {
31396
+ if (digits === void 0) return 0;
31397
+ let value = 0;
31398
+ for (const digit of digits) {
31399
+ value = value * 10 + (digit.charCodeAt(0) - 48);
31400
+ if (!Number.isSafeInteger(value)) return null;
31401
+ }
31402
+ return sign === "-" ? -value : value;
31403
+ }
31404
+ function parseExactDecimal(input) {
31405
+ const match = DECIMAL_PATTERN.exec(input.trim());
31406
+ if (match === null) return null;
31407
+ const exponent = parseSafeExponent(match[5], match[6]);
31408
+ if (exponent === null) return null;
31409
+ const fraction = match[3] ?? match[4] ?? "";
31410
+ let coefficient = `${match[2] ?? ""}${fraction}`.replace(/^0+/, "");
31411
+ if (coefficient === "") return { sign: 0, coefficient: "0", scale: 0 };
31412
+ let scale = fraction.length - exponent;
31413
+ if (!Number.isSafeInteger(scale)) return null;
31414
+ const trailingZeros = /0+$/.exec(coefficient)?.[0].length ?? 0;
31415
+ if (trailingZeros > 0) {
31416
+ coefficient = coefficient.slice(0, -trailingZeros);
31417
+ scale -= trailingZeros;
31418
+ if (!Number.isSafeInteger(scale)) return null;
31419
+ }
31420
+ if (!Number.isSafeInteger(coefficient.length - scale)) return null;
31421
+ const sign = match[1] === "-" ? -1 : 1;
31422
+ return { sign, coefficient, scale };
31423
+ }
31424
+ function formatPlainDecimal(dec) {
31425
+ if (dec.sign === 0) return "0";
31426
+ const digits = dec.coefficient;
31427
+ let magnitude;
31428
+ if (dec.scale <= 0) {
31429
+ magnitude = `${digits}${"0".repeat(-dec.scale)}`;
31430
+ } else if (digits.length > dec.scale) {
31431
+ const point = digits.length - dec.scale;
31432
+ magnitude = `${digits.slice(0, point)}.${digits.slice(point)}`;
31433
+ } else {
31434
+ magnitude = `0.${"0".repeat(dec.scale - digits.length)}${digits}`;
31435
+ }
31436
+ return dec.sign === -1 ? `-${magnitude}` : magnitude;
31437
+ }
31438
+ function toPlainDecimal(input) {
31439
+ const dec = parseExactDecimal(input);
31440
+ return dec === null ? null : formatPlainDecimal(dec);
31441
+ }
31442
+ function compareMagnitudes(left, right) {
31443
+ const leftPoint = left.coefficient.length - left.scale;
31444
+ const rightPoint = right.coefficient.length - right.scale;
31445
+ if (!Number.isSafeInteger(leftPoint) || !Number.isSafeInteger(rightPoint)) {
31446
+ throw new Error("ArgumentError: exact decimal scale is outside the supported range.");
31447
+ }
31448
+ if (leftPoint !== rightPoint) return leftPoint < rightPoint ? -1 : 1;
31449
+ const width = Math.max(left.coefficient.length, right.coefficient.length);
31450
+ for (let index = 0; index < width; index++) {
31451
+ const a = index < left.coefficient.length ? left.coefficient.charCodeAt(index) : 48;
31452
+ const b = index < right.coefficient.length ? right.coefficient.charCodeAt(index) : 48;
31453
+ if (a !== b) return a < b ? -1 : 1;
31454
+ }
31455
+ return 0;
31456
+ }
31457
+ function compareExactDecimal(left, right) {
31458
+ if (left.sign !== right.sign) return left.sign < right.sign ? -1 : 1;
31459
+ if (left.sign === 0) return 0;
31460
+ const magnitude = compareMagnitudes(left, right);
31461
+ return left.sign === -1 ? magnitude === 0 ? 0 : magnitude === -1 ? 1 : -1 : magnitude;
31462
+ }
31463
+ function compareDecimal(left, right) {
31464
+ const a = parseExactDecimal(left);
31465
+ const b = parseExactDecimal(right);
31466
+ if (a === null || b === null) {
31467
+ throw new Error("ArgumentError: compareDecimal requires finite decimal inputs.");
31468
+ }
31469
+ return compareExactDecimal(a, b);
31470
+ }
31471
+
31378
31472
  // src/types/ast.ts
31379
31473
  var NO_FROM_CTE_NAME = "__NO_FROM__";
31474
+ function makeNumberLiteral(raw) {
31475
+ return { type: "NUMBER", value: Number(raw), raw };
31476
+ }
31477
+ function numberLiteralText(node) {
31478
+ const source = node.raw ?? String(node.value);
31479
+ return toPlainDecimal(source) ?? source;
31480
+ }
31380
31481
 
31381
31482
  // src/parser/parser.ts
31382
31483
  var MAX_BATCH_STATEMENTS = 20;
@@ -31400,13 +31501,18 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
31400
31501
  "LTRIM" /* LTRIM */,
31401
31502
  "RTRIM" /* RTRIM */,
31402
31503
  "LENGTH" /* LENGTH */,
31504
+ "LENGTH_CHAR" /* LENGTH_CHAR */,
31403
31505
  "SUBSTRING" /* SUBSTRING */,
31404
31506
  "SUBSTR" /* SUBSTR */,
31405
31507
  "CONCAT" /* CONCAT */,
31406
31508
  "REPLACE" /* REPLACE */,
31509
+ "TRANSLATE" /* TRANSLATE */,
31407
31510
  "COALESCE" /* COALESCE */,
31408
31511
  "NULLIF" /* NULLIF */,
31409
31512
  "ISNULL" /* ISNULL */,
31513
+ "REGEXP_LIKE" /* REGEXP_LIKE */,
31514
+ "REGEXP_REPLACE" /* REGEXP_REPLACE */,
31515
+ "REGEXP_SUBSTR" /* REGEXP_SUBSTR */,
31410
31516
  "LEFT" /* LEFT */,
31411
31517
  "RIGHT" /* RIGHT */,
31412
31518
  "INSTR" /* INSTR */,
@@ -31455,6 +31561,7 @@ var ParseError = class extends Error {
31455
31561
  var Parser = class {
31456
31562
  constructor(tokens) {
31457
31563
  this.tokens = tokens;
31564
+ this.allowUnaryPlusNumber = false;
31458
31565
  this.pos = 0;
31459
31566
  /** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
31460
31567
  this.cteNames = /* @__PURE__ */ new Set();
@@ -32169,12 +32276,12 @@ var Parser = class {
32169
32276
  if (this.peek().kind === "-" /* MINUS */) {
32170
32277
  this.advance();
32171
32278
  const operand = this.parseAggPrimary();
32172
- if (operand.type === "NUMBER") return { type: "NUMBER", value: -operand.value };
32173
- return { type: "AGG_ARITH", left: { type: "NUMBER", value: 0 }, op: "-", right: operand };
32279
+ if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
32280
+ return { type: "AGG_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
32174
32281
  }
32175
32282
  if (this.peek().kind === "NUMBER" /* NUMBER */) {
32176
32283
  const tok = this.advance();
32177
- return { type: "NUMBER", value: Number(tok.value) };
32284
+ return makeNumberLiteral(tok.value);
32178
32285
  }
32179
32286
  const aggFunc = this.tryAggregateFunc();
32180
32287
  if (aggFunc !== null) {
@@ -32223,11 +32330,19 @@ var Parser = class {
32223
32330
  this.expect(")" /* RPAREN */);
32224
32331
  return expr;
32225
32332
  }
32333
+ if (this.allowUnaryPlusNumber && this.peek().kind === "+" /* PLUS */) {
32334
+ this.advance();
32335
+ const number4 = this.expect("NUMBER" /* NUMBER */, "\u5358\u9805 + \u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059");
32336
+ return makeNumberLiteral(`+${number4.value}`);
32337
+ }
32226
32338
  if (this.peek().kind === "-" /* MINUS */) {
32227
32339
  this.advance();
32340
+ if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
32341
+ 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());
32342
+ }
32228
32343
  const operand = this.parseArithPrimary();
32229
- if (operand.type === "NUMBER") return { type: "NUMBER", value: -operand.value };
32230
- return { type: "ARITH", left: { type: "NUMBER", value: 0 }, op: "-", right: operand };
32344
+ if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
32345
+ return { type: "ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
32231
32346
  }
32232
32347
  if (this.tryStringFuncName() !== null) {
32233
32348
  return this.parseStringFuncExpr();
@@ -32235,7 +32350,7 @@ var Parser = class {
32235
32350
  const tok = this.peek();
32236
32351
  if (tok.kind === "NUMBER" /* NUMBER */) {
32237
32352
  this.advance();
32238
- return { type: "NUMBER", value: Number(tok.value) };
32353
+ return makeNumberLiteral(tok.value);
32239
32354
  }
32240
32355
  if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
32241
32356
  this.advance();
@@ -32334,10 +32449,15 @@ var Parser = class {
32334
32449
  ["LTRIM" /* LTRIM */]: "LTRIM",
32335
32450
  ["RTRIM" /* RTRIM */]: "RTRIM",
32336
32451
  ["LENGTH" /* LENGTH */]: "LENGTH",
32452
+ ["LENGTH_CHAR" /* LENGTH_CHAR */]: "LENGTH_CHAR",
32337
32453
  ["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
32338
32454
  ["SUBSTR" /* SUBSTR */]: "SUBSTRING",
32339
32455
  ["CONCAT" /* CONCAT */]: "CONCAT",
32340
32456
  ["REPLACE" /* REPLACE */]: "REPLACE",
32457
+ ["REGEXP_LIKE" /* REGEXP_LIKE */]: "REGEXP_LIKE",
32458
+ ["REGEXP_REPLACE" /* REGEXP_REPLACE */]: "REGEXP_REPLACE",
32459
+ ["REGEXP_SUBSTR" /* REGEXP_SUBSTR */]: "REGEXP_SUBSTR",
32460
+ ["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
32341
32461
  ["COALESCE" /* COALESCE */]: "COALESCE",
32342
32462
  ["NULLIF" /* NULLIF */]: "NULLIF",
32343
32463
  ["ISNULL" /* ISNULL */]: "ISNULL",
@@ -32876,7 +32996,7 @@ var Parser = class {
32876
32996
  }
32877
32997
  if (tok.kind === "NUMBER" /* NUMBER */ || tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */ || tok.kind === "(" /* LPAREN */ || tok.kind === "-" /* MINUS */ || this.tryStringFuncName() !== null) {
32878
32998
  const expr = this.parseArithAddSub();
32879
- if (expr.type === "NUMBER") return { type: "NUMBER", value: expr.value };
32999
+ if (expr.type === "NUMBER") return expr;
32880
33000
  return { type: "ARITH_VALUE", expr };
32881
33001
  }
32882
33002
  throw new ParseError(
@@ -32903,15 +33023,15 @@ var Parser = class {
32903
33023
  if (tok.kind === "STRING" /* STRING */) {
32904
33024
  values.push({ type: "STRING", value: tok.value });
32905
33025
  } else if (tok.kind === "NUMBER" /* NUMBER */) {
32906
- values.push({ type: "NUMBER", value: Number(tok.value) });
33026
+ values.push(makeNumberLiteral(tok.value));
32907
33027
  } else if (tok.kind === "-" /* MINUS */ || tok.kind === "+" /* PLUS */) {
32908
33028
  const number4 = this.peek();
32909
33029
  if (number4.kind !== "NUMBER" /* NUMBER */) {
32910
33030
  throw new ParseError(invalidValueMessage, tok);
32911
33031
  }
32912
33032
  this.advance();
32913
- const sign = tok.kind === "-" /* MINUS */ ? -1 : 1;
32914
- values.push({ type: "NUMBER", value: sign * Number(number4.value) });
33033
+ const sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
33034
+ values.push(makeNumberLiteral(`${sign}${number4.value}`));
32915
33035
  } else if (tok.kind === "VARIABLE" /* VARIABLE */) {
32916
33036
  values.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
32917
33037
  } else {
@@ -33098,12 +33218,16 @@ var Parser = class {
33098
33218
  } else if (this.peek().kind === "IF" /* IF */) {
33099
33219
  const expr = this.parseIfExpr();
33100
33220
  row.push({ type: "CASE_VALUE", expr });
33221
+ } else if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
33222
+ const sign = this.advance();
33223
+ 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");
33224
+ row.push(makeNumberLiteral(`${sign.kind === "-" /* MINUS */ ? "-" : "+"}${number4.value}`));
33101
33225
  } else {
33102
33226
  const tok = this.advance();
33103
33227
  if (tok.kind === "STRING" /* STRING */) {
33104
33228
  row.push({ type: "STRING", value: tok.value });
33105
33229
  } else if (tok.kind === "NUMBER" /* NUMBER */) {
33106
- row.push({ type: "NUMBER", value: Number(tok.value) });
33230
+ row.push(makeNumberLiteral(tok.value));
33107
33231
  } else {
33108
33232
  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);
33109
33233
  }
@@ -33127,6 +33251,12 @@ var Parser = class {
33127
33251
  const { appId, subtableCode } = extractTableRef(name, this.prev());
33128
33252
  this.expect("SET" /* SET */);
33129
33253
  const assignments = this.parseAssignments();
33254
+ if (subtableCode && assignments.some((a) => a.value.type === "STRING_FUNC")) {
33255
+ throw new ParseError(
33256
+ "\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093",
33257
+ this.prev()
33258
+ );
33259
+ }
33130
33260
  let from = null;
33131
33261
  if (this.consume("FROM" /* FROM */)) {
33132
33262
  const table = this.parseTableRef();
@@ -33170,7 +33300,14 @@ var Parser = class {
33170
33300
  from.targetFilter = decomposed.targetFilter;
33171
33301
  } else if (assignments.some((a) => a.value.type === "SOURCE_FIELD")) {
33172
33302
  throw new ParseError(
33173
- "SET \u306E\u5024\u306B\u306F\u30EA\u30C6\u30E9\u30EB\u30FB\u7B97\u8853\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u306E\u307F\u306F\u4E0D\u53EF\uFF09",
33303
+ "SET \u306E\u5024\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
33304
+ whereTok
33305
+ );
33306
+ } else if (assignments.some(
33307
+ (a) => a.value.type === "STRING_FUNC" && this.nodeContainsAnyQualifier(a.value)
33308
+ )) {
33309
+ throw new ParseError(
33310
+ "UPDATE SET \u306E\u6587\u5B57\u5217\u95A2\u6570\u3067\u306F\u66F4\u65B0\u5148\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u4FEE\u98FE\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044",
33174
33311
  whereTok
33175
33312
  );
33176
33313
  }
@@ -33237,6 +33374,12 @@ var Parser = class {
33237
33374
  }
33238
33375
  validateUpdateFromAssignments(assignments, sourceAlias, tok) {
33239
33376
  for (const assignment of assignments) {
33377
+ if (assignment.value.type === "STRING_FUNC") {
33378
+ throw new ParseError(
33379
+ "UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093",
33380
+ tok
33381
+ );
33382
+ }
33240
33383
  if (assignment.value.type === "SOURCE_FIELD") {
33241
33384
  if (assignment.value.alias.toLowerCase() !== sourceAlias.toLowerCase()) {
33242
33385
  throw new ParseError(`UPDATE ... FROM \u306E SET \u53C2\u7167\u306F\u30BD\u30FC\u30B9 alias ${sourceAlias} \u3067\u4FEE\u98FE\u3057\u3066\u304F\u3060\u3055\u3044`, tok);
@@ -33376,9 +33519,17 @@ var Parser = class {
33376
33519
  this.expect(")" /* RPAREN */);
33377
33520
  return { type: "SCALAR_SUBQUERY", query };
33378
33521
  }
33379
- const node = this.parseArithAddSub();
33522
+ const previousAllowUnaryPlusNumber = this.allowUnaryPlusNumber;
33523
+ this.allowUnaryPlusNumber = true;
33524
+ let node;
33525
+ try {
33526
+ node = this.parseArithAddSub();
33527
+ } finally {
33528
+ this.allowUnaryPlusNumber = previousAllowUnaryPlusNumber;
33529
+ }
33380
33530
  if (node.type === "NUMBER") return node;
33381
33531
  if (node.type === "ARITH") return node;
33532
+ if (node.type === "STRING_FUNC") return node;
33382
33533
  if (node.type === "FIELD_REF") {
33383
33534
  const dot = node.field.indexOf(".");
33384
33535
  if (dot > 0 && dot < node.field.length - 1) {
@@ -33386,7 +33537,7 @@ var Parser = class {
33386
33537
  }
33387
33538
  }
33388
33539
  throw new ParseError(
33389
- "SET \u306E\u5024\u306B\u306F\u30EA\u30C6\u30E9\u30EB\u30FB\u7B97\u8853\u5F0F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u306E\u307F\u306F\u4E0D\u53EF\uFF09",
33540
+ "SET \u306E\u5024\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u3092\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
33390
33541
  tok
33391
33542
  );
33392
33543
  }
@@ -33898,7 +34049,7 @@ function convertValue(value, op) {
33898
34049
  case "STRING":
33899
34050
  return convertString(value);
33900
34051
  case "NUMBER":
33901
- return String(value.value);
34052
+ return numberLiteralText(value);
33902
34053
  case "KINTONE_FUNC":
33903
34054
  return convertKintoneFunc(value);
33904
34055
  case "IN_LIST":
@@ -33927,7 +34078,7 @@ function convertInList(v, op) {
33927
34078
  }
33928
34079
  assertResolvedInListValues(v.values);
33929
34080
  const values = v.values.map(
33930
- (item) => item.type === "STRING" ? convertString(item) : String(item.value)
34081
+ (item) => item.type === "STRING" ? convertString(item) : numberLiteralText(item)
33931
34082
  ).join(",");
33932
34083
  return `(${values})`;
33933
34084
  }
@@ -34440,7 +34591,7 @@ function aggregateSyntheticName(func, distinct, arg) {
34440
34591
  }
34441
34592
  function arithNodeLabel(node) {
34442
34593
  if (node.type === "FIELD_REF") return node.field;
34443
- if (node.type === "NUMBER") return String(node.value);
34594
+ if (node.type === "NUMBER") return numberLiteralText(node);
34444
34595
  if (node.type === "STRING_FUNC") return stringFuncLabel(node);
34445
34596
  return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
34446
34597
  }
@@ -34597,7 +34748,7 @@ function isNumericCandidate(expr, options) {
34597
34748
  if (!isTargetField(expr.left, options)) return false;
34598
34749
  if (expr.right.type !== "NUMBER") return false;
34599
34750
  if (expr.op === "=") return true;
34600
- return (expr.op === "<" || expr.op === ">") && Number.isSafeInteger(expr.right.value);
34751
+ return (expr.op === "<" || expr.op === ">") && /^[+-]?\d+$/.test(numberLiteralText(expr.right)) && Number.isSafeInteger(expr.right.value);
34601
34752
  }
34602
34753
  function isSelectionInCandidate(expr, options) {
34603
34754
  if (expr.left.type !== "FIELD" || expr.left.field === "$id") return false;
@@ -35202,9 +35353,10 @@ function triCompare(left, right) {
35202
35353
  }
35203
35354
  function numberKey(value) {
35204
35355
  if (value === "") return { band: 0 };
35356
+ const decimal = parseExactDecimal(value);
35357
+ if (decimal !== null) return { band: 2, value: decimal };
35205
35358
  const numeric = Number(value);
35206
35359
  if (numeric === Number.NEGATIVE_INFINITY) return { band: 1 };
35207
- if (Number.isFinite(numeric)) return { band: 2, value: numeric };
35208
35360
  if (numeric === Number.POSITIVE_INFINITY) return { band: 3 };
35209
35361
  if (value === "NaN") return { band: 4 };
35210
35362
  return { band: 5, value };
@@ -35213,7 +35365,7 @@ function compareNumbers(left, right) {
35213
35365
  const a = numberKey(left);
35214
35366
  const b = numberKey(right);
35215
35367
  if (a.band !== b.band) return a.band < b.band ? -1 : 1;
35216
- if (a.band === 2 && b.band === 2) return triCompare(a.value, b.value);
35368
+ if (a.band === 2 && b.band === 2) return compareExactDecimal(a.value, b.value);
35217
35369
  if (a.band === 5 && b.band === 5) return compareCodePointStrings(a.value, b.value);
35218
35370
  return 0;
35219
35371
  }
@@ -35313,7 +35465,9 @@ function selectScalarExtreme(values, extreme) {
35313
35465
  const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
35314
35466
  const compare = (left, right) => {
35315
35467
  if (numeric) {
35316
- const numericCmp = triCompare(Number(left), Number(right));
35468
+ const leftDecimal = parseExactDecimal(left);
35469
+ const rightDecimal = parseExactDecimal(right);
35470
+ const numericCmp = leftDecimal !== null && rightDecimal !== null ? compareExactDecimal(leftDecimal, rightDecimal) : triCompare(Number(left), Number(right));
35317
35471
  if (numericCmp !== 0) return numericCmp;
35318
35472
  }
35319
35473
  return compareCodePointStrings(left, right);
@@ -35399,6 +35553,149 @@ function applyRoundOp(op, num, digits) {
35399
35553
  if (digits > 0) return String(parseFloat(raw.toFixed(digits)));
35400
35554
  return String(raw);
35401
35555
  }
35556
+ function isHighSurrogate(codeUnit) {
35557
+ return codeUnit >= 55296 && codeUnit <= 56319;
35558
+ }
35559
+ function isLowSurrogate(codeUnit) {
35560
+ return codeUnit >= 56320 && codeUnit <= 57343;
35561
+ }
35562
+ function splitsSurrogatePair(value, index) {
35563
+ return index > 0 && index < value.length && isHighSurrogate(value.charCodeAt(index - 1)) && isLowSurrogate(value.charCodeAt(index));
35564
+ }
35565
+ function normalizeSliceIndex(index, length) {
35566
+ if (Number.isNaN(index) || index === Number.NEGATIVE_INFINITY) return 0;
35567
+ if (index === Number.POSITIVE_INFINITY) return length;
35568
+ const integer2 = Math.trunc(index);
35569
+ return integer2 < 0 ? Math.max(length + integer2, 0) : Math.min(integer2, length);
35570
+ }
35571
+ function sliceSafePrefix(value, budget) {
35572
+ let end = Math.min(Math.max(0, budget), value.length);
35573
+ if (splitsSurrogatePair(value, end)) end -= 1;
35574
+ return value.slice(0, end);
35575
+ }
35576
+ function sliceSafeSuffix(value, budget) {
35577
+ let start = Math.max(0, value.length - budget);
35578
+ if (splitsSurrogatePair(value, start)) start += 1;
35579
+ return value.slice(start);
35580
+ }
35581
+ function sliceSafeRange(value, rawStart, rawEnd) {
35582
+ let start = normalizeSliceIndex(rawStart, value.length);
35583
+ let end = normalizeSliceIndex(rawEnd, value.length);
35584
+ if (end <= start) return "";
35585
+ if (splitsSurrogatePair(value, start)) start += 1;
35586
+ if (splitsSurrogatePair(value, end)) end -= 1;
35587
+ return value.slice(start, Math.max(start, end));
35588
+ }
35589
+ function makeSafePadding(pad, gap) {
35590
+ const repeated = pad.repeat(Math.ceil(gap / pad.length));
35591
+ return sliceSafePrefix(repeated, gap);
35592
+ }
35593
+ var REGEXP_CACHE_MAX = 200;
35594
+ var regexpCache = /* @__PURE__ */ new Map();
35595
+ function normalizeRegexpFlags(flags) {
35596
+ if (/[^ims]/.test(flags)) {
35597
+ throw new Error("ArgumentError: regular expression flags may contain only i, m, or s.");
35598
+ }
35599
+ if (new Set(flags).size !== flags.length) {
35600
+ throw new Error("ArgumentError: regular expression flags must not contain duplicates.");
35601
+ }
35602
+ return `${flags}u`;
35603
+ }
35604
+ function compileRegexp(pattern, flags, global = false) {
35605
+ const normalizedFlags = normalizeRegexpFlags(flags) + (global ? "g" : "");
35606
+ const key = `${pattern}\0${normalizedFlags}`;
35607
+ const cached2 = regexpCache.get(key);
35608
+ if (cached2 !== void 0) {
35609
+ cached2.lastIndex = 0;
35610
+ return cached2;
35611
+ }
35612
+ let regexp;
35613
+ try {
35614
+ regexp = new RegExp(pattern, normalizedFlags);
35615
+ } catch (error51) {
35616
+ const detail = error51 instanceof Error ? error51.message : String(error51);
35617
+ throw new Error(`ArgumentError: invalid regular expression: ${detail}`);
35618
+ }
35619
+ if (regexpCache.size >= REGEXP_CACHE_MAX) {
35620
+ const oldest = regexpCache.keys().next().value;
35621
+ if (oldest !== void 0) regexpCache.delete(oldest);
35622
+ }
35623
+ regexpCache.set(key, regexp);
35624
+ return regexp;
35625
+ }
35626
+ function assertRegexpReplacement(replacement) {
35627
+ if (replacement.includes("$`") || replacement.includes("$'")) {
35628
+ throw new Error("ArgumentError: REGEXP_REPLACE replacement must not contain $` or $'.");
35629
+ }
35630
+ }
35631
+ function parseRegexpOccurrence(arg) {
35632
+ if (arg === void 0) return 0;
35633
+ if (!/^\d+$/.test(arg)) {
35634
+ throw new Error("ArgumentError: REGEXP_REPLACE occurrence must be a non-negative integer.");
35635
+ }
35636
+ return Number(arg);
35637
+ }
35638
+ function expandRegexpReplacement(replacement, match, captures, namedGroups) {
35639
+ let result = "";
35640
+ for (let i = 0; i < replacement.length; i += 1) {
35641
+ const char = replacement[i];
35642
+ if (char !== "$" || i + 1 >= replacement.length) {
35643
+ result += char;
35644
+ continue;
35645
+ }
35646
+ const next = replacement[i + 1];
35647
+ if (next === "$") {
35648
+ result += "$";
35649
+ i += 1;
35650
+ continue;
35651
+ }
35652
+ if (next === "&") {
35653
+ result += match;
35654
+ i += 1;
35655
+ continue;
35656
+ }
35657
+ if (next === "<" && namedGroups !== void 0) {
35658
+ const end = replacement.indexOf(">", i + 2);
35659
+ if (end >= 0) {
35660
+ result += namedGroups[replacement.slice(i + 2, end)] ?? "";
35661
+ i = end;
35662
+ continue;
35663
+ }
35664
+ }
35665
+ if (/\d/.test(next)) {
35666
+ const secondDigit = replacement[i + 2];
35667
+ if (secondDigit !== void 0 && /\d/.test(secondDigit)) {
35668
+ const twoDigitIndex = Number(next + secondDigit);
35669
+ if (twoDigitIndex >= 1 && twoDigitIndex <= captures.length) {
35670
+ result += captures[twoDigitIndex - 1] ?? "";
35671
+ i += 2;
35672
+ continue;
35673
+ }
35674
+ }
35675
+ const oneDigitIndex = Number(next);
35676
+ if (oneDigitIndex >= 1 && oneDigitIndex <= captures.length) {
35677
+ result += captures[oneDigitIndex - 1] ?? "";
35678
+ i += 1;
35679
+ continue;
35680
+ }
35681
+ }
35682
+ result += "$";
35683
+ }
35684
+ return result;
35685
+ }
35686
+ function replaceNthMatch(input, globalRe, replacement, n) {
35687
+ let matchCount = 0;
35688
+ return input.replace(globalRe, (match, ...callbackArgs) => {
35689
+ matchCount += 1;
35690
+ if (matchCount !== n) return match;
35691
+ const lastArg = callbackArgs[callbackArgs.length - 1];
35692
+ const hasNamedGroups = typeof lastArg === "object" && lastArg !== null;
35693
+ const capturesEnd = callbackArgs.length - (hasNamedGroups ? 3 : 2);
35694
+ const captures = callbackArgs.slice(0, capturesEnd);
35695
+ const namedGroups = hasNamedGroups ? lastArg : void 0;
35696
+ return expandRegexpReplacement(replacement, match, captures, namedGroups);
35697
+ });
35698
+ }
35402
35699
  function evalStringFunc(expr, row) {
35403
35700
  const args = expr.args.map((a) => evalStringFuncArg(a, row));
35404
35701
  switch (expr.func) {
@@ -35414,23 +35711,26 @@ function evalStringFunc(expr, row) {
35414
35711
  return (args[0] ?? "").trimEnd();
35415
35712
  case "LENGTH":
35416
35713
  return String((args[0] ?? "").length);
35714
+ case "LENGTH_CHAR":
35715
+ assertArity("LENGTH_CHAR", args, 1, 1);
35716
+ return String([...args[0] ?? ""].length);
35417
35717
  case "SUBSTRING": {
35418
35718
  const str = args[0] ?? "";
35419
35719
  const start = Math.max(0, Number(args[1] ?? "1") - 1);
35420
35720
  const len = args[2] !== void 0 ? Number(args[2]) : void 0;
35421
- return len !== void 0 ? str.slice(start, start + len) : str.slice(start);
35721
+ return sliceSafeRange(str, start, len !== void 0 ? start + len : str.length);
35422
35722
  }
35423
35723
  case "LEFT": {
35424
35724
  assertArity("LEFT", args, 2, 2);
35425
35725
  const str = args[0];
35426
35726
  const n = Math.trunc(Number(args[1]));
35427
- return Number.isNaN(n) || n <= 0 ? "" : str.slice(0, n);
35727
+ return Number.isNaN(n) || n <= 0 ? "" : sliceSafePrefix(str, n);
35428
35728
  }
35429
35729
  case "RIGHT": {
35430
35730
  assertArity("RIGHT", args, 2, 2);
35431
35731
  const str = args[0];
35432
35732
  const n = Math.trunc(Number(args[1]));
35433
- return Number.isNaN(n) || n <= 0 ? "" : str.slice(Math.max(0, str.length - n));
35733
+ return Number.isNaN(n) || n <= 0 ? "" : sliceSafeSuffix(str, n);
35434
35734
  }
35435
35735
  case "INSTR":
35436
35736
  assertArity("INSTR", args, 2, 2);
@@ -35441,10 +35741,11 @@ function evalStringFunc(expr, row) {
35441
35741
  const str = args[0];
35442
35742
  const n = Math.trunc(Number(args[1]));
35443
35743
  if (Number.isNaN(n) || n <= 0) return "";
35444
- if (str.length >= n) return str.slice(0, n);
35744
+ if (str.length >= n) return sliceSafePrefix(str, n);
35445
35745
  const pad = args[2] ?? " ";
35446
35746
  if (pad === "") return str;
35447
- return expr.func === "LPAD" ? str.padStart(n, pad) : str.padEnd(n, pad);
35747
+ const padding = makeSafePadding(pad, n - str.length);
35748
+ return expr.func === "LPAD" ? padding + str : str + padding;
35448
35749
  }
35449
35750
  case "GREATEST":
35450
35751
  case "LEAST":
@@ -35458,6 +35759,36 @@ function evalStringFunc(expr, row) {
35458
35759
  const to = args[2] ?? "";
35459
35760
  return from === "" ? str : str.split(from).join(to);
35460
35761
  }
35762
+ case "REGEXP_LIKE": {
35763
+ assertArity("REGEXP_LIKE", args, 2, 3);
35764
+ return compileRegexp(args[1], args[2] ?? "").test(args[0]) ? "1" : "0";
35765
+ }
35766
+ case "REGEXP_REPLACE": {
35767
+ assertArity("REGEXP_REPLACE", args, 3, 5);
35768
+ assertRegexpReplacement(args[2]);
35769
+ const occurrence = parseRegexpOccurrence(args[4]);
35770
+ const regexp = compileRegexp(args[1], args[3] ?? "", true);
35771
+ return occurrence === 0 ? args[0].replace(regexp, args[2]) : replaceNthMatch(args[0], regexp, args[2], occurrence);
35772
+ }
35773
+ case "REGEXP_SUBSTR": {
35774
+ assertArity("REGEXP_SUBSTR", args, 2, 3);
35775
+ return compileRegexp(args[1], args[2] ?? "").exec(args[0])?.[0] ?? "";
35776
+ }
35777
+ case "TRANSLATE": {
35778
+ assertArity("TRANSLATE", args, 3, 3);
35779
+ const from = [...args[1]];
35780
+ const to = [...args[2]];
35781
+ if (from.length !== to.length) {
35782
+ throw new Error(
35783
+ `ArgumentError: TRANSLATE \u306E from \u3068 to \u306F\u540C\u3058\u6587\u5B57\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08from=${from.length}, to=${to.length}\uFF09`
35784
+ );
35785
+ }
35786
+ const map2 = /* @__PURE__ */ new Map();
35787
+ from.forEach((ch, i) => {
35788
+ if (!map2.has(ch)) map2.set(ch, to[i]);
35789
+ });
35790
+ return [...args[0]].map((ch) => map2.get(ch) ?? ch).join("");
35791
+ }
35461
35792
  case "COALESCE":
35462
35793
  return args.find((a) => a !== "") ?? "";
35463
35794
  case "NULLIF":
@@ -35621,7 +35952,7 @@ function evalStringFuncArg(arg, row) {
35621
35952
  if (arg.type === "STRING") return arg.value;
35622
35953
  if (arg.type === "STRING_FUNC") return evalStringFunc(arg, row);
35623
35954
  if (arg.type === "FIELD_REF") return resolveFieldRef(row, arg.field);
35624
- if (arg.type === "NUMBER") return String(arg.value);
35955
+ if (arg.type === "NUMBER") return numberLiteralText(arg);
35625
35956
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
35626
35957
  return String(evalArithExpr(arg, row));
35627
35958
  }
@@ -35670,7 +36001,7 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics
35670
36001
  let values = null;
35671
36002
  if (right.type === "IN_LIST") {
35672
36003
  assertResolvedInListValues2(right.values);
35673
- values = new Set(right.values.map((v) => String(v.value)));
36004
+ values = new Set(right.values.map((v) => v.type === "NUMBER" ? fieldType === "NUMBER" ? numberLiteralText(v) : String(v.value) : v.value));
35674
36005
  }
35675
36006
  if (right.type === "SUBQUERY_IN_LIST") {
35676
36007
  values = right.resolved;
@@ -35695,6 +36026,7 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics
35695
36026
  }
35696
36027
  var NUMERIC_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
35697
36028
  "LENGTH",
36029
+ "LENGTH_CHAR",
35698
36030
  "INSTR",
35699
36031
  "ROUND",
35700
36032
  "FLOOR",
@@ -35749,6 +36081,10 @@ var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"])
35749
36081
  function typedInContains(leftStr, values, fieldType) {
35750
36082
  const fallback = () => values.has(leftStr);
35751
36083
  if (fieldType === void 0) return fallback();
36084
+ if (fieldType === "NUMBER") {
36085
+ const semantics = syntheticSemantics("number");
36086
+ return [...values].some((value) => compareScalarValues("=", leftStr, value, semantics));
36087
+ }
35752
36088
  let parsed;
35753
36089
  if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
35754
36090
  try {
@@ -35807,7 +36143,7 @@ function resolveValue(value, row, resolveFieldType, resolveFieldSemantics2) {
35807
36143
  case "STRING":
35808
36144
  return value.value;
35809
36145
  case "NUMBER":
35810
- return String(value.value);
36146
+ return numberLiteralText(value);
35811
36147
  case "KINTONE_FUNC":
35812
36148
  return resolveKintoneFunc(value.name);
35813
36149
  case "IN_LIST":
@@ -35942,7 +36278,7 @@ function updateToPutBatches(stmt, ids, fieldTypes = /* @__PURE__ */ new Map()) {
35942
36278
  function buildUpdateRecord(assignments, fieldTypes) {
35943
36279
  const record2 = {};
35944
36280
  for (const { field, value } of assignments) {
35945
- if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "SOURCE_FIELD") continue;
36281
+ if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
35946
36282
  record2[field] = { value: toKintoneValue(value, fieldTypes.get(field)) };
35947
36283
  }
35948
36284
  return record2;
@@ -35952,12 +36288,19 @@ function hasArithAssignment(stmt) {
35952
36288
  (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE"
35953
36289
  );
35954
36290
  }
36291
+ function hasRowDependentAssignment(stmt) {
36292
+ return stmt.assignments.some(
36293
+ (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
36294
+ );
36295
+ }
35955
36296
  function updateToGetQueryForArith(stmt) {
35956
36297
  assertDmlWhereIsSafe(stmt.where);
35957
36298
  const refFields = /* @__PURE__ */ new Set();
35958
36299
  for (const { value } of stmt.assignments) {
35959
36300
  if (value.type === "ARITH") {
35960
36301
  collectArithFields2(value, refFields);
36302
+ } else if (value.type === "STRING_FUNC") {
36303
+ collectStringFuncFields2(value, refFields);
35961
36304
  } else if (value.type === "CASE_VALUE") {
35962
36305
  collectCaseFields(value.expr, refFields);
35963
36306
  }
@@ -36044,6 +36387,8 @@ function updateToPutBatchesArith(stmt, records, fieldTypes = /* @__PURE__ */ new
36044
36387
  for (const { field, value } of stmt.assignments) {
36045
36388
  if (value.type === "ARITH") {
36046
36389
  record2[field] = { value: String(evalArith(value, raw)) };
36390
+ } else if (value.type === "STRING_FUNC") {
36391
+ record2[field] = { value: evalStringFunc(value, row) };
36047
36392
  } else if (value.type === "CASE_VALUE") {
36048
36393
  record2[field] = { value: evalCaseWhenValue(value.expr, row, fieldTypes.get(field)) };
36049
36394
  } else if (value.type === "SOURCE_FIELD") {
@@ -36092,6 +36437,8 @@ function updateFromToPutBatches(stmt, matched, fieldTypes = /* @__PURE__ */ new
36092
36437
  throw new DmlConvertError(`\u6570\u5024\u30D5\u30A3\u30FC\u30EB\u30C9 ${field} \u306B\u5909\u63DB\u3067\u304D\u306A\u3044\u5024\u3067\u3059: ${raw}`);
36093
36438
  }
36094
36439
  record2[field] = { value: toKintoneValue({ type: "STRING", value: raw }, fieldType) };
36440
+ } else if (value.type === "STRING_FUNC") {
36441
+ throw new DmlConvertError("UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
36095
36442
  } else if (value.type === "ARITH") {
36096
36443
  record2[field] = { value: String(evalArith(value, target)) };
36097
36444
  } else if (value.type === "CASE_VALUE") {
@@ -36236,7 +36583,7 @@ function convertDmlSqlValue(value, fieldType) {
36236
36583
  case "STRING":
36237
36584
  return convertString2(value.value, fieldType);
36238
36585
  case "NUMBER":
36239
- return String(value.value);
36586
+ return numberLiteralText(value);
36240
36587
  case "ARRAY":
36241
36588
  return convertArray(value.elements.map((e) => e.value), fieldType);
36242
36589
  case "KINTONE_FUNC":
@@ -36868,7 +37215,7 @@ function evalAggArithExpr(node, rows, resolveAggSortKind) {
36868
37215
  }
36869
37216
  }
36870
37217
  function aggArithDefaultKey(node) {
36871
- if (node.type === "NUMBER") return String(node.value);
37218
+ if (node.type === "NUMBER") return numberLiteralText(node);
36872
37219
  if (node.type === "AGG_REF") return aggregateSyntheticName2(node.func, node.distinct, node.arg);
36873
37220
  return `${aggArithDefaultKey(node.left)}${node.op}${aggArithDefaultKey(node.right)}`;
36874
37221
  }
@@ -36983,6 +37330,7 @@ function compareSortKeys(a, b, meta3) {
36983
37330
  }
36984
37331
  var NUMERIC_ORDER_FUNCTIONS = /* @__PURE__ */ new Set([
36985
37332
  "LENGTH",
37333
+ "LENGTH_CHAR",
36986
37334
  "INSTR",
36987
37335
  "ROUND",
36988
37336
  "FLOOR",
@@ -37217,7 +37565,7 @@ function stripParentShortcutColumns(row) {
37217
37565
  function arithColDefaultKey(expr) {
37218
37566
  const nodeLabel = (n) => {
37219
37567
  if (n.type === "FIELD_REF") return n.field;
37220
- if (n.type === "NUMBER") return String(n.value);
37568
+ if (n.type === "NUMBER") return numberLiteralText(n);
37221
37569
  if (n.type === "STRING_FUNC") return stringFuncDefaultKey(n);
37222
37570
  return `(${nodeLabel(n.left)}${n.op}${nodeLabel(n.right)})`;
37223
37571
  };
@@ -37246,10 +37594,11 @@ function hasAggregateInStringFuncExpr2(expr) {
37246
37594
  function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
37247
37595
  if (arg.type === "AGG_REF") {
37248
37596
  const value = evalAggregate(arg.func, arg.distinct, arg.arg, arg.separator, rows, resolveAggSortKind);
37249
- return typeof value === "number" ? { type: "NUMBER", value } : { type: "STRING", value };
37597
+ return typeof value === "number" ? { type: "NUMBER", value, raw: String(value) } : { type: "STRING", value };
37250
37598
  }
37251
37599
  if (arg.type === "AGG_ARITH") {
37252
- return { type: "NUMBER", value: evalAggArithExpr(arg, rows, resolveAggSortKind) };
37600
+ const value = evalAggArithExpr(arg, rows, resolveAggSortKind);
37601
+ return { type: "NUMBER", value, raw: String(value) };
37253
37602
  }
37254
37603
  if (arg.type === "STRING_FUNC") {
37255
37604
  return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
@@ -37367,10 +37716,43 @@ function toFlatString(value) {
37367
37716
  }
37368
37717
  }
37369
37718
 
37719
+ // src/core/numberPrecision.ts
37720
+ function parseIntegerSetting(value, name, min, max) {
37721
+ if (typeof value !== "string" || !/^\d+$/.test(value)) {
37722
+ throw new Error(`SettingsError: numberPrecision.${name} must be an integer string.`);
37723
+ }
37724
+ let parsed = 0;
37725
+ for (const digit of value) parsed = parsed * 10 + digit.charCodeAt(0) - 48;
37726
+ if (parsed < min || parsed > max) {
37727
+ throw new Error(`SettingsError: numberPrecision.${name} must be between ${min} and ${max}.`);
37728
+ }
37729
+ return parsed;
37730
+ }
37731
+ function parseNumberPrecisionSettings(response) {
37732
+ const raw = response.numberPrecision;
37733
+ if (raw === void 0 || raw === null || typeof raw !== "object") {
37734
+ throw new Error("SettingsError: numberPrecision is missing from app settings.");
37735
+ }
37736
+ const digits = parseIntegerSetting(raw.digits, "digits", 1, 30);
37737
+ const decimalPlaces = parseIntegerSetting(raw.decimalPlaces, "decimalPlaces", 0, 10);
37738
+ const roundingMode = raw.roundingMode;
37739
+ if (roundingMode !== "HALF_EVEN" && roundingMode !== "UP" && roundingMode !== "DOWN") {
37740
+ throw new Error("SettingsError: numberPrecision.roundingMode is unsupported.");
37741
+ }
37742
+ return { digits, decimalPlaces, roundingMode };
37743
+ }
37744
+ function exactDecimalDigitCounts(value) {
37745
+ if (value.sign === 0) return { integerDigits: 0, fractionDigits: 0 };
37746
+ return {
37747
+ integerDigits: Math.max(value.coefficient.length - value.scale, 0),
37748
+ fractionDigits: Math.max(value.scale, 0)
37749
+ };
37750
+ }
37751
+
37370
37752
  // src/core/dmlValidation.ts
37371
37753
  var ARRAY_TYPES2 = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
37372
37754
  var CHOICE_TYPES = /* @__PURE__ */ new Set(["DROP_DOWN", "RADIO_BUTTON", "CHECK_BOX", "MULTI_SELECT"]);
37373
- function validateAndNormalizeDmlValue(raw, field) {
37755
+ function validateAndNormalizeDmlValue(raw, field, numberPrecision) {
37374
37756
  if (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME") {
37375
37757
  const original = rawScalarText(raw);
37376
37758
  if (original !== "" && !isValidTemporalInput(original, field.fieldType)) {
@@ -37389,7 +37771,8 @@ function validateAndNormalizeDmlValue(raw, field) {
37389
37771
  }
37390
37772
  if (!isEmpty(value) && field.fieldType === "NUMBER") {
37391
37773
  const text = String(value);
37392
- if (!isFiniteDecimal(text)) {
37774
+ const decimal = parseExactDecimal(text);
37775
+ if (decimal === null) {
37393
37776
  return { ok: false, code: "ERR_TYPE_NUMBER", message: `${field.code} \u306F\u6570\u5024\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044` };
37394
37777
  }
37395
37778
  if (field.minValue != null && compareDecimal(text, field.minValue) < 0) {
@@ -37398,6 +37781,17 @@ function validateAndNormalizeDmlValue(raw, field) {
37398
37781
  if (field.maxValue != null && compareDecimal(text, field.maxValue) > 0) {
37399
37782
  return { ok: false, code: "ERR_RANGE_MAX", message: `${field.code} \u306F ${field.maxValue} \u4EE5\u4E0B\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044` };
37400
37783
  }
37784
+ if (numberPrecision !== void 0) {
37785
+ const { integerDigits } = exactDecimalDigitCounts(decimal);
37786
+ const integerBudget = numberPrecision.digits - numberPrecision.decimalPlaces;
37787
+ if (integerDigits > integerBudget) {
37788
+ return {
37789
+ ok: false,
37790
+ code: "ERR_NUMBER_INTEGER_DIGITS",
37791
+ 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})`
37792
+ };
37793
+ }
37794
+ }
37401
37795
  }
37402
37796
  if (!isEmpty(value) && (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME")) {
37403
37797
  if (!isValidTemporal(String(value), field.fieldType)) {
@@ -37425,7 +37819,8 @@ function validateAndNormalizeDmlValue(raw, field) {
37425
37819
  }
37426
37820
  function rawScalarText(raw) {
37427
37821
  if (raw == null) return "";
37428
- if (isSqlValue(raw) && (raw.type === "STRING" || raw.type === "NUMBER")) return String(raw.value);
37822
+ if (isSqlValue(raw) && raw.type === "NUMBER") return numberLiteralText(raw);
37823
+ if (isSqlValue(raw) && raw.type === "STRING") return raw.value;
37429
37824
  return typeof raw === "string" || typeof raw === "number" ? String(raw) : "";
37430
37825
  }
37431
37826
  function isValidTemporalInput(value, type) {
@@ -37475,34 +37870,6 @@ function isEmpty(value) {
37475
37870
  function typeCode(type) {
37476
37871
  return type === "NUMBER" ? "ERR_TYPE_NUMBER" : "ERR_TYPE_DATE";
37477
37872
  }
37478
- function isFiniteDecimal(value) {
37479
- return /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(value.trim());
37480
- }
37481
- function compareDecimal(left, right) {
37482
- const normalize = (input) => {
37483
- let s = input.trim();
37484
- let sign = 1;
37485
- if (s.startsWith("-")) {
37486
- sign = -1;
37487
- s = s.slice(1);
37488
- } else if (s.startsWith("+")) s = s.slice(1);
37489
- let [whole, fraction = ""] = s.split(".");
37490
- whole = (whole || "0").replace(/^0+(?=\d)/, "");
37491
- fraction = fraction.replace(/0+$/, "");
37492
- if (/^0*$/.test(whole) && fraction === "") sign = 1;
37493
- return { sign, whole, fraction };
37494
- };
37495
- const a = normalize(left);
37496
- const b = normalize(right);
37497
- if (a.sign !== b.sign) return a.sign < b.sign ? -1 : 1;
37498
- const direction = a.sign;
37499
- if (a.whole.length !== b.whole.length) return a.whole.length < b.whole.length ? -direction : direction;
37500
- if (a.whole !== b.whole) return a.whole < b.whole ? -direction : direction;
37501
- const width = Math.max(a.fraction.length, b.fraction.length);
37502
- const af = a.fraction.padEnd(width, "0");
37503
- const bf = b.fraction.padEnd(width, "0");
37504
- return af === bf ? 0 : af < bf ? -direction : direction;
37505
- }
37506
37873
  function isValidTemporal(value, type) {
37507
37874
  if (type === "TIME") {
37508
37875
  const m2 = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
@@ -37530,7 +37897,7 @@ var VALIDATION_META_COLUMNS = [
37530
37897
  "$err_code",
37531
37898
  "$err_message"
37532
37899
  ];
37533
- function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber) {
37900
+ function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision) {
37534
37901
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
37535
37902
  const errors = [];
37536
37903
  const invalid = /* @__PURE__ */ new Set();
@@ -37538,7 +37905,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37538
37905
  candidate.record ??= {};
37539
37906
  const rowErrors = [...candidate.preErrors];
37540
37907
  for (const code of targetFields) {
37541
- const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code));
37908
+ const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
37542
37909
  if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
37543
37910
  else candidate.record[code] = { value: result.value };
37544
37911
  }
@@ -37548,14 +37915,14 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37548
37915
  if (candidate.payload.has(info.code)) continue;
37549
37916
  const emptyDefault = isEmptyDmlValue(info.defaultValue);
37550
37917
  if (!emptyDefault) {
37551
- const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info);
37918
+ const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info, numberPrecision);
37552
37919
  if (!defaultResult.ok) rowErrors.push({
37553
37920
  field: info.code,
37554
37921
  code: defaultResult.code,
37555
37922
  message: `\u65E2\u5B9A\u5024: ${defaultResult.message}`
37556
37923
  });
37557
37924
  } else {
37558
- const emptyResult = validateAndNormalizeDmlValue("", info);
37925
+ const emptyResult = validateAndNormalizeDmlValue("", info, numberPrecision);
37559
37926
  if (!emptyResult.ok) {
37560
37927
  rowErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
37561
37928
  } else if (info.required) {
@@ -37583,7 +37950,8 @@ function renderValidationValue(value) {
37583
37950
  if (value == null) return "";
37584
37951
  if (typeof value === "object" && "type" in value) {
37585
37952
  const sql = value;
37586
- if (sql.type === "STRING" || sql.type === "NUMBER") return String(sql.value ?? "");
37953
+ if (sql.type === "NUMBER") return sql.raw ?? String(sql.value ?? "");
37954
+ if (sql.type === "STRING") return String(sql.value ?? "");
37587
37955
  if (sql.type === "ARRAY") return JSON.stringify(sql.elements?.map((e) => e.value) ?? []);
37588
37956
  }
37589
37957
  if (Array.isArray(value)) return JSON.stringify(value);
@@ -37825,6 +38193,7 @@ function createEmptyMetrics() {
37825
38193
  putCalls: 0,
37826
38194
  deleteCalls: 0,
37827
38195
  fieldCalls: 0,
38196
+ numberPrecisionCalls: 0,
37828
38197
  appsCalls: 0,
37829
38198
  processStatusCalls: 0,
37830
38199
  cursorCreateCalls: 0,
@@ -37910,6 +38279,10 @@ function wrapClientWithMetrics(client, metrics) {
37910
38279
  metrics.fieldCalls += 1;
37911
38280
  return client.getFields(appId);
37912
38281
  },
38282
+ getNumberPrecision: (appId) => {
38283
+ metrics.numberPrecisionCalls += 1;
38284
+ return client.getNumberPrecision(appId);
38285
+ },
37913
38286
  getProcessStatuses: (appId) => {
37914
38287
  metrics.processStatusCalls += 1;
37915
38288
  return client.getProcessStatuses(appId);
@@ -38177,7 +38550,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
38177
38550
  const first = resolvedStmt2.expr.query.columns[0];
38178
38551
  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");
38179
38552
  const numberValue = numeric ? Number(value) : Number.NaN;
38180
- variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue } : { type: "string", value });
38553
+ variables.set(stmt.name, numeric && Number.isFinite(numberValue) ? { type: "number", value: numberValue, raw: value } : { type: "string", value });
38181
38554
  } catch (e) {
38182
38555
  if (e instanceof ScalarSubqueryError) {
38183
38556
  throw new Error(`ArgumentError: ${e.message}`);
@@ -38195,7 +38568,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
38195
38568
  variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
38196
38569
  } else {
38197
38570
  const value = evaluateScalarExpr(stmt.default);
38198
- variables.set(stmt.name, { type: "string", value: String(value.value) });
38571
+ variables.set(stmt.name, {
38572
+ type: "string",
38573
+ value: value.type === "number" ? value.raw ?? String(value.value) : value.value
38574
+ });
38199
38575
  }
38200
38576
  return {};
38201
38577
  }
@@ -38371,7 +38747,7 @@ function evaluateScalarExpr(expr) {
38371
38747
  case "STRING":
38372
38748
  return { type: "string", value: expr.value };
38373
38749
  case "NUMBER":
38374
- return { type: "number", value: expr.value };
38750
+ return { type: "number", value: expr.value, raw: numberLiteralText(expr) };
38375
38751
  case "KINTONE_FUNC":
38376
38752
  return { type: "string", value: resolveKintoneFunc(expr.name) };
38377
38753
  case "STRING_FUNC":
@@ -38381,7 +38757,7 @@ function evaluateScalarExpr(expr) {
38381
38757
  if (!Number.isFinite(value)) {
38382
38758
  throw new Error("ArgumentError: SET scalar arithmetic produced a non-finite number.");
38383
38759
  }
38384
- return { type: "number", value };
38760
+ return { type: "number", value, raw: String(value) };
38385
38761
  }
38386
38762
  }
38387
38763
  }
@@ -38396,7 +38772,7 @@ function resolveVariableRefs(node, variables) {
38396
38772
  if (value === void 0) {
38397
38773
  throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
38398
38774
  }
38399
- return value.type === "number" ? { type: "NUMBER", value: value.value } : { type: "STRING", value: value.value };
38775
+ return value.type === "number" ? { type: "NUMBER", value: value.value, raw: value.raw ?? String(value.value) } : { type: "STRING", value: value.value };
38400
38776
  }
38401
38777
  return Object.fromEntries(
38402
38778
  Object.entries(obj).map(([key, value]) => [key, resolveVariableRefs(value, variables)])
@@ -38462,7 +38838,7 @@ async function evalAssertOperand(operand, client, options, cacheContext, tempTab
38462
38838
  case "VARIABLE":
38463
38839
  throw new Error(`ParseError: unresolved batch variable @${operand.name}.`);
38464
38840
  case "NUMBER":
38465
- return String(operand.value);
38841
+ return numberLiteralText(operand);
38466
38842
  case "STRING":
38467
38843
  return operand.value;
38468
38844
  case "ARITH":
@@ -39203,6 +39579,7 @@ function systemColumnMeta(field) {
39203
39579
  }
39204
39580
  var NUMBER_RETURNING_STRING_FUNCTIONS = /* @__PURE__ */ new Set([
39205
39581
  "LENGTH",
39582
+ "LENGTH_CHAR",
39206
39583
  "INSTR",
39207
39584
  "ROUND",
39208
39585
  "FLOOR",
@@ -39744,8 +40121,8 @@ async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, pa
39744
40121
  }
39745
40122
  var UPSERT_IN_CHUNK_SIZE = 50;
39746
40123
  function normalizeKeyPart(v) {
39747
- const t = v.trim();
39748
- if (t !== "" && !Number.isNaN(Number(t))) return String(Number(t));
40124
+ const decimal = parseExactDecimal(v);
40125
+ if (decimal !== null) return JSON.stringify(decimal);
39749
40126
  return v;
39750
40127
  }
39751
40128
  function upsertCompositeKey(parts) {
@@ -39897,6 +40274,7 @@ var optionOrderCache = /* @__PURE__ */ new Map();
39897
40274
  var sortKindCache = /* @__PURE__ */ new Map();
39898
40275
  var fieldInfoCache = /* @__PURE__ */ new Map();
39899
40276
  var processStatusCache = /* @__PURE__ */ new Map();
40277
+ var numberPrecisionCache = /* @__PURE__ */ new Map();
39900
40278
  function getScopedCacheValue(root, cacheContext, appId) {
39901
40279
  return root.get(cacheContext)?.get(appId);
39902
40280
  }
@@ -39918,6 +40296,13 @@ async function getFieldsCached(appId, client, cacheContext) {
39918
40296
  setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
39919
40297
  return loading;
39920
40298
  }
40299
+ async function getNumberPrecisionCached(appId, client, cacheContext) {
40300
+ const cached2 = getScopedCacheValue(numberPrecisionCache, cacheContext, appId);
40301
+ if (cached2) return cached2;
40302
+ const loading = client.getNumberPrecision(appId);
40303
+ setScopedCacheValue(numberPrecisionCache, cacheContext, appId, loading);
40304
+ return loading;
40305
+ }
39921
40306
  async function getProcessStatusesCached(appId, client, cacheContext) {
39922
40307
  const cached2 = getScopedCacheValue(processStatusCache, cacheContext, appId);
39923
40308
  if (cached2) return cached2;
@@ -40170,6 +40555,45 @@ var NON_WRITABLE_FIELD_TYPES = /* @__PURE__ */ new Set([
40170
40555
  "CATEGORY",
40171
40556
  "REFERENCE_TABLE"
40172
40557
  ]);
40558
+ function assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos) {
40559
+ const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
40560
+ for (const code of targetFields) {
40561
+ const info = infoByCode.get(code);
40562
+ if (!info) {
40563
+ throw new Error(`ArgumentError: DML target field ${code} does not exist.`);
40564
+ }
40565
+ if (info.inSubtable) {
40566
+ throw new Error(
40567
+ `ArgumentError: DML target field ${code} is inside a subtable. Use subtable DML syntax (for example, APP${appId}$\u30C6\u30FC\u30D6\u30EB).`
40568
+ );
40569
+ }
40570
+ if (info.writable === false || NON_WRITABLE_FIELD_TYPES.has(info.fieldType)) {
40571
+ throw new Error(`ArgumentError: DML target field ${code} is not writable (${info.fieldType}).`);
40572
+ }
40573
+ }
40574
+ }
40575
+ async function loadWritableTopLevelDmlFields(appId, targetFields, client, cacheContext) {
40576
+ const fieldInfos = await getFieldsCached(appId, client, cacheContext);
40577
+ assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos);
40578
+ return fieldInfos;
40579
+ }
40580
+ async function loadNumberPrecisionForTargets(appId, targetFields, fieldInfos, client, cacheContext) {
40581
+ const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
40582
+ return targetFields.some((code) => infoByCode.get(code)?.fieldType === "NUMBER") ? getNumberPrecisionCached(appId, client, cacheContext) : void 0;
40583
+ }
40584
+ function assertValidDmlRecords(records, targetFields, fieldInfos, numberPrecision) {
40585
+ const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
40586
+ records.forEach((record2, rowIndex) => {
40587
+ for (const code of targetFields) {
40588
+ const info = infoByCode.get(code);
40589
+ const result = validateAndNormalizeDmlValue(record2[code]?.value ?? "", info, numberPrecision);
40590
+ if (!result.ok) {
40591
+ throw new Error(`DmlValidationError: ${result.code} ${result.message} (row=${rowIndex + 1}, field=${code})`);
40592
+ }
40593
+ record2[code] = { value: result.value };
40594
+ }
40595
+ });
40596
+ }
40173
40597
  async function executeDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
40174
40598
  return (await prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber)).result;
40175
40599
  }
@@ -40181,24 +40605,29 @@ var RejectLimitExceededError = class extends Error {
40181
40605
  }
40182
40606
  };
40183
40607
  async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
40184
- if (stmt.type === "UPDATE") {
40185
- await assertDmlWhereCapability(stmt, client, cacheContext);
40186
- }
40187
40608
  const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
40188
40609
  const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
40189
40610
  if (new Set(payloadFields).size !== payloadFields.length) {
40190
40611
  throw new Error("ArgumentError: DML target fields contain duplicates.");
40191
40612
  }
40192
- const fieldInfos = await getFieldsCached(stmt.appId, client, cacheContext);
40193
- const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
40194
40613
  const targetFields = stmt.type === "UPDATE" ? stmt.assignments.map((a) => a.field) : stmt.fields;
40195
- for (const code of targetFields) {
40196
- const info = infoByCode.get(code);
40197
- if (!info) throw new Error(`ArgumentError: DML target field ${code} does not exist.`);
40198
- if (info.writable === false || NON_WRITABLE_FIELD_TYPES.has(info.fieldType)) {
40199
- throw new Error(`ArgumentError: DML target field ${code} is not writable (${info.fieldType}).`);
40200
- }
40614
+ const fieldInfos = await loadWritableTopLevelDmlFields(
40615
+ stmt.appId,
40616
+ targetFields,
40617
+ client,
40618
+ cacheContext
40619
+ );
40620
+ if (stmt.type === "UPDATE") {
40621
+ await assertDmlWhereCapability(stmt, client, cacheContext);
40201
40622
  }
40623
+ const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
40624
+ const numberPrecision = await loadNumberPrecisionForTargets(
40625
+ stmt.appId,
40626
+ targetFields,
40627
+ fieldInfos,
40628
+ client,
40629
+ cacheContext
40630
+ );
40202
40631
  const candidates = await materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode);
40203
40632
  const { errors, invalidRows, invalidRowNumbers } = validateDmlCandidates(
40204
40633
  candidates,
@@ -40206,7 +40635,8 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
40206
40635
  payloadFields,
40207
40636
  targetFields,
40208
40637
  fieldInfos,
40209
- statementNumber
40638
+ statementNumber,
40639
+ numberPrecision
40210
40640
  );
40211
40641
  const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
40212
40642
  const result = {
@@ -40367,7 +40797,7 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
40367
40797
  await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
40368
40798
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40369
40799
  let records;
40370
- if (hasArithAssignment(stmt)) {
40800
+ if (hasRowDependentAssignment(stmt)) {
40371
40801
  const getParams = updateToGetQueryForArith(stmt);
40372
40802
  const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [...getParams.fields], {
40373
40803
  maxRecords: options.maxRecords ?? 1e4,
@@ -40430,6 +40860,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40430
40860
  tempTables
40431
40861
  );
40432
40862
  const sourceByKey = /* @__PURE__ */ new Map();
40863
+ const sourceQueryByKey = /* @__PURE__ */ new Map();
40433
40864
  for (const row of sourceRows) {
40434
40865
  if (!Object.prototype.hasOwnProperty.call(row, from.joinKeyField)) {
40435
40866
  throw new Error(`ArgumentError: UPDATE ... FROM source column ${from.joinKeyField} does not exist.`);
@@ -40439,6 +40870,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40439
40870
  throw new Error(`ArgumentError: UPDATE ... FROM source has multiple rows for normalized key ${key}.`);
40440
40871
  }
40441
40872
  sourceByKey.set(key, row);
40873
+ sourceQueryByKey.set(key, String(row[from.joinKeyField]).trim());
40442
40874
  }
40443
40875
  if (sourceByKey.size === 0) return [];
40444
40876
  const maxRecords2 = options.maxRecords ?? 1e4;
@@ -40447,7 +40879,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40447
40879
  const targetRecords = [];
40448
40880
  const seenTargetIds = /* @__PURE__ */ new Set();
40449
40881
  let fetchedTargetCount = 0;
40450
- for (const keys of splitChunks([...sourceByKey.keys()], UPDATE_FROM_KEY_CHUNK_SIZE)) {
40882
+ for (const keys of splitChunks([...sourceQueryByKey.values()], UPDATE_FROM_KEY_CHUNK_SIZE)) {
40451
40883
  const keyQuery = `${from.targetJoinField} in (${keys.map(sqlQuote).join(",")})`;
40452
40884
  const query = filterQuery ? `(${keyQuery}) and (${filterQuery})` : keyQuery;
40453
40885
  const resolved = await fetchRecordsForSharedPlan(
@@ -40548,36 +40980,28 @@ function normalizeUpdateFromJoinKey(raw, kind, side) {
40548
40980
  }
40549
40981
  if (kind === "number" && side === "target" && raw === "") return null;
40550
40982
  if (kind === "id") {
40551
- const text2 = raw.trim();
40552
- const id = Number(text2);
40553
- if (text2 === "" || !Number.isSafeInteger(id) || id <= 0) {
40983
+ const text = raw.trim();
40984
+ const id = Number(text);
40985
+ if (text === "" || !Number.isSafeInteger(id) || id <= 0) {
40554
40986
  throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a positive safe integer: ${raw}`);
40555
40987
  }
40556
40988
  return String(id);
40557
40989
  }
40558
- const text = raw.trim();
40559
- if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(text)) {
40990
+ const decimal = parseExactDecimal(raw);
40991
+ if (decimal === null) {
40560
40992
  throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a finite decimal: ${raw}`);
40561
40993
  }
40562
- let unsigned = text;
40563
- let negative = false;
40564
- if (unsigned.startsWith("-") || unsigned.startsWith("+")) {
40565
- negative = unsigned[0] === "-";
40566
- unsigned = unsigned.slice(1);
40567
- }
40568
- let [whole, fraction = ""] = unsigned.split(".");
40569
- whole = (whole || "0").replace(/^0+(?=\d)/, "");
40570
- fraction = fraction.replace(/0+$/, "");
40571
- const zero = /^0*$/.test(whole) && fraction === "";
40572
- const canonical = fraction === "" ? whole : `${whole}.${fraction}`;
40573
- return negative && !zero ? `-${canonical}` : canonical;
40994
+ return JSON.stringify(decimal);
40574
40995
  }
40575
40996
  async function executeInsert(stmt, client, options, cacheContext) {
40576
40997
  if (stmt.subtableCode) {
40577
40998
  return executeInsertSubtable(stmt, client, options, cacheContext);
40578
40999
  }
41000
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41001
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40579
41002
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40580
41003
  const batches = insertToPostBatches(stmt, fieldTypes);
41004
+ assertValidDmlRecords(batches.flatMap((batch) => batch.records), stmt.fields, fieldInfos, numberPrecision);
40581
41005
  const createdIds = [];
40582
41006
  for (const batch of batches) {
40583
41007
  const res = await client.postRecords(batch);
@@ -40590,6 +41014,8 @@ async function executeInsert(stmt, client, options, cacheContext) {
40590
41014
  };
40591
41015
  }
40592
41016
  async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
41017
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41018
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40593
41019
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
40594
41020
  const { rows, columns } = selectResult;
40595
41021
  if (columns.length !== stmt.fields.length) {
@@ -40611,6 +41037,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
40611
41037
  });
40612
41038
  return record2;
40613
41039
  });
41040
+ assertValidDmlRecords(allRecords, stmt.fields, fieldInfos, numberPrecision);
40614
41041
  const createdIds = [];
40615
41042
  for (let i = 0; i < allRecords.length; i += 100) {
40616
41043
  const batch = allRecords.slice(i, i + 100);
@@ -40624,17 +41051,32 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
40624
41051
  };
40625
41052
  }
40626
41053
  async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40627
- await assertDmlWhereCapability(stmt, client, cacheContext);
40628
41054
  if (stmt.subtableCode) {
41055
+ await assertDmlWhereCapability(stmt, client, cacheContext);
40629
41056
  return executeUpdateSubtable(stmt, client, options, cacheContext);
40630
41057
  }
41058
+ const fieldInfos = await loadWritableTopLevelDmlFields(
41059
+ stmt.appId,
41060
+ stmt.assignments.map((assignment) => assignment.field),
41061
+ client,
41062
+ cacheContext
41063
+ );
41064
+ const targetFields = stmt.assignments.map((assignment) => assignment.field);
41065
+ const numberPrecision = await loadNumberPrecisionForTargets(
41066
+ stmt.appId,
41067
+ targetFields,
41068
+ fieldInfos,
41069
+ client,
41070
+ cacheContext
41071
+ );
41072
+ await assertDmlWhereCapability(stmt, client, cacheContext);
40631
41073
  if (stmt.from != null) {
40632
41074
  return executeUpdateFrom(stmt, stmt.from, client, options, cacheContext, tempTables);
40633
41075
  }
40634
41076
  const maxRecords2 = options.maxRecords ?? 1e4;
40635
41077
  await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
40636
41078
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40637
- if (hasArithAssignment(stmt)) {
41079
+ if (hasRowDependentAssignment(stmt)) {
40638
41080
  const getParams2 = updateToGetQueryForArith(stmt);
40639
41081
  const resolved2 = await fetchRecordsForSharedPlan(
40640
41082
  client.getRecords,
@@ -40644,11 +41086,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40644
41086
  { maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
40645
41087
  );
40646
41088
  const records = resolved2.records;
41089
+ const batches2 = updateToPutBatchesArith(stmt, records, fieldTypes);
41090
+ assertValidDmlRecords(batches2.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
40647
41091
  if (options.confirm) {
40648
41092
  const ok = await options.confirm(records.length, "UPDATE");
40649
41093
  if (!ok) throw new OperationCancelledError("UPDATE", records.length);
40650
41094
  }
40651
- const batches2 = updateToPutBatchesArith(stmt, records, fieldTypes);
40652
41095
  for (const batch of batches2) {
40653
41096
  await client.putRecords(batch);
40654
41097
  }
@@ -40662,11 +41105,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40662
41105
  { maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
40663
41106
  );
40664
41107
  const ids = resolved.ids;
41108
+ const batches = updateToPutBatches(stmt, ids, fieldTypes);
41109
+ assertValidDmlRecords(batches.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
40665
41110
  if (options.confirm) {
40666
41111
  const ok = await options.confirm(ids.length, "UPDATE");
40667
41112
  if (!ok) throw new OperationCancelledError("UPDATE", ids.length);
40668
41113
  }
40669
- const batches = updateToPutBatches(stmt, ids, fieldTypes);
40670
41114
  for (const batch of batches) {
40671
41115
  await client.putRecords(batch);
40672
41116
  }
@@ -40674,12 +41118,16 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40674
41118
  }
40675
41119
  async function executeUpdateFrom(stmt, from, client, options, cacheContext, tempTables) {
40676
41120
  const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
41121
+ const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
41122
+ const batches = updateFromToPutBatches(stmt, matched, fieldTypes);
41123
+ const targetFields = stmt.assignments.map((assignment) => assignment.field);
41124
+ const fieldInfos = await getFieldsCached(stmt.appId, client, cacheContext);
41125
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, targetFields, fieldInfos, client, cacheContext);
41126
+ assertValidDmlRecords(batches.flatMap((batch) => batch.records.map((entry) => entry.record)), targetFields, fieldInfos, numberPrecision);
40677
41127
  if (options.confirm) {
40678
41128
  const ok = await options.confirm(matched.length, "UPDATE");
40679
41129
  if (!ok) throw new OperationCancelledError("UPDATE", matched.length);
40680
41130
  }
40681
- const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40682
- const batches = updateFromToPutBatches(stmt, matched, fieldTypes);
40683
41131
  for (const batch of batches) await client.putRecords(batch);
40684
41132
  return { type: "UPDATE", updatedCount: matched.length };
40685
41133
  }
@@ -40728,6 +41176,8 @@ async function executeDelete(stmt, client, options, cacheContext) {
40728
41176
  return { type: "DELETE", deletedCount: ids.length };
40729
41177
  }
40730
41178
  async function executeUpsert(stmt, client, options, cacheContext) {
41179
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41180
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40731
41181
  const toInsert = [];
40732
41182
  const toUpdate = [];
40733
41183
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
@@ -40736,7 +41186,7 @@ async function executeUpsert(stmt, client, options, cacheContext) {
40736
41186
  const idx = stmt.fields.indexOf(key);
40737
41187
  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`);
40738
41188
  const val = row[idx];
40739
- 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(",");
41189
+ 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(",");
40740
41190
  })
40741
41191
  );
40742
41192
  const targetIndex = await resolveUpsertTargets(stmt.appId, stmt.keyFields, rowKeyValues, client, options, fieldTypes);
@@ -40757,6 +41207,12 @@ async function executeUpsert(stmt, client, options, cacheContext) {
40757
41207
  toInsert.push(record2);
40758
41208
  }
40759
41209
  });
41210
+ assertValidDmlRecords(
41211
+ [...toInsert, ...toUpdate.map((entry) => entry.record)],
41212
+ stmt.fields,
41213
+ fieldInfos,
41214
+ numberPrecision
41215
+ );
40760
41216
  if (options.confirm && toInsert.length + toUpdate.length > 0) {
40761
41217
  const total = toInsert.length + toUpdate.length;
40762
41218
  const ok = await options.confirm(total, "UPDATE");
@@ -41032,14 +41488,14 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
41032
41488
  }
41033
41489
  function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
41034
41490
  if (value.type === "STRING") return value.value;
41035
- if (value.type === "NUMBER") return String(value.value);
41491
+ if (value.type === "NUMBER") return numberLiteralText(value);
41036
41492
  if (value.type === "ARITH") return String(evalArithExpr(value, row));
41037
41493
  if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
41038
41494
  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`);
41039
41495
  }
41040
41496
  function valueToString(value) {
41041
41497
  if (value.type === "STRING") return value.value;
41042
- if (value.type === "NUMBER") return String(value.value);
41498
+ if (value.type === "NUMBER") return numberLiteralText(value);
41043
41499
  if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, {});
41044
41500
  return value.elements.map((e) => e.value).join(",");
41045
41501
  }
@@ -41154,6 +41610,8 @@ function evalOrderKeyForRow(key, row) {
41154
41610
  }
41155
41611
  }
41156
41612
  async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
41613
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41614
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
41157
41615
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
41158
41616
  const { rows, columns } = selectResult;
41159
41617
  if (columns.length !== stmt.fields.length) {
@@ -41176,6 +41634,7 @@ async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache
41176
41634
  });
41177
41635
  return record2;
41178
41636
  });
41637
+ assertValidDmlRecords(records, stmt.fields, fieldInfos, numberPrecision);
41179
41638
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
41180
41639
  const rowKeyValues = records.map(
41181
41640
  (record2) => stmt.keyFields.map((key) => String(record2[key]?.value ?? ""))
@@ -41789,6 +42248,8 @@ function buildInsertSelectPlan(stmt, label, capabilities, orderPlans) {
41789
42248
  }
41790
42249
  function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
41791
42250
  const isArith = hasArithAssignment(stmt);
42251
+ const isStringFunc = stmt.assignments.some((a) => a.value.type === "STRING_FUNC");
42252
+ const isRowDependent = hasRowDependentAssignment(stmt);
41792
42253
  const isSubq = stmt.assignments.some((a) => a.value.type === "SCALAR_SUBQUERY");
41793
42254
  const lines = [];
41794
42255
  if (label) lines.push(label);
@@ -41805,10 +42266,11 @@ function buildUpdatePlan(stmt, label, capabilities, orderPlans) {
41805
42266
  lines.push(` api: GET /k/v1/records.json \u2192 PUT /k/v1/records.json`);
41806
42267
  const setTypes = [];
41807
42268
  if (isArith) setTypes.push("\u7B97\u8853 SET\uFF08\u73FE\u5728\u5024\u3092\u53D6\u5F97\u3057\u3066\u8A08\u7B97\uFF09");
42269
+ if (isStringFunc) setTypes.push("\u6587\u5B57\u5217\u95A2\u6570 SET\uFF08\u73FE\u5728\u5024\u3092\u53D6\u5F97\u3057\u3066\u8A55\u4FA1\uFF09");
41808
42270
  if (isSubq) setTypes.push("\u30B9\u30AB\u30E9\u30FC\u30B5\u30D6\u30AF\u30A8\u30EA SET");
41809
- if (!isArith && !isSubq) setTypes.push("\u5358\u7D14 SET");
42271
+ if (!isRowDependent && !isSubq) setTypes.push("\u5358\u7D14 SET");
41810
42272
  lines.push(` set type: ${setTypes.join(", ")}`);
41811
- if (isArith) {
42273
+ if (isRowDependent) {
41812
42274
  const refFields = collectArithRefFields(stmt);
41813
42275
  if (refFields.length > 0) {
41814
42276
  lines.push(` ref fields: ${refFields.join(", ")}\uFF08GET \u306B\u542B\u3081\u308B\uFF09`);
@@ -41894,6 +42356,7 @@ function collectArithRefFields(stmt) {
41894
42356
  const refs = /* @__PURE__ */ new Set();
41895
42357
  for (const { value } of stmt.assignments) {
41896
42358
  if (value.type === "ARITH") collectArithNodeRefs(value, refs);
42359
+ if (value.type === "STRING_FUNC") collectArithNodeRefs(value, refs);
41897
42360
  }
41898
42361
  return [...refs];
41899
42362
  }
@@ -41906,6 +42369,13 @@ function collectArithNodeRefs(node, out) {
41906
42369
  collectArithNodeRefs(node.left, out);
41907
42370
  collectArithNodeRefs(node.right, out);
41908
42371
  }
42372
+ if (node.type === "STRING_FUNC") {
42373
+ for (const arg of node.args) {
42374
+ if (arg.type !== "STRING" && arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") {
42375
+ collectArithNodeRefs(arg, out);
42376
+ }
42377
+ }
42378
+ }
41909
42379
  }
41910
42380
  function formatAssignment(a) {
41911
42381
  const v = a.value;
@@ -41913,6 +42383,7 @@ function formatAssignment(a) {
41913
42383
  if (v.type === "NUMBER") return `${a.field} = ${v.value}`;
41914
42384
  if (v.type === "ARITH") return `${a.field} = ${formatArithExprStr(v)}`;
41915
42385
  if (v.type === "CASE_VALUE") return `${a.field} = CASE WHEN ...`;
42386
+ if (v.type === "STRING_FUNC") return `${a.field} = ${v.func}(...)`;
41916
42387
  if (v.type === "SCALAR_SUBQUERY") return `${a.field} = (SELECT ...)`;
41917
42388
  if (v.type === "SOURCE_FIELD") return `${a.field} = ${v.alias}.${v.field}`;
41918
42389
  return `${a.field} = (${v.type})`;
@@ -41922,7 +42393,7 @@ function formatArithExprStr(expr) {
41922
42393
  }
41923
42394
  function formatArithNodeStr(node) {
41924
42395
  if (node.type === "FIELD_REF") return node.field;
41925
- if (node.type === "NUMBER") return String(node.value);
42396
+ if (node.type === "NUMBER") return numberLiteralText(node);
41926
42397
  if (node.type === "ARITH") return `(${formatArithExprStr(node)})`;
41927
42398
  return "...";
41928
42399
  }
@@ -42384,6 +42855,7 @@ function withRequestGate(client, gate) {
42384
42855
  },
42385
42856
  getApps: () => gate.runReadOnly(() => client.getApps()),
42386
42857
  getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
42858
+ getNumberPrecision: (appId) => gate.runReadOnly(() => client.getNumberPrecision(appId)),
42387
42859
  getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
42388
42860
  postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
42389
42861
  putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
@@ -42945,6 +43417,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
42945
43417
  );
42946
43418
  return flattenFormFieldProperties(res.properties);
42947
43419
  },
43420
+ async getNumberPrecision(appId) {
43421
+ const qs = new URLSearchParams();
43422
+ qs.set("app", String(appId));
43423
+ const res = await requestJson(
43424
+ `${apiBasePath}/app/settings.json?${qs.toString()}`,
43425
+ { method: "GET" },
43426
+ appId
43427
+ );
43428
+ return parseNumberPrecisionSettings(res);
43429
+ },
42948
43430
  async getProcessStatuses(appId) {
42949
43431
  const qs = new URLSearchParams();
42950
43432
  qs.set("app", String(appId));
@@ -43473,6 +43955,12 @@ async function createKsqlRuntime(serverOptions, input) {
43473
43955
  if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
43474
43956
  return routed.getFields(binding.appId);
43475
43957
  },
43958
+ getNumberPrecision: (appId) => {
43959
+ const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
43960
+ const routed = runtimeContext.clientsByProfile.get(binding.profile);
43961
+ if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
43962
+ return routed.getNumberPrecision(binding.appId);
43963
+ },
43476
43964
  getProcessStatuses: (appId) => {
43477
43965
  const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
43478
43966
  const routed = runtimeContext.clientsByProfile.get(binding.profile);
@@ -43708,6 +44196,9 @@ function noOpClient() {
43708
44196
  getFields: fail,
43709
44197
  async getProcessStatuses() {
43710
44198
  return { enable: false, states: [] };
44199
+ },
44200
+ async getNumberPrecision() {
44201
+ return { digits: 30, decimalPlaces: 10, roundingMode: "HALF_EVEN" };
43711
44202
  }
43712
44203
  };
43713
44204
  }
@@ -44507,7 +44998,7 @@ Options:
44507
44998
  -h, --help Show help
44508
44999
  `);
44509
45000
  }
44510
- var SERVER_VERSION = true ? "3.1.0" : "0.0.0-dev";
45001
+ var SERVER_VERSION = true ? "3.3.0" : "0.0.0-dev";
44511
45002
  function createServer(args) {
44512
45003
  const server = new McpServer({
44513
45004
  name: "ksql-mcp",
@@ -44529,12 +45020,12 @@ function createServer(args) {
44529
45020
  }, tools.explainTool);
44530
45021
  server.registerTool("ksql_query", {
44531
45022
  title: "Run read-only kSQL",
44532
- 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.",
45023
+ 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.",
44533
45024
  inputSchema: queryInputShape
44534
45025
  }, tools.queryTool);
44535
45026
  server.registerTool("ksql_mutate", {
44536
45027
  title: "Run mutating kSQL",
44537
- 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).",
45028
+ 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).",
44538
45029
  inputSchema: mutateInputShape
44539
45030
  }, tools.mutateTool);
44540
45031
  server.registerTool("ksql_describe_app", {