@rex0220/kintone-sql-tools 3.2.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.
@@ -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),
@@ -31377,8 +31390,94 @@ function isJapanese(cp) {
31377
31390
  return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65281 && cp <= 65376;
31378
31391
  }
31379
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
+
31380
31472
  // src/types/ast.ts
31381
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
+ }
31382
31481
 
31383
31482
  // src/parser/parser.ts
31384
31483
  var MAX_BATCH_STATEMENTS = 20;
@@ -31411,6 +31510,9 @@ var FUNC_CALL_PREFIX_KINDS = /* @__PURE__ */ new Set([
31411
31510
  "COALESCE" /* COALESCE */,
31412
31511
  "NULLIF" /* NULLIF */,
31413
31512
  "ISNULL" /* ISNULL */,
31513
+ "REGEXP_LIKE" /* REGEXP_LIKE */,
31514
+ "REGEXP_REPLACE" /* REGEXP_REPLACE */,
31515
+ "REGEXP_SUBSTR" /* REGEXP_SUBSTR */,
31414
31516
  "LEFT" /* LEFT */,
31415
31517
  "RIGHT" /* RIGHT */,
31416
31518
  "INSTR" /* INSTR */,
@@ -32174,12 +32276,12 @@ var Parser = class {
32174
32276
  if (this.peek().kind === "-" /* MINUS */) {
32175
32277
  this.advance();
32176
32278
  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 };
32279
+ if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
32280
+ return { type: "AGG_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
32179
32281
  }
32180
32282
  if (this.peek().kind === "NUMBER" /* NUMBER */) {
32181
32283
  const tok = this.advance();
32182
- return { type: "NUMBER", value: Number(tok.value) };
32284
+ return makeNumberLiteral(tok.value);
32183
32285
  }
32184
32286
  const aggFunc = this.tryAggregateFunc();
32185
32287
  if (aggFunc !== null) {
@@ -32231,7 +32333,7 @@ var Parser = class {
32231
32333
  if (this.allowUnaryPlusNumber && this.peek().kind === "+" /* PLUS */) {
32232
32334
  this.advance();
32233
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");
32234
- return { type: "NUMBER", value: Number(number4.value) };
32336
+ return makeNumberLiteral(`+${number4.value}`);
32235
32337
  }
32236
32338
  if (this.peek().kind === "-" /* MINUS */) {
32237
32339
  this.advance();
@@ -32239,8 +32341,8 @@ var Parser = class {
32239
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());
32240
32342
  }
32241
32343
  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 };
32344
+ if (operand.type === "NUMBER") return makeNumberLiteral(`-${numberLiteralText(operand)}`);
32345
+ return { type: "ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
32244
32346
  }
32245
32347
  if (this.tryStringFuncName() !== null) {
32246
32348
  return this.parseStringFuncExpr();
@@ -32248,7 +32350,7 @@ var Parser = class {
32248
32350
  const tok = this.peek();
32249
32351
  if (tok.kind === "NUMBER" /* NUMBER */) {
32250
32352
  this.advance();
32251
- return { type: "NUMBER", value: Number(tok.value) };
32353
+ return makeNumberLiteral(tok.value);
32252
32354
  }
32253
32355
  if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
32254
32356
  this.advance();
@@ -32352,6 +32454,9 @@ var Parser = class {
32352
32454
  ["SUBSTR" /* SUBSTR */]: "SUBSTRING",
32353
32455
  ["CONCAT" /* CONCAT */]: "CONCAT",
32354
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",
32355
32460
  ["TRANSLATE" /* TRANSLATE */]: "TRANSLATE",
32356
32461
  ["COALESCE" /* COALESCE */]: "COALESCE",
32357
32462
  ["NULLIF" /* NULLIF */]: "NULLIF",
@@ -32891,7 +32996,7 @@ var Parser = class {
32891
32996
  }
32892
32997
  if (tok.kind === "NUMBER" /* NUMBER */ || tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */ || tok.kind === "(" /* LPAREN */ || tok.kind === "-" /* MINUS */ || this.tryStringFuncName() !== null) {
32893
32998
  const expr = this.parseArithAddSub();
32894
- if (expr.type === "NUMBER") return { type: "NUMBER", value: expr.value };
32999
+ if (expr.type === "NUMBER") return expr;
32895
33000
  return { type: "ARITH_VALUE", expr };
32896
33001
  }
32897
33002
  throw new ParseError(
@@ -32918,15 +33023,15 @@ var Parser = class {
32918
33023
  if (tok.kind === "STRING" /* STRING */) {
32919
33024
  values.push({ type: "STRING", value: tok.value });
32920
33025
  } else if (tok.kind === "NUMBER" /* NUMBER */) {
32921
- values.push({ type: "NUMBER", value: Number(tok.value) });
33026
+ values.push(makeNumberLiteral(tok.value));
32922
33027
  } else if (tok.kind === "-" /* MINUS */ || tok.kind === "+" /* PLUS */) {
32923
33028
  const number4 = this.peek();
32924
33029
  if (number4.kind !== "NUMBER" /* NUMBER */) {
32925
33030
  throw new ParseError(invalidValueMessage, tok);
32926
33031
  }
32927
33032
  this.advance();
32928
- const sign = tok.kind === "-" /* MINUS */ ? -1 : 1;
32929
- values.push({ type: "NUMBER", value: sign * Number(number4.value) });
33033
+ const sign = tok.kind === "-" /* MINUS */ ? "-" : "+";
33034
+ values.push(makeNumberLiteral(`${sign}${number4.value}`));
32930
33035
  } else if (tok.kind === "VARIABLE" /* VARIABLE */) {
32931
33036
  values.push({ type: "VARIABLE", name: tok.value.slice(1).toLowerCase() });
32932
33037
  } else {
@@ -33116,14 +33221,13 @@ var Parser = class {
33116
33221
  } else if (this.peek().kind === "-" /* MINUS */ || this.peek().kind === "+" /* PLUS */) {
33117
33222
  const sign = this.advance();
33118
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");
33119
- const value = Number(number4.value);
33120
- row.push({ type: "NUMBER", value: sign.kind === "-" /* MINUS */ ? -value : value });
33224
+ row.push(makeNumberLiteral(`${sign.kind === "-" /* MINUS */ ? "-" : "+"}${number4.value}`));
33121
33225
  } else {
33122
33226
  const tok = this.advance();
33123
33227
  if (tok.kind === "STRING" /* STRING */) {
33124
33228
  row.push({ type: "STRING", value: tok.value });
33125
33229
  } else if (tok.kind === "NUMBER" /* NUMBER */) {
33126
- row.push({ type: "NUMBER", value: Number(tok.value) });
33230
+ row.push(makeNumberLiteral(tok.value));
33127
33231
  } else {
33128
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);
33129
33233
  }
@@ -33945,7 +34049,7 @@ function convertValue(value, op) {
33945
34049
  case "STRING":
33946
34050
  return convertString(value);
33947
34051
  case "NUMBER":
33948
- return String(value.value);
34052
+ return numberLiteralText(value);
33949
34053
  case "KINTONE_FUNC":
33950
34054
  return convertKintoneFunc(value);
33951
34055
  case "IN_LIST":
@@ -33974,7 +34078,7 @@ function convertInList(v, op) {
33974
34078
  }
33975
34079
  assertResolvedInListValues(v.values);
33976
34080
  const values = v.values.map(
33977
- (item) => item.type === "STRING" ? convertString(item) : String(item.value)
34081
+ (item) => item.type === "STRING" ? convertString(item) : numberLiteralText(item)
33978
34082
  ).join(",");
33979
34083
  return `(${values})`;
33980
34084
  }
@@ -34487,7 +34591,7 @@ function aggregateSyntheticName(func, distinct, arg) {
34487
34591
  }
34488
34592
  function arithNodeLabel(node) {
34489
34593
  if (node.type === "FIELD_REF") return node.field;
34490
- if (node.type === "NUMBER") return String(node.value);
34594
+ if (node.type === "NUMBER") return numberLiteralText(node);
34491
34595
  if (node.type === "STRING_FUNC") return stringFuncLabel(node);
34492
34596
  return `(${arithNodeLabel(node.left)}${node.op}${arithNodeLabel(node.right)})`;
34493
34597
  }
@@ -34644,7 +34748,7 @@ function isNumericCandidate(expr, options) {
34644
34748
  if (!isTargetField(expr.left, options)) return false;
34645
34749
  if (expr.right.type !== "NUMBER") return false;
34646
34750
  if (expr.op === "=") return true;
34647
- 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);
34648
34752
  }
34649
34753
  function isSelectionInCandidate(expr, options) {
34650
34754
  if (expr.left.type !== "FIELD" || expr.left.field === "$id") return false;
@@ -35249,9 +35353,10 @@ function triCompare(left, right) {
35249
35353
  }
35250
35354
  function numberKey(value) {
35251
35355
  if (value === "") return { band: 0 };
35356
+ const decimal = parseExactDecimal(value);
35357
+ if (decimal !== null) return { band: 2, value: decimal };
35252
35358
  const numeric = Number(value);
35253
35359
  if (numeric === Number.NEGATIVE_INFINITY) return { band: 1 };
35254
- if (Number.isFinite(numeric)) return { band: 2, value: numeric };
35255
35360
  if (numeric === Number.POSITIVE_INFINITY) return { band: 3 };
35256
35361
  if (value === "NaN") return { band: 4 };
35257
35362
  return { band: 5, value };
@@ -35260,7 +35365,7 @@ function compareNumbers(left, right) {
35260
35365
  const a = numberKey(left);
35261
35366
  const b = numberKey(right);
35262
35367
  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);
35368
+ if (a.band === 2 && b.band === 2) return compareExactDecimal(a.value, b.value);
35264
35369
  if (a.band === 5 && b.band === 5) return compareCodePointStrings(a.value, b.value);
35265
35370
  return 0;
35266
35371
  }
@@ -35360,7 +35465,9 @@ function selectScalarExtreme(values, extreme) {
35360
35465
  const numeric = candidates.every((value) => !Number.isNaN(Number(value)));
35361
35466
  const compare = (left, right) => {
35362
35467
  if (numeric) {
35363
- 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));
35364
35471
  if (numericCmp !== 0) return numericCmp;
35365
35472
  }
35366
35473
  return compareCodePointStrings(left, right);
@@ -35483,6 +35590,112 @@ function makeSafePadding(pad, gap) {
35483
35590
  const repeated = pad.repeat(Math.ceil(gap / pad.length));
35484
35591
  return sliceSafePrefix(repeated, gap);
35485
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
+ }
35486
35699
  function evalStringFunc(expr, row) {
35487
35700
  const args = expr.args.map((a) => evalStringFuncArg(a, row));
35488
35701
  switch (expr.func) {
@@ -35546,6 +35759,21 @@ function evalStringFunc(expr, row) {
35546
35759
  const to = args[2] ?? "";
35547
35760
  return from === "" ? str : str.split(from).join(to);
35548
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
+ }
35549
35777
  case "TRANSLATE": {
35550
35778
  assertArity("TRANSLATE", args, 3, 3);
35551
35779
  const from = [...args[1]];
@@ -35724,7 +35952,7 @@ function evalStringFuncArg(arg, row) {
35724
35952
  if (arg.type === "STRING") return arg.value;
35725
35953
  if (arg.type === "STRING_FUNC") return evalStringFunc(arg, row);
35726
35954
  if (arg.type === "FIELD_REF") return resolveFieldRef(row, arg.field);
35727
- if (arg.type === "NUMBER") return String(arg.value);
35955
+ if (arg.type === "NUMBER") return numberLiteralText(arg);
35728
35956
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
35729
35957
  return String(evalArithExpr(arg, row));
35730
35958
  }
@@ -35773,7 +36001,7 @@ function evalOp(op, leftStr, right, row, fieldType, resolveFieldType, semantics
35773
36001
  let values = null;
35774
36002
  if (right.type === "IN_LIST") {
35775
36003
  assertResolvedInListValues2(right.values);
35776
- 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));
35777
36005
  }
35778
36006
  if (right.type === "SUBQUERY_IN_LIST") {
35779
36007
  values = right.resolved;
@@ -35853,6 +36081,10 @@ var SINGLE_OBJECT_FIELD_TYPES = /* @__PURE__ */ new Set(["CREATOR", "MODIFIER"])
35853
36081
  function typedInContains(leftStr, values, fieldType) {
35854
36082
  const fallback = () => values.has(leftStr);
35855
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
+ }
35856
36088
  let parsed;
35857
36089
  if (STRING_ARRAY_FIELD_TYPES.has(fieldType) || OBJECT_ARRAY_FIELD_TYPES.has(fieldType) || SINGLE_OBJECT_FIELD_TYPES.has(fieldType)) {
35858
36090
  try {
@@ -35911,7 +36143,7 @@ function resolveValue(value, row, resolveFieldType, resolveFieldSemantics2) {
35911
36143
  case "STRING":
35912
36144
  return value.value;
35913
36145
  case "NUMBER":
35914
- return String(value.value);
36146
+ return numberLiteralText(value);
35915
36147
  case "KINTONE_FUNC":
35916
36148
  return resolveKintoneFunc(value.name);
35917
36149
  case "IN_LIST":
@@ -36351,7 +36583,7 @@ function convertDmlSqlValue(value, fieldType) {
36351
36583
  case "STRING":
36352
36584
  return convertString2(value.value, fieldType);
36353
36585
  case "NUMBER":
36354
- return String(value.value);
36586
+ return numberLiteralText(value);
36355
36587
  case "ARRAY":
36356
36588
  return convertArray(value.elements.map((e) => e.value), fieldType);
36357
36589
  case "KINTONE_FUNC":
@@ -36983,7 +37215,7 @@ function evalAggArithExpr(node, rows, resolveAggSortKind) {
36983
37215
  }
36984
37216
  }
36985
37217
  function aggArithDefaultKey(node) {
36986
- if (node.type === "NUMBER") return String(node.value);
37218
+ if (node.type === "NUMBER") return numberLiteralText(node);
36987
37219
  if (node.type === "AGG_REF") return aggregateSyntheticName2(node.func, node.distinct, node.arg);
36988
37220
  return `${aggArithDefaultKey(node.left)}${node.op}${aggArithDefaultKey(node.right)}`;
36989
37221
  }
@@ -37333,7 +37565,7 @@ function stripParentShortcutColumns(row) {
37333
37565
  function arithColDefaultKey(expr) {
37334
37566
  const nodeLabel = (n) => {
37335
37567
  if (n.type === "FIELD_REF") return n.field;
37336
- if (n.type === "NUMBER") return String(n.value);
37568
+ if (n.type === "NUMBER") return numberLiteralText(n);
37337
37569
  if (n.type === "STRING_FUNC") return stringFuncDefaultKey(n);
37338
37570
  return `(${nodeLabel(n.left)}${n.op}${nodeLabel(n.right)})`;
37339
37571
  };
@@ -37362,10 +37594,11 @@ function hasAggregateInStringFuncExpr2(expr) {
37362
37594
  function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
37363
37595
  if (arg.type === "AGG_REF") {
37364
37596
  const value = evalAggregate(arg.func, arg.distinct, arg.arg, arg.separator, rows, resolveAggSortKind);
37365
- return typeof value === "number" ? { type: "NUMBER", value } : { type: "STRING", value };
37597
+ return typeof value === "number" ? { type: "NUMBER", value, raw: String(value) } : { type: "STRING", value };
37366
37598
  }
37367
37599
  if (arg.type === "AGG_ARITH") {
37368
- return { type: "NUMBER", value: evalAggArithExpr(arg, rows, resolveAggSortKind) };
37600
+ const value = evalAggArithExpr(arg, rows, resolveAggSortKind);
37601
+ return { type: "NUMBER", value, raw: String(value) };
37369
37602
  }
37370
37603
  if (arg.type === "STRING_FUNC") {
37371
37604
  return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
@@ -37483,10 +37716,43 @@ function toFlatString(value) {
37483
37716
  }
37484
37717
  }
37485
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
+
37486
37752
  // src/core/dmlValidation.ts
37487
37753
  var ARRAY_TYPES2 = /* @__PURE__ */ new Set(["CHECK_BOX", "MULTI_SELECT"]);
37488
37754
  var CHOICE_TYPES = /* @__PURE__ */ new Set(["DROP_DOWN", "RADIO_BUTTON", "CHECK_BOX", "MULTI_SELECT"]);
37489
- function validateAndNormalizeDmlValue(raw, field) {
37755
+ function validateAndNormalizeDmlValue(raw, field, numberPrecision) {
37490
37756
  if (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME") {
37491
37757
  const original = rawScalarText(raw);
37492
37758
  if (original !== "" && !isValidTemporalInput(original, field.fieldType)) {
@@ -37505,7 +37771,8 @@ function validateAndNormalizeDmlValue(raw, field) {
37505
37771
  }
37506
37772
  if (!isEmpty(value) && field.fieldType === "NUMBER") {
37507
37773
  const text = String(value);
37508
- if (!isFiniteDecimal(text)) {
37774
+ const decimal = parseExactDecimal(text);
37775
+ if (decimal === null) {
37509
37776
  return { ok: false, code: "ERR_TYPE_NUMBER", message: `${field.code} \u306F\u6570\u5024\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044` };
37510
37777
  }
37511
37778
  if (field.minValue != null && compareDecimal(text, field.minValue) < 0) {
@@ -37514,6 +37781,17 @@ function validateAndNormalizeDmlValue(raw, field) {
37514
37781
  if (field.maxValue != null && compareDecimal(text, field.maxValue) > 0) {
37515
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` };
37516
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
+ }
37517
37795
  }
37518
37796
  if (!isEmpty(value) && (field.fieldType === "DATE" || field.fieldType === "TIME" || field.fieldType === "DATETIME")) {
37519
37797
  if (!isValidTemporal(String(value), field.fieldType)) {
@@ -37541,7 +37819,8 @@ function validateAndNormalizeDmlValue(raw, field) {
37541
37819
  }
37542
37820
  function rawScalarText(raw) {
37543
37821
  if (raw == null) return "";
37544
- 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;
37545
37824
  return typeof raw === "string" || typeof raw === "number" ? String(raw) : "";
37546
37825
  }
37547
37826
  function isValidTemporalInput(value, type) {
@@ -37591,34 +37870,6 @@ function isEmpty(value) {
37591
37870
  function typeCode(type) {
37592
37871
  return type === "NUMBER" ? "ERR_TYPE_NUMBER" : "ERR_TYPE_DATE";
37593
37872
  }
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
37873
  function isValidTemporal(value, type) {
37623
37874
  if (type === "TIME") {
37624
37875
  const m2 = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
@@ -37646,7 +37897,7 @@ var VALIDATION_META_COLUMNS = [
37646
37897
  "$err_code",
37647
37898
  "$err_message"
37648
37899
  ];
37649
- function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber) {
37900
+ function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision) {
37650
37901
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
37651
37902
  const errors = [];
37652
37903
  const invalid = /* @__PURE__ */ new Set();
@@ -37654,7 +37905,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37654
37905
  candidate.record ??= {};
37655
37906
  const rowErrors = [...candidate.preErrors];
37656
37907
  for (const code of targetFields) {
37657
- const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code));
37908
+ const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
37658
37909
  if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
37659
37910
  else candidate.record[code] = { value: result.value };
37660
37911
  }
@@ -37664,14 +37915,14 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37664
37915
  if (candidate.payload.has(info.code)) continue;
37665
37916
  const emptyDefault = isEmptyDmlValue(info.defaultValue);
37666
37917
  if (!emptyDefault) {
37667
- const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info);
37918
+ const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info, numberPrecision);
37668
37919
  if (!defaultResult.ok) rowErrors.push({
37669
37920
  field: info.code,
37670
37921
  code: defaultResult.code,
37671
37922
  message: `\u65E2\u5B9A\u5024: ${defaultResult.message}`
37672
37923
  });
37673
37924
  } else {
37674
- const emptyResult = validateAndNormalizeDmlValue("", info);
37925
+ const emptyResult = validateAndNormalizeDmlValue("", info, numberPrecision);
37675
37926
  if (!emptyResult.ok) {
37676
37927
  rowErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
37677
37928
  } else if (info.required) {
@@ -37699,7 +37950,8 @@ function renderValidationValue(value) {
37699
37950
  if (value == null) return "";
37700
37951
  if (typeof value === "object" && "type" in value) {
37701
37952
  const sql = value;
37702
- 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 ?? "");
37703
37955
  if (sql.type === "ARRAY") return JSON.stringify(sql.elements?.map((e) => e.value) ?? []);
37704
37956
  }
37705
37957
  if (Array.isArray(value)) return JSON.stringify(value);
@@ -37941,6 +38193,7 @@ function createEmptyMetrics() {
37941
38193
  putCalls: 0,
37942
38194
  deleteCalls: 0,
37943
38195
  fieldCalls: 0,
38196
+ numberPrecisionCalls: 0,
37944
38197
  appsCalls: 0,
37945
38198
  processStatusCalls: 0,
37946
38199
  cursorCreateCalls: 0,
@@ -38026,6 +38279,10 @@ function wrapClientWithMetrics(client, metrics) {
38026
38279
  metrics.fieldCalls += 1;
38027
38280
  return client.getFields(appId);
38028
38281
  },
38282
+ getNumberPrecision: (appId) => {
38283
+ metrics.numberPrecisionCalls += 1;
38284
+ return client.getNumberPrecision(appId);
38285
+ },
38029
38286
  getProcessStatuses: (appId) => {
38030
38287
  metrics.processStatusCalls += 1;
38031
38288
  return client.getProcessStatuses(appId);
@@ -38293,7 +38550,7 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
38293
38550
  const first = resolvedStmt2.expr.query.columns[0];
38294
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");
38295
38552
  const numberValue = numeric ? Number(value) : Number.NaN;
38296
- 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 });
38297
38554
  } catch (e) {
38298
38555
  if (e instanceof ScalarSubqueryError) {
38299
38556
  throw new Error(`ArgumentError: ${e.message}`);
@@ -38311,7 +38568,10 @@ async function executeBatchStatement(stmt, info, client, options, cacheContext,
38311
38568
  variables.set(stmt.name, { type: "string", value: injected[stmt.name] });
38312
38569
  } else {
38313
38570
  const value = evaluateScalarExpr(stmt.default);
38314
- 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
+ });
38315
38575
  }
38316
38576
  return {};
38317
38577
  }
@@ -38487,7 +38747,7 @@ function evaluateScalarExpr(expr) {
38487
38747
  case "STRING":
38488
38748
  return { type: "string", value: expr.value };
38489
38749
  case "NUMBER":
38490
- return { type: "number", value: expr.value };
38750
+ return { type: "number", value: expr.value, raw: numberLiteralText(expr) };
38491
38751
  case "KINTONE_FUNC":
38492
38752
  return { type: "string", value: resolveKintoneFunc(expr.name) };
38493
38753
  case "STRING_FUNC":
@@ -38497,7 +38757,7 @@ function evaluateScalarExpr(expr) {
38497
38757
  if (!Number.isFinite(value)) {
38498
38758
  throw new Error("ArgumentError: SET scalar arithmetic produced a non-finite number.");
38499
38759
  }
38500
- return { type: "number", value };
38760
+ return { type: "number", value, raw: String(value) };
38501
38761
  }
38502
38762
  }
38503
38763
  }
@@ -38512,7 +38772,7 @@ function resolveVariableRefs(node, variables) {
38512
38772
  if (value === void 0) {
38513
38773
  throw new Error(`ParseError: variable @${obj["name"]} is not defined in this batch.`);
38514
38774
  }
38515
- 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 };
38516
38776
  }
38517
38777
  return Object.fromEntries(
38518
38778
  Object.entries(obj).map(([key, value]) => [key, resolveVariableRefs(value, variables)])
@@ -38578,7 +38838,7 @@ async function evalAssertOperand(operand, client, options, cacheContext, tempTab
38578
38838
  case "VARIABLE":
38579
38839
  throw new Error(`ParseError: unresolved batch variable @${operand.name}.`);
38580
38840
  case "NUMBER":
38581
- return String(operand.value);
38841
+ return numberLiteralText(operand);
38582
38842
  case "STRING":
38583
38843
  return operand.value;
38584
38844
  case "ARITH":
@@ -39861,8 +40121,8 @@ async function fetchTableRecordsForFullScan(stmt, table, client, maxRecords2, pa
39861
40121
  }
39862
40122
  var UPSERT_IN_CHUNK_SIZE = 50;
39863
40123
  function normalizeKeyPart(v) {
39864
- const t = v.trim();
39865
- if (t !== "" && !Number.isNaN(Number(t))) return String(Number(t));
40124
+ const decimal = parseExactDecimal(v);
40125
+ if (decimal !== null) return JSON.stringify(decimal);
39866
40126
  return v;
39867
40127
  }
39868
40128
  function upsertCompositeKey(parts) {
@@ -40014,6 +40274,7 @@ var optionOrderCache = /* @__PURE__ */ new Map();
40014
40274
  var sortKindCache = /* @__PURE__ */ new Map();
40015
40275
  var fieldInfoCache = /* @__PURE__ */ new Map();
40016
40276
  var processStatusCache = /* @__PURE__ */ new Map();
40277
+ var numberPrecisionCache = /* @__PURE__ */ new Map();
40017
40278
  function getScopedCacheValue(root, cacheContext, appId) {
40018
40279
  return root.get(cacheContext)?.get(appId);
40019
40280
  }
@@ -40035,6 +40296,13 @@ async function getFieldsCached(appId, client, cacheContext) {
40035
40296
  setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
40036
40297
  return loading;
40037
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
+ }
40038
40306
  async function getProcessStatusesCached(appId, client, cacheContext) {
40039
40307
  const cached2 = getScopedCacheValue(processStatusCache, cacheContext, appId);
40040
40308
  if (cached2) return cached2;
@@ -40309,6 +40577,23 @@ async function loadWritableTopLevelDmlFields(appId, targetFields, client, cacheC
40309
40577
  assertWritableTopLevelDmlFields(appId, targetFields, fieldInfos);
40310
40578
  return fieldInfos;
40311
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
+ }
40312
40597
  async function executeDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
40313
40598
  return (await prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber)).result;
40314
40599
  }
@@ -40336,6 +40621,13 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
40336
40621
  await assertDmlWhereCapability(stmt, client, cacheContext);
40337
40622
  }
40338
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
+ );
40339
40631
  const candidates = await materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode);
40340
40632
  const { errors, invalidRows, invalidRowNumbers } = validateDmlCandidates(
40341
40633
  candidates,
@@ -40343,7 +40635,8 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
40343
40635
  payloadFields,
40344
40636
  targetFields,
40345
40637
  fieldInfos,
40346
- statementNumber
40638
+ statementNumber,
40639
+ numberPrecision
40347
40640
  );
40348
40641
  const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
40349
40642
  const result = {
@@ -40567,6 +40860,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40567
40860
  tempTables
40568
40861
  );
40569
40862
  const sourceByKey = /* @__PURE__ */ new Map();
40863
+ const sourceQueryByKey = /* @__PURE__ */ new Map();
40570
40864
  for (const row of sourceRows) {
40571
40865
  if (!Object.prototype.hasOwnProperty.call(row, from.joinKeyField)) {
40572
40866
  throw new Error(`ArgumentError: UPDATE ... FROM source column ${from.joinKeyField} does not exist.`);
@@ -40576,6 +40870,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40576
40870
  throw new Error(`ArgumentError: UPDATE ... FROM source has multiple rows for normalized key ${key}.`);
40577
40871
  }
40578
40872
  sourceByKey.set(key, row);
40873
+ sourceQueryByKey.set(key, String(row[from.joinKeyField]).trim());
40579
40874
  }
40580
40875
  if (sourceByKey.size === 0) return [];
40581
40876
  const maxRecords2 = options.maxRecords ?? 1e4;
@@ -40584,7 +40879,7 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40584
40879
  const targetRecords = [];
40585
40880
  const seenTargetIds = /* @__PURE__ */ new Set();
40586
40881
  let fetchedTargetCount = 0;
40587
- 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)) {
40588
40883
  const keyQuery = `${from.targetJoinField} in (${keys.map(sqlQuote).join(",")})`;
40589
40884
  const query = filterQuery ? `(${keyQuery}) and (${filterQuery})` : keyQuery;
40590
40885
  const resolved = await fetchRecordsForSharedPlan(
@@ -40685,37 +40980,28 @@ function normalizeUpdateFromJoinKey(raw, kind, side) {
40685
40980
  }
40686
40981
  if (kind === "number" && side === "target" && raw === "") return null;
40687
40982
  if (kind === "id") {
40688
- const text2 = raw.trim();
40689
- const id = Number(text2);
40690
- 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) {
40691
40986
  throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a positive safe integer: ${raw}`);
40692
40987
  }
40693
40988
  return String(id);
40694
40989
  }
40695
- const text = raw.trim();
40696
- if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(text)) {
40990
+ const decimal = parseExactDecimal(raw);
40991
+ if (decimal === null) {
40697
40992
  throw new Error(`ArgumentError: UPDATE ... FROM ${side} key must be a finite decimal: ${raw}`);
40698
40993
  }
40699
- let unsigned = text;
40700
- let negative = false;
40701
- if (unsigned.startsWith("-") || unsigned.startsWith("+")) {
40702
- negative = unsigned[0] === "-";
40703
- unsigned = unsigned.slice(1);
40704
- }
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;
40994
+ return JSON.stringify(decimal);
40711
40995
  }
40712
40996
  async function executeInsert(stmt, client, options, cacheContext) {
40713
40997
  if (stmt.subtableCode) {
40714
40998
  return executeInsertSubtable(stmt, client, options, cacheContext);
40715
40999
  }
40716
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41000
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41001
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40717
41002
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40718
41003
  const batches = insertToPostBatches(stmt, fieldTypes);
41004
+ assertValidDmlRecords(batches.flatMap((batch) => batch.records), stmt.fields, fieldInfos, numberPrecision);
40719
41005
  const createdIds = [];
40720
41006
  for (const batch of batches) {
40721
41007
  const res = await client.postRecords(batch);
@@ -40728,7 +41014,8 @@ async function executeInsert(stmt, client, options, cacheContext) {
40728
41014
  };
40729
41015
  }
40730
41016
  async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
40731
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41017
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41018
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40732
41019
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
40733
41020
  const { rows, columns } = selectResult;
40734
41021
  if (columns.length !== stmt.fields.length) {
@@ -40750,6 +41037,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
40750
41037
  });
40751
41038
  return record2;
40752
41039
  });
41040
+ assertValidDmlRecords(allRecords, stmt.fields, fieldInfos, numberPrecision);
40753
41041
  const createdIds = [];
40754
41042
  for (let i = 0; i < allRecords.length; i += 100) {
40755
41043
  const batch = allRecords.slice(i, i + 100);
@@ -40767,12 +41055,20 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40767
41055
  await assertDmlWhereCapability(stmt, client, cacheContext);
40768
41056
  return executeUpdateSubtable(stmt, client, options, cacheContext);
40769
41057
  }
40770
- await loadWritableTopLevelDmlFields(
41058
+ const fieldInfos = await loadWritableTopLevelDmlFields(
40771
41059
  stmt.appId,
40772
41060
  stmt.assignments.map((assignment) => assignment.field),
40773
41061
  client,
40774
41062
  cacheContext
40775
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
+ );
40776
41072
  await assertDmlWhereCapability(stmt, client, cacheContext);
40777
41073
  if (stmt.from != null) {
40778
41074
  return executeUpdateFrom(stmt, stmt.from, client, options, cacheContext, tempTables);
@@ -40790,11 +41086,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40790
41086
  { maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
40791
41087
  );
40792
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);
40793
41091
  if (options.confirm) {
40794
41092
  const ok = await options.confirm(records.length, "UPDATE");
40795
41093
  if (!ok) throw new OperationCancelledError("UPDATE", records.length);
40796
41094
  }
40797
- const batches2 = updateToPutBatchesArith(stmt, records, fieldTypes);
40798
41095
  for (const batch of batches2) {
40799
41096
  await client.putRecords(batch);
40800
41097
  }
@@ -40808,11 +41105,12 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40808
41105
  { maxRecords: maxRecords2, parallel: options.fetchParallel ?? 1 }
40809
41106
  );
40810
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);
40811
41110
  if (options.confirm) {
40812
41111
  const ok = await options.confirm(ids.length, "UPDATE");
40813
41112
  if (!ok) throw new OperationCancelledError("UPDATE", ids.length);
40814
41113
  }
40815
- const batches = updateToPutBatches(stmt, ids, fieldTypes);
40816
41114
  for (const batch of batches) {
40817
41115
  await client.putRecords(batch);
40818
41116
  }
@@ -40820,12 +41118,16 @@ async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
40820
41118
  }
40821
41119
  async function executeUpdateFrom(stmt, from, client, options, cacheContext, tempTables) {
40822
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);
40823
41127
  if (options.confirm) {
40824
41128
  const ok = await options.confirm(matched.length, "UPDATE");
40825
41129
  if (!ok) throw new OperationCancelledError("UPDATE", matched.length);
40826
41130
  }
40827
- const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40828
- const batches = updateFromToPutBatches(stmt, matched, fieldTypes);
40829
41131
  for (const batch of batches) await client.putRecords(batch);
40830
41132
  return { type: "UPDATE", updatedCount: matched.length };
40831
41133
  }
@@ -40874,7 +41176,8 @@ async function executeDelete(stmt, client, options, cacheContext) {
40874
41176
  return { type: "DELETE", deletedCount: ids.length };
40875
41177
  }
40876
41178
  async function executeUpsert(stmt, client, options, cacheContext) {
40877
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41179
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41180
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
40878
41181
  const toInsert = [];
40879
41182
  const toUpdate = [];
40880
41183
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
@@ -40883,7 +41186,7 @@ async function executeUpsert(stmt, client, options, cacheContext) {
40883
41186
  const idx = stmt.fields.indexOf(key);
40884
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`);
40885
41188
  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(",");
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(",");
40887
41190
  })
40888
41191
  );
40889
41192
  const targetIndex = await resolveUpsertTargets(stmt.appId, stmt.keyFields, rowKeyValues, client, options, fieldTypes);
@@ -40904,6 +41207,12 @@ async function executeUpsert(stmt, client, options, cacheContext) {
40904
41207
  toInsert.push(record2);
40905
41208
  }
40906
41209
  });
41210
+ assertValidDmlRecords(
41211
+ [...toInsert, ...toUpdate.map((entry) => entry.record)],
41212
+ stmt.fields,
41213
+ fieldInfos,
41214
+ numberPrecision
41215
+ );
40907
41216
  if (options.confirm && toInsert.length + toUpdate.length > 0) {
40908
41217
  const total = toInsert.length + toUpdate.length;
40909
41218
  const ok = await options.confirm(total, "UPDATE");
@@ -41179,14 +41488,14 @@ function buildSubtableReorderPutParams(appId, parentId, revision, subtableCode,
41179
41488
  }
41180
41489
  function evalAssignmentValueForSubtable(value, row, resolveFieldType) {
41181
41490
  if (value.type === "STRING") return value.value;
41182
- if (value.type === "NUMBER") return String(value.value);
41491
+ if (value.type === "NUMBER") return numberLiteralText(value);
41183
41492
  if (value.type === "ARITH") return String(evalArithExpr(value, row));
41184
41493
  if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, row, resolveFieldType);
41185
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`);
41186
41495
  }
41187
41496
  function valueToString(value) {
41188
41497
  if (value.type === "STRING") return value.value;
41189
- if (value.type === "NUMBER") return String(value.value);
41498
+ if (value.type === "NUMBER") return numberLiteralText(value);
41190
41499
  if (value.type === "CASE_VALUE") return evalCaseWhen(value.expr, {});
41191
41500
  return value.elements.map((e) => e.value).join(",");
41192
41501
  }
@@ -41301,7 +41610,8 @@ function evalOrderKeyForRow(key, row) {
41301
41610
  }
41302
41611
  }
41303
41612
  async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
41304
- await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41613
+ const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41614
+ const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
41305
41615
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
41306
41616
  const { rows, columns } = selectResult;
41307
41617
  if (columns.length !== stmt.fields.length) {
@@ -41324,6 +41634,7 @@ async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache
41324
41634
  });
41325
41635
  return record2;
41326
41636
  });
41637
+ assertValidDmlRecords(records, stmt.fields, fieldInfos, numberPrecision);
41327
41638
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
41328
41639
  const rowKeyValues = records.map(
41329
41640
  (record2) => stmt.keyFields.map((key) => String(record2[key]?.value ?? ""))
@@ -42082,7 +42393,7 @@ function formatArithExprStr(expr) {
42082
42393
  }
42083
42394
  function formatArithNodeStr(node) {
42084
42395
  if (node.type === "FIELD_REF") return node.field;
42085
- if (node.type === "NUMBER") return String(node.value);
42396
+ if (node.type === "NUMBER") return numberLiteralText(node);
42086
42397
  if (node.type === "ARITH") return `(${formatArithExprStr(node)})`;
42087
42398
  return "...";
42088
42399
  }
@@ -42544,6 +42855,7 @@ function withRequestGate(client, gate) {
42544
42855
  },
42545
42856
  getApps: () => gate.runReadOnly(() => client.getApps()),
42546
42857
  getFields: (appId) => gate.runReadOnly(() => client.getFields(appId)),
42858
+ getNumberPrecision: (appId) => gate.runReadOnly(() => client.getNumberPrecision(appId)),
42547
42859
  getProcessStatuses: (appId) => gate.runReadOnly(() => client.getProcessStatuses(appId)),
42548
42860
  postRecords: (params) => gate.runMutation(() => client.postRecords(params)),
42549
42861
  putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
@@ -43105,6 +43417,16 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
43105
43417
  );
43106
43418
  return flattenFormFieldProperties(res.properties);
43107
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
+ },
43108
43430
  async getProcessStatuses(appId) {
43109
43431
  const qs = new URLSearchParams();
43110
43432
  qs.set("app", String(appId));
@@ -43633,6 +43955,12 @@ async function createKsqlRuntime(serverOptions, input) {
43633
43955
  if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
43634
43956
  return routed.getFields(binding.appId);
43635
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
+ },
43636
43964
  getProcessStatuses: (appId) => {
43637
43965
  const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
43638
43966
  const routed = runtimeContext.clientsByProfile.get(binding.profile);
@@ -43868,6 +44196,9 @@ function noOpClient() {
43868
44196
  getFields: fail,
43869
44197
  async getProcessStatuses() {
43870
44198
  return { enable: false, states: [] };
44199
+ },
44200
+ async getNumberPrecision() {
44201
+ return { digits: 30, decimalPlaces: 10, roundingMode: "HALF_EVEN" };
43871
44202
  }
43872
44203
  };
43873
44204
  }
@@ -44667,7 +44998,7 @@ Options:
44667
44998
  -h, --help Show help
44668
44999
  `);
44669
45000
  }
44670
- var SERVER_VERSION = true ? "3.2.0" : "0.0.0-dev";
45001
+ var SERVER_VERSION = true ? "3.3.0" : "0.0.0-dev";
44671
45002
  function createServer(args) {
44672
45003
  const server = new McpServer({
44673
45004
  name: "ksql-mcp",
@@ -44689,12 +45020,12 @@ function createServer(args) {
44689
45020
  }, tools.explainTool);
44690
45021
  server.registerTool("ksql_query", {
44691
45022
  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.",
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.",
44693
45024
  inputSchema: queryInputShape
44694
45025
  }, tools.queryTool);
44695
45026
  server.registerTool("ksql_mutate", {
44696
45027
  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).",
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).",
44698
45029
  inputSchema: mutateInputShape
44699
45030
  }, tools.mutateTool);
44700
45031
  server.registerTool("ksql_describe_app", {