@rex0220/kintone-sql-tools 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31219,6 +31219,10 @@ var Lexer = class {
31219
31219
  this.pos += 2;
31220
31220
  return this.makeToken("<=" /* LTE */, "<=", start);
31221
31221
  }
31222
+ if (ch === "|" && ch2 === "|") {
31223
+ this.pos += 2;
31224
+ return this.makeToken("||" /* CONCAT_OP */, "||", start);
31225
+ }
31222
31226
  switch (ch) {
31223
31227
  case "=":
31224
31228
  this.pos++;
@@ -31562,6 +31566,8 @@ var Parser = class {
31562
31566
  constructor(tokens) {
31563
31567
  this.tokens = tokens;
31564
31568
  this.allowUnaryPlusNumber = false;
31569
+ this.scalarAllowsAggregateArgs = true;
31570
+ this.scalarAllowsCase = true;
31565
31571
  this.pos = 0;
31566
31572
  /** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
31567
31573
  this.cteNames = /* @__PURE__ */ new Set();
@@ -31730,17 +31736,19 @@ var Parser = class {
31730
31736
  }
31731
31737
  rejectNonScalarExpr(node, tok, context) {
31732
31738
  if (node.type === "STRING" || node.type === "NUMBER") return;
31733
- if (node.type === "FIELD_REF" || node.type === "AGG_REF") {
31739
+ if (node.type === "FIELD_REF" || node.type === "FIELD" || node.type === "VARIABLE" || node.type === "AGG_REF") {
31734
31740
  throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F\u30D5\u30A3\u30FC\u30EB\u30C9\u53C2\u7167\u30FB\u96C6\u8A08\u95A2\u6570\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
31735
31741
  }
31736
- if (node.type === "ARITH" || node.type === "AGG_ARITH") {
31742
+ if (node.type === "ARITH" || node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP" || node.type === "AGG_ARITH") {
31737
31743
  this.rejectNonScalarExpr(node.left, tok, context);
31738
31744
  this.rejectNonScalarExpr(node.right, tok, context);
31739
31745
  return;
31740
31746
  }
31741
31747
  if (node.type === "STRING_FUNC") {
31742
31748
  for (const arg of node.args) this.rejectNonScalarExpr(arg, tok, context);
31749
+ return;
31743
31750
  }
31751
+ throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
31744
31752
  }
31745
31753
  // ----------------------------------------------------------
31746
31754
  // CREATE TEMP TABLE / DROP TEMP TABLE(バッチ内一時テーブル)
@@ -32111,6 +32119,11 @@ var Parser = class {
32111
32119
  if (this.consume("*" /* STAR */)) {
32112
32120
  return { type: "WILDCARD" };
32113
32121
  }
32122
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
32123
+ const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
32124
+ const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
32125
+ return { type: "SCALAR_VALUE_COL", expr, alias: alias2 };
32126
+ }
32114
32127
  const windowFunc = this.tryWindowFunc();
32115
32128
  if (windowFunc !== null) {
32116
32129
  return this.parseWindowColumn(windowFunc);
@@ -32226,13 +32239,25 @@ var Parser = class {
32226
32239
  }
32227
32240
  selectColumnHasAggregate(column) {
32228
32241
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
32229
- if (column.type !== "STRFUNC_COL") return false;
32230
- return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
32242
+ if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
32243
+ if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
32244
+ return false;
32231
32245
  }
32232
32246
  stringFuncArgHasAggregate(arg) {
32233
32247
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
32234
- if (arg.type === "STRING_FUNC") {
32235
- return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
32248
+ return this.scalarValueHasAggregate(arg);
32249
+ }
32250
+ scalarValueHasAggregate(expr) {
32251
+ if (expr.type === "STRING_FUNC") return expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
32252
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
32253
+ return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
32254
+ }
32255
+ if (expr.type === "CASE_WHEN") {
32256
+ const results = [...expr.branches.map((b) => b.result), ...expr.elseResult ? [expr.elseResult] : []];
32257
+ return results.some((result) => {
32258
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
32259
+ return this.scalarValueHasAggregate(result);
32260
+ });
32236
32261
  }
32237
32262
  return false;
32238
32263
  }
@@ -32290,6 +32315,105 @@ var Parser = class {
32290
32315
  throw new ParseError("\u96C6\u8A08\u7B97\u8853\u5F0F\u306B\u306F\u96C6\u8A08\u95A2\u6570\u307E\u305F\u306F\u6570\u5024\u304C\u5FC5\u8981\u3067\u3059", this.peek());
32291
32316
  }
32292
32317
  // ──────────────────────────────────────────────────
32318
+ // 汎用スカラー値式パーサー(B38)
32319
+ // ──────────────────────────────────────────────────
32320
+ /** 比較・述語・集約・サブクエリを含まない値式の公開入口。 */
32321
+ parseScalarValueExpr(options = {}) {
32322
+ const previousAggregateArgs = this.scalarAllowsAggregateArgs;
32323
+ const previousCase = this.scalarAllowsCase;
32324
+ this.scalarAllowsAggregateArgs = options.allowAggregateArgs === true;
32325
+ this.scalarAllowsCase = options.allowCase !== false;
32326
+ let expr;
32327
+ try {
32328
+ expr = this.parseScalarAddSubConcat(this.scalarAllowsCase);
32329
+ } finally {
32330
+ this.scalarAllowsAggregateArgs = previousAggregateArgs;
32331
+ this.scalarAllowsCase = previousCase;
32332
+ }
32333
+ const next = this.peek();
32334
+ if (next.kind === "IS" /* IS */ || next.kind === "=" /* EQ */ || next.kind === "!=" /* NEQ */ || next.kind === "<>" /* LT_GT */ || next.kind === ">" /* GT */ || next.kind === "<" /* LT */ || next.kind === ">=" /* GTE */ || next.kind === "<=" /* LTE */ || next.kind === "LIKE" /* LIKE */ || next.kind === "KLIKE" /* KLIKE */ || next.kind === "IN" /* IN */ || next.kind === "BETWEEN" /* BETWEEN */) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u6BD4\u8F03\u30FB\u8FF0\u8A9E\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", next);
32335
+ return expr;
32336
+ }
32337
+ parseScalarAddSubConcat(allowCase) {
32338
+ let left = this.parseScalarMulDiv(allowCase);
32339
+ while (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */ || this.peek().kind === "||" /* CONCAT_OP */) {
32340
+ const token = this.advance();
32341
+ const right = this.parseScalarMulDiv(allowCase);
32342
+ left = token.kind === "||" /* CONCAT_OP */ ? { type: "CONCAT_OP", left, right } : { type: "SCALAR_ARITH", left, op: token.kind === "+" /* PLUS */ ? "+" : "-", right };
32343
+ }
32344
+ return left;
32345
+ }
32346
+ parseScalarMulDiv(allowCase) {
32347
+ let left = this.parseScalarPrimary(allowCase);
32348
+ while (this.peek().kind === "*" /* STAR */ || this.peek().kind === "/" /* SLASH */ || this.peek().kind === "%" /* PERCENT */) {
32349
+ const token = this.advance();
32350
+ const op = token.kind === "*" /* STAR */ ? "*" : token.kind === "/" /* SLASH */ ? "/" : "%";
32351
+ left = { type: "SCALAR_ARITH", left, op, right: this.parseScalarPrimary(allowCase) };
32352
+ }
32353
+ return left;
32354
+ }
32355
+ parseScalarPrimary(allowCase) {
32356
+ const tok = this.peek();
32357
+ if (tok.kind === "(" /* LPAREN */) {
32358
+ if (this.peekAt(1).kind === "SELECT" /* SELECT */) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
32359
+ this.advance();
32360
+ const expr = this.parseScalarAddSubConcat(allowCase);
32361
+ this.expect(")" /* RPAREN */);
32362
+ return expr;
32363
+ }
32364
+ if (tok.kind === "+" /* PLUS */ || tok.kind === "-" /* MINUS */) {
32365
+ this.advance();
32366
+ if (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */) {
32367
+ throw new ParseError("\u5358\u9805\u7B26\u53F7\u3092\u91CD\u306D\u3066\u6307\u5B9A\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093", this.peek());
32368
+ }
32369
+ const operand = this.parseScalarPrimary(allowCase);
32370
+ if (operand.type === "NUMBER") {
32371
+ return makeNumberLiteral(`${tok.kind === "-" /* MINUS */ ? "-" : "+"}${numberLiteralText(operand)}`);
32372
+ }
32373
+ if (tok.kind === "+" /* PLUS */) throw new ParseError("\u5358\u9805 + \u306E\u76F4\u5F8C\u306B\u306F\u6570\u5024\u30EA\u30C6\u30E9\u30EB\u304C\u5FC5\u8981\u3067\u3059", tok);
32374
+ return { type: "SCALAR_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
32375
+ }
32376
+ if (tok.kind === "STRING" /* STRING */) {
32377
+ this.advance();
32378
+ return { type: "STRING", value: tok.value };
32379
+ }
32380
+ if (tok.kind === "NUMBER" /* NUMBER */) {
32381
+ this.advance();
32382
+ return makeNumberLiteral(tok.value);
32383
+ }
32384
+ if (tok.kind === "VARIABLE" /* VARIABLE */) {
32385
+ this.advance();
32386
+ return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
32387
+ }
32388
+ if (tok.kind === "CASE" /* CASE */) {
32389
+ if (!allowCase) throw new ParseError("\u3053\u306E\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
32390
+ return this.parseCaseWhenExpr();
32391
+ }
32392
+ if (this.tryAggregateFunc() !== null) throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306B\u96C6\u7D04\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093", tok);
32393
+ if (this.tryStringFuncName() !== null) return this.parseStringFuncExpr();
32394
+ if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
32395
+ this.advance();
32396
+ if (this.consume("." /* DOT */)) return { type: "FIELD", tableAlias: tok.value, field: this.parseIdentifier() };
32397
+ return { type: "FIELD", tableAlias: null, field: tok.value };
32398
+ }
32399
+ throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306E\u30AA\u30DA\u30E9\u30F3\u30C9\u304C\u5FC5\u8981\u3067\u3059", tok);
32400
+ }
32401
+ /** 現在の値の終端までに指定トークンがあるか(括弧内も対象)。 */
32402
+ hasTopLevelTokenBeforeValueEnd(target) {
32403
+ let depth = 0;
32404
+ for (let i = this.pos; i < this.tokens.length; i++) {
32405
+ const kind = this.tokens[i].kind;
32406
+ if (kind === "(" /* LPAREN */ || kind === "[" /* LBRACKET */) depth++;
32407
+ else if (kind === ")" /* RPAREN */ || kind === "]" /* RBRACKET */) {
32408
+ if (depth === 0) break;
32409
+ depth--;
32410
+ }
32411
+ if (kind === target) return true;
32412
+ if (depth === 0 && (kind === "," /* COMMA */ || kind === "AS" /* AS */ || kind === "FROM" /* FROM */ || kind === "WHERE" /* WHERE */ || kind === "WHEN" /* WHEN */ || kind === "THEN" /* THEN */ || kind === "ELSE" /* ELSE */ || kind === "END" /* END */ || kind === ";" /* SEMICOLON */ || kind === "EOF" /* EOF */)) break;
32413
+ }
32414
+ return false;
32415
+ }
32416
+ // ──────────────────────────────────────────────────
32293
32417
  // 算術式パーサー(演算子優先順位: * / > + -)
32294
32418
  //
32295
32419
  // parseArithAddSub : + -(左結合・低優先度)
@@ -32411,12 +32535,15 @@ var Parser = class {
32411
32535
  this.expect("END" /* END */);
32412
32536
  return { type: "CASE_WHEN", branches, elseResult };
32413
32537
  }
32414
- /** THEN / ELSE の結果値: 文字列リテラル / 配列リテラル / 文字列関数 / 算術式 */
32538
+ /** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
32415
32539
  parseCaseResult() {
32416
32540
  const tok = this.peek();
32417
32541
  if (tok.kind === "[" /* LBRACKET */) {
32418
32542
  return this.parseArrayLiteral();
32419
32543
  }
32544
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
32545
+ return this.parseScalarValueExpr({ allowAggregateArgs: true });
32546
+ }
32420
32547
  if (tok.kind === "STRING" /* STRING */) {
32421
32548
  this.advance();
32422
32549
  return { type: "STRING", value: tok.value };
@@ -32564,25 +32691,19 @@ var Parser = class {
32564
32691
  }
32565
32692
  return { type: "STRING", value: normalized };
32566
32693
  }
32567
- /** 文字列関数の引数: 文字列リテラル / ネスト文字列関数 / 算術式 / 集計算術式 */
32694
+ /** 文字列関数の引数: ScalarValueExpr / 集計算術式 */
32568
32695
  parseStringFuncArg() {
32569
- const tok = this.peek();
32570
- if (tok.kind === "STRING" /* STRING */) {
32571
- this.advance();
32572
- return { type: "STRING", value: tok.value };
32573
- }
32574
- if (this.tryStringFuncName() !== null) {
32575
- return this.parseStringFuncExpr();
32576
- }
32577
- const startPos = this.pos;
32578
- try {
32579
- const left = this.parseAggPrimary();
32580
- const expr = this.continueAggArith(left);
32581
- if (this.hasAggregateOperand(expr)) return expr;
32582
- } catch {
32696
+ if (this.scalarAllowsAggregateArgs) {
32697
+ const startPos = this.pos;
32698
+ try {
32699
+ const left = this.parseAggPrimary();
32700
+ const expr = this.continueAggArith(left);
32701
+ if (this.hasAggregateOperand(expr)) return expr;
32702
+ } catch {
32703
+ }
32704
+ this.pos = startPos;
32583
32705
  }
32584
- this.pos = startPos;
32585
- return this.parseArithAddSub();
32706
+ return this.parseScalarAddSubConcat(this.scalarAllowsCase);
32586
32707
  }
32587
32708
  hasAggregateOperand(node) {
32588
32709
  if (node.type === "AGG_REF") return true;
@@ -32670,6 +32791,7 @@ var Parser = class {
32670
32791
  const k = this.peek().kind;
32671
32792
  if (k === "IDENT" /* IDENT */ || k === "BIDENT" /* BIDENT */) {
32672
32793
  if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "VALIDATE" && this.peekAt(1).kind === "IDENT" /* IDENT */ && this.peekAt(1).value.toUpperCase() === "ONLY") return null;
32794
+ if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "CHECK" && this.peekAt(1).kind === "WHEN" /* WHEN */) return null;
32673
32795
  return this.parseTableAliasName();
32674
32796
  }
32675
32797
  return null;
@@ -33135,8 +33257,9 @@ var Parser = class {
33135
33257
  if (subtableCode) {
33136
33258
  throw new ParseError("INSERT INTO ... SELECT \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB\u4EEE\u60F3\u30C6\u30FC\u30D6\u30EB\u3067\u306F\u672A\u5BFE\u5FDC\u3067\u3059", this.prev());
33137
33259
  }
33260
+ const checkGroups2 = this.parseCheckGroups();
33138
33261
  const validation2 = this.parseDmlControlSuffix();
33139
- return { type: "INSERT_SELECT", appId, fields, select, ...validation2 };
33262
+ return { type: "INSERT_SELECT", appId, fields, select, ...checkGroups2, ...validation2 };
33140
33263
  }
33141
33264
  this.expect("VALUES" /* VALUES */);
33142
33265
  const values = [];
@@ -33146,11 +33269,15 @@ var Parser = class {
33146
33269
  this.expect(")" /* RPAREN */);
33147
33270
  values.push(row);
33148
33271
  } while (this.consume("," /* COMMA */));
33272
+ const checkGroups = this.parseCheckGroups();
33149
33273
  const validation = this.parseDmlControlSuffix();
33274
+ if (subtableCode && checkGroups.checkGroups) {
33275
+ throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB INSERT \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
33276
+ }
33150
33277
  if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
33151
33278
  throw new ParseError("VALIDATE ONLY / ON ERROR SKIP \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB INSERT \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
33152
33279
  }
33153
- return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...validation } : { type: "INSERT", appId, fields, values, ...validation };
33280
+ return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...checkGroups, ...validation } : { type: "INSERT", appId, fields, values, ...checkGroups, ...validation };
33154
33281
  }
33155
33282
  parseUpsert() {
33156
33283
  this.expect("UPSERT" /* UPSERT */);
@@ -33167,8 +33294,9 @@ var Parser = class {
33167
33294
  if (this.peek().kind === "SELECT" /* SELECT */) {
33168
33295
  const select = this.parseSelect();
33169
33296
  const keyFields2 = this.parseOnDuplicate();
33297
+ const checkGroups2 = this.parseCheckGroups();
33170
33298
  const validation2 = this.parseDmlControlSuffix();
33171
- return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...validation2 };
33299
+ return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...checkGroups2, ...validation2 };
33172
33300
  }
33173
33301
  this.expect("VALUES" /* VALUES */);
33174
33302
  const values = [];
@@ -33178,8 +33306,9 @@ var Parser = class {
33178
33306
  this.expect(")" /* RPAREN */);
33179
33307
  } while (this.consume("," /* COMMA */));
33180
33308
  const keyFields = this.parseOnDuplicate();
33309
+ const checkGroups = this.parseCheckGroups();
33181
33310
  const validation = this.parseDmlControlSuffix();
33182
- return { type: "UPSERT", appId, fields, values, keyFields, ...validation };
33311
+ return { type: "UPSERT", appId, fields, values, keyFields, ...checkGroups, ...validation };
33183
33312
  }
33184
33313
  parseOnDuplicate() {
33185
33314
  this.expectKeyword("ON" /* ON */, "UPSERT \u306B\u306F ON DUPLICATE (\u30AD\u30FC\u30D5\u30A3\u30FC\u30EB\u30C9) \u304C\u5FC5\u8981\u3067\u3059");
@@ -33311,12 +33440,33 @@ var Parser = class {
33311
33440
  whereTok
33312
33441
  );
33313
33442
  }
33443
+ const checkGroups = this.parseCheckGroups();
33314
33444
  const validation = this.parseDmlControlSuffix();
33445
+ if (subtableCode && checkGroups.checkGroups) {
33446
+ throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
33447
+ }
33315
33448
  if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
33316
33449
  throw new ParseError("VALIDATE ONLY / ON ERROR SKIP \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
33317
33450
  }
33318
- if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...validation };
33319
- return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...validation } : { type: "UPDATE", appId, assignments, where, ...validation };
33451
+ if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...checkGroups, ...validation };
33452
+ return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...checkGroups, ...validation } : { type: "UPDATE", appId, assignments, where, ...checkGroups, ...validation };
33453
+ }
33454
+ /** CHECK WHEN ... THEN ... blocks. CHECK is a soft keyword. */
33455
+ parseCheckGroups() {
33456
+ const groups = [];
33457
+ while (this.isSoftKeyword("CHECK") && this.peekAt(1).kind === "WHEN" /* WHEN */) {
33458
+ const check2 = this.advance();
33459
+ const rules = [];
33460
+ while (this.consume("WHEN" /* WHEN */)) {
33461
+ const condition = this.parseWhereExpr();
33462
+ this.expect("THEN" /* THEN */, "CHECK WHEN \u306E\u6761\u4EF6\u306E\u5F8C\u306B\u306F THEN \u304C\u5FC5\u8981\u3067\u3059");
33463
+ const message = this.parseScalarValueExpr({ allowCase: false });
33464
+ rules.push({ condition, message });
33465
+ }
33466
+ if (rules.length === 0) throw new ParseError("CHECK \u306E\u5F8C\u306B\u306F WHEN \u304C\u6700\u4F4E 1 \u3064\u5FC5\u8981\u3067\u3059", check2);
33467
+ groups.push({ rules });
33468
+ }
33469
+ return groups.length > 0 ? { checkGroups: groups } : {};
33320
33470
  }
33321
33471
  /** DML末尾の VALIDATE ONLY または ON ERROR SKIP。各語はsoft keyword。 */
33322
33472
  parseDmlControlSuffix() {
@@ -33505,6 +33655,12 @@ var Parser = class {
33505
33655
  */
33506
33656
  parseAssignmentValue() {
33507
33657
  const tok = this.peek();
33658
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
33659
+ const expr = this.parseScalarValueExpr();
33660
+ if (expr.type === "CONCAT_OP" || expr.type === "SCALAR_ARITH" || expr.type === "STRING_FUNC") return expr;
33661
+ if (expr.type === "CASE_WHEN") return { type: "CASE_VALUE", expr };
33662
+ throw new ParseError("SET \u306E\u5024\u306B\u306F\u9023\u7D50\u3092\u542B\u3080\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u304C\u5FC5\u8981\u3067\u3059", tok);
33663
+ }
33508
33664
  if (tok.kind === "VARIABLE" /* VARIABLE */) return this.parseSqlValue();
33509
33665
  if (tok.kind === "STRING" /* STRING */) return this.parseSqlValue();
33510
33666
  if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) return this.parseSqlValue();
@@ -34116,7 +34272,7 @@ function resolveSelectMode(stmt) {
34116
34272
  if (stmt.distinct) return "FULL_SCAN";
34117
34273
  if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
34118
34274
  if (stmt.columns.some(
34119
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
34275
+ (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate(c.expr)
34120
34276
  )) return "FULL_SCAN";
34121
34277
  if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
34122
34278
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
@@ -34211,6 +34367,8 @@ function extractFields(columns) {
34211
34367
  collectArithNode(col.expr, fields);
34212
34368
  } else if (col.type === "STRFUNC_COL") {
34213
34369
  collectStringFuncFields(col.expr, fields);
34370
+ } else if (col.type === "SCALAR_VALUE_COL") {
34371
+ collectScalarValueFields(col.expr, fields);
34214
34372
  }
34215
34373
  }
34216
34374
  return [...new Set(fields)];
@@ -34236,16 +34394,38 @@ function collectStringFuncFields(expr, out) {
34236
34394
  }
34237
34395
  }
34238
34396
  function collectStringFuncArgFields(arg, out) {
34239
- if (arg.type === "STRING") return;
34240
- if (arg.type === "STRING_FUNC") {
34241
- collectStringFuncFields(arg, out);
34242
- return;
34243
- }
34244
34397
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
34245
34398
  collectAggOperandFields(arg, out);
34246
34399
  return;
34247
34400
  }
34248
- collectArithNode(arg, out);
34401
+ collectScalarValueFields(arg, out);
34402
+ }
34403
+ function collectScalarValueFields(expr, out) {
34404
+ if (expr.type === "FIELD") {
34405
+ out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
34406
+ return;
34407
+ }
34408
+ if (expr.type === "STRING_FUNC") {
34409
+ collectStringFuncFields(expr, out);
34410
+ return;
34411
+ }
34412
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
34413
+ collectScalarValueFields(expr.left, out);
34414
+ collectScalarValueFields(expr.right, out);
34415
+ return;
34416
+ }
34417
+ if (expr.type === "CASE_WHEN") {
34418
+ for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
34419
+ if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
34420
+ }
34421
+ }
34422
+ function collectCaseResultScalarFields(result, out) {
34423
+ if (result.type === "ARRAY") return;
34424
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
34425
+ collectArithNode(result, out);
34426
+ return;
34427
+ }
34428
+ collectScalarValueFields(result, out);
34249
34429
  }
34250
34430
  function collectAggOperandFields(node, out) {
34251
34431
  if (node.type === "AGG_REF") {
@@ -34260,10 +34440,23 @@ function collectAggOperandFields(node, out) {
34260
34440
  function hasAggregateInStringFuncExpr(expr) {
34261
34441
  return expr.args.some((arg) => {
34262
34442
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
34263
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(arg);
34264
- return false;
34443
+ return scalarValueHasAggregate(arg);
34265
34444
  });
34266
34445
  }
34446
+ function scalarValueHasAggregate(expr) {
34447
+ if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(expr);
34448
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
34449
+ return scalarValueHasAggregate(expr.left) || scalarValueHasAggregate(expr.right);
34450
+ }
34451
+ if (expr.type === "CASE_WHEN") {
34452
+ return expr.branches.some((b) => caseResultHasAggregate(b.result)) || expr.elseResult !== null && caseResultHasAggregate(expr.elseResult);
34453
+ }
34454
+ return false;
34455
+ }
34456
+ function caseResultHasAggregate(result) {
34457
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
34458
+ return scalarValueHasAggregate(result);
34459
+ }
34267
34460
  function collectRequiredFieldsByTable(stmt) {
34268
34461
  const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
34269
34462
  const states = /* @__PURE__ */ new Map();
@@ -34398,28 +34591,38 @@ function collectRequiredFieldsByTable(stmt) {
34398
34591
  }
34399
34592
  };
34400
34593
  const walkStringArg = (arg, phase = "select") => {
34401
- if (arg.type === "STRING") return;
34402
- if (arg.type === "STRING_FUNC") {
34403
- walkStringFunc(arg, phase);
34404
- return;
34405
- }
34406
34594
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
34407
34595
  walkAgg(arg, phase);
34408
34596
  return;
34409
34597
  }
34410
- walkArith(arg, phase);
34598
+ walkScalar(arg, phase);
34411
34599
  };
34412
34600
  const walkStringFunc = (expr, phase = "select") => {
34413
34601
  for (const arg of expr.args) walkStringArg(arg, phase);
34414
34602
  };
34603
+ const walkScalar = (expr, phase = "select") => {
34604
+ if (expr.type === "FIELD") {
34605
+ addFieldRef(expr.field, expr.tableAlias, phase);
34606
+ return;
34607
+ }
34608
+ if (expr.type === "STRING_FUNC") {
34609
+ walkStringFunc(expr, phase);
34610
+ return;
34611
+ }
34612
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
34613
+ walkScalar(expr.left, phase);
34614
+ walkScalar(expr.right, phase);
34615
+ return;
34616
+ }
34617
+ if (expr.type === "CASE_WHEN") walkCase(expr, phase);
34618
+ };
34415
34619
  const walkCaseResult = (result, phase = "select") => {
34416
- if (result.type === "STRING") return;
34417
34620
  if (result.type === "ARRAY") return;
34418
- if (result.type === "STRING_FUNC") {
34419
- walkStringFunc(result, phase);
34621
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
34622
+ walkArith(result, phase);
34420
34623
  return;
34421
34624
  }
34422
- walkArith(result, phase);
34625
+ walkScalar(result, phase);
34423
34626
  };
34424
34627
  const walkCase = (expr, phase = "select") => {
34425
34628
  for (const b of expr.branches) {
@@ -34525,6 +34728,9 @@ function collectRequiredFieldsByTable(stmt) {
34525
34728
  case "STRFUNC_COL":
34526
34729
  walkStringFunc(col.expr, "select");
34527
34730
  break;
34731
+ case "SCALAR_VALUE_COL":
34732
+ walkScalar(col.expr, "select");
34733
+ break;
34528
34734
  case "SCALAR_SUBQUERY_COL":
34529
34735
  break;
34530
34736
  case "WINDOW_COL":
@@ -34575,6 +34781,10 @@ function collectSelectOutputNames(columns) {
34575
34781
  if (col.alias) names.add(col.alias);
34576
34782
  continue;
34577
34783
  }
34784
+ if (col.type === "SCALAR_VALUE_COL") {
34785
+ if (col.alias) names.add(col.alias);
34786
+ continue;
34787
+ }
34578
34788
  if (col.type === "SCALAR_SUBQUERY_COL") {
34579
34789
  names.add(col.alias ?? "(subquery)");
34580
34790
  continue;
@@ -34597,14 +34807,32 @@ function arithNodeLabel(node) {
34597
34807
  }
34598
34808
  function stringFuncLabel(expr) {
34599
34809
  const args = expr.args.map((a) => {
34600
- if (a.type === "STRING") return `'${a.value}'`;
34601
- if (a.type === "STRING_FUNC") return stringFuncLabel(a);
34602
34810
  if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
34603
34811
  if (a.type === "AGG_ARITH") return "agg_arith";
34604
- return arithNodeLabel(a);
34812
+ return scalarValueLabel(a);
34605
34813
  });
34606
34814
  return `${expr.func}(${args.join(",")})`;
34607
34815
  }
34816
+ function scalarValueLabel(expr) {
34817
+ switch (expr.type) {
34818
+ case "STRING":
34819
+ return `'${expr.value}'`;
34820
+ case "NUMBER":
34821
+ return numberLiteralText(expr);
34822
+ case "VARIABLE":
34823
+ return `@${expr.name}`;
34824
+ case "FIELD":
34825
+ return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
34826
+ case "STRING_FUNC":
34827
+ return stringFuncLabel(expr);
34828
+ case "CASE_WHEN":
34829
+ return "case";
34830
+ case "SCALAR_ARITH":
34831
+ return `(${scalarValueLabel(expr.left)}${expr.op}${scalarValueLabel(expr.right)})`;
34832
+ case "CONCAT_OP":
34833
+ return `(${scalarValueLabel(expr.left)}||${scalarValueLabel(expr.right)})`;
34834
+ }
34835
+ }
34608
34836
  function isAggregateSyntheticName(name) {
34609
34837
  return /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT)\(/i.test(name);
34610
34838
  }
@@ -35547,6 +35775,45 @@ function evalArithExpr(expr, row) {
35547
35775
  return r !== 0 ? l % r : NaN;
35548
35776
  }
35549
35777
  }
35778
+ function evalScalarValueExpr(expr, row) {
35779
+ switch (expr.type) {
35780
+ case "STRING":
35781
+ return expr.value;
35782
+ case "NUMBER":
35783
+ return expr.value;
35784
+ case "FIELD":
35785
+ return resolveFieldRef(row, expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
35786
+ case "VARIABLE":
35787
+ throw new Error(`ArgumentError: unresolved variable @${expr.name} reached scalar evaluator.`);
35788
+ case "STRING_FUNC":
35789
+ return evalStringFunc(expr, row);
35790
+ case "CASE_WHEN":
35791
+ return evalCaseWhen(expr, row);
35792
+ case "CONCAT_OP": {
35793
+ return evalStringFunc({
35794
+ type: "STRING_FUNC",
35795
+ func: "CONCAT",
35796
+ args: [expr.left, expr.right]
35797
+ }, row);
35798
+ }
35799
+ case "SCALAR_ARITH": {
35800
+ const left = Number(evalScalarValueExpr(expr.left, row));
35801
+ const right = Number(evalScalarValueExpr(expr.right, row));
35802
+ switch (expr.op) {
35803
+ case "+":
35804
+ return left + right;
35805
+ case "-":
35806
+ return left - right;
35807
+ case "*":
35808
+ return left * right;
35809
+ case "/":
35810
+ return right !== 0 ? left / right : NaN;
35811
+ case "%":
35812
+ return right !== 0 ? left % right : NaN;
35813
+ }
35814
+ }
35815
+ }
35816
+ }
35550
35817
  function applyRoundOp(op, num, digits) {
35551
35818
  const factor = Math.pow(10, digits);
35552
35819
  const raw = Math[op](num * factor) / factor;
@@ -35949,12 +36216,9 @@ function formatWithComma(num, digits) {
35949
36216
  return decStr ? `${intFmt}.${decStr}` : intFmt;
35950
36217
  }
35951
36218
  function evalStringFuncArg(arg, row) {
35952
- if (arg.type === "STRING") return arg.value;
35953
- if (arg.type === "STRING_FUNC") return evalStringFunc(arg, row);
35954
- if (arg.type === "FIELD_REF") return resolveFieldRef(row, arg.field);
35955
- if (arg.type === "NUMBER") return numberLiteralText(arg);
35956
36219
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
35957
- return String(evalArithExpr(arg, row));
36220
+ if (arg.type === "NUMBER") return numberLiteralText(arg);
36221
+ return String(evalScalarValueExpr(arg, row));
35958
36222
  }
35959
36223
  function resolveFieldRef(row, field) {
35960
36224
  const direct = row[field];
@@ -36177,10 +36441,13 @@ function evalCaseWhen(expr, row, resolveFieldType, resolveFieldSemantics2) {
36177
36441
  }
36178
36442
  function evalCaseResult(result, row) {
36179
36443
  if (result.type === "ARRAY") return result.elements.map((e) => e.value).join(",");
36180
- if (result.type === "STRING") return result.value;
36181
- if (result.type === "STRING_FUNC") return evalStringFunc(result, row);
36182
- if (result.type === "FIELD_REF") return row[result.field] ?? "";
36183
- return String(evalArithExpr(result, row));
36444
+ if (result.type === "FIELD_REF") {
36445
+ return row[result.field] ?? "";
36446
+ }
36447
+ if (result.type === "ARITH") {
36448
+ return String(evalArithExpr(result, row));
36449
+ }
36450
+ return String(evalScalarValueExpr(result, row));
36184
36451
  }
36185
36452
  function resolveKintoneFunc(name) {
36186
36453
  const now = /* @__PURE__ */ new Date();
@@ -36224,6 +36491,63 @@ function matchLike(value, pattern) {
36224
36491
  return regex.test(value);
36225
36492
  }
36226
36493
 
36494
+ // src/core/dmlCustomCheck.ts
36495
+ function collectCheckFieldRefs(groups) {
36496
+ return collectRefs2(groups);
36497
+ }
36498
+ function collectCheckComparisonFieldRefs(groups) {
36499
+ return collectRefs2(groups.flatMap((group) => group.rules.map((rule) => rule.condition)));
36500
+ }
36501
+ function collectRefs2(root) {
36502
+ const refs = [];
36503
+ const seen = /* @__PURE__ */ new Set();
36504
+ const visit = (node) => {
36505
+ if (Array.isArray(node)) {
36506
+ node.forEach(visit);
36507
+ return;
36508
+ }
36509
+ if (node === null || typeof node !== "object") return;
36510
+ const obj = node;
36511
+ if (obj.type === "EXISTS" || obj.type === "SUBQUERY_IN_LIST" || obj.type === "SCALAR_SUBQUERY") {
36512
+ throw customCheckParseError("CHECK \u306B\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
36513
+ }
36514
+ if (obj.type === "FIELD" && typeof obj.field === "string") {
36515
+ add(typeof obj.tableAlias === "string" ? obj.tableAlias : null, obj.field);
36516
+ } else if (obj.type === "FIELD_REF" && typeof obj.field === "string") {
36517
+ const dot = obj.field.indexOf(".");
36518
+ add(dot > 0 ? obj.field.slice(0, dot) : null, dot > 0 ? obj.field.slice(dot + 1) : obj.field);
36519
+ }
36520
+ for (const value of Object.values(obj)) visit(value);
36521
+ };
36522
+ const add = (tableAlias, field) => {
36523
+ if (/^(COUNT|SUM|AVG|MIN|MAX|GROUP_CONCAT)\(/i.test(field)) {
36524
+ throw customCheckParseError("CHECK \u306B\u96C6\u7D04\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
36525
+ }
36526
+ const key = `${tableAlias ?? ""}\0${field}`;
36527
+ if (!seen.has(key)) {
36528
+ seen.add(key);
36529
+ refs.push({ tableAlias, field });
36530
+ }
36531
+ };
36532
+ visit(root);
36533
+ return refs;
36534
+ }
36535
+ function customCheckParseError(message) {
36536
+ return new ParseError(message, { kind: "EOF" /* EOF */, value: "CHECK", pos: 0 });
36537
+ }
36538
+ function evaluateCustomChecks(groups, row, resolveFieldType) {
36539
+ const errors = [];
36540
+ groups.forEach((group, groupIndex) => {
36541
+ for (const rule of group.rules) {
36542
+ if (!evalWhere(rule.condition, row, resolveFieldType)) continue;
36543
+ const value = evalScalarValueExpr(rule.message, row);
36544
+ errors.push({ groupIndex, message: value == null ? "" : String(value) });
36545
+ break;
36546
+ }
36547
+ });
36548
+ return errors;
36549
+ }
36550
+
36227
36551
  // src/converter/dmlToKintone.ts
36228
36552
  function assertDmlWhereIsSafe(where) {
36229
36553
  if (whereHasKlike(where)) {
@@ -36261,10 +36585,11 @@ function buildInsertRecord(fields, row, fieldTypes) {
36261
36585
  }
36262
36586
  function updateToGetQuery(stmt) {
36263
36587
  assertDmlWhereIsSafe(stmt.where);
36588
+ const checkFields = collectUpdateCheckTargetFields(stmt);
36264
36589
  return {
36265
36590
  app: stmt.appId,
36266
36591
  query: whereToKintone(stmt.where),
36267
- fields: ["$id"],
36592
+ fields: ["$id", ...checkFields],
36268
36593
  totalCount: false
36269
36594
  };
36270
36595
  }
@@ -36278,19 +36603,19 @@ function updateToPutBatches(stmt, ids, fieldTypes = /* @__PURE__ */ new Map()) {
36278
36603
  function buildUpdateRecord(assignments, fieldTypes) {
36279
36604
  const record2 = {};
36280
36605
  for (const { field, value } of assignments) {
36281
- if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
36606
+ if (value.type === "ARITH" || value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
36282
36607
  record2[field] = { value: toKintoneValue(value, fieldTypes.get(field)) };
36283
36608
  }
36284
36609
  return record2;
36285
36610
  }
36286
36611
  function hasArithAssignment(stmt) {
36287
36612
  return stmt.assignments.some(
36288
- (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE"
36613
+ (a) => a.value.type === "ARITH" || a.value.type === "SCALAR_ARITH" || a.value.type === "CONCAT_OP" || a.value.type === "CASE_VALUE"
36289
36614
  );
36290
36615
  }
36291
36616
  function hasRowDependentAssignment(stmt) {
36292
36617
  return stmt.assignments.some(
36293
- (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
36618
+ (a) => a.value.type === "ARITH" || a.value.type === "SCALAR_ARITH" || a.value.type === "CONCAT_OP" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
36294
36619
  );
36295
36620
  }
36296
36621
  function updateToGetQueryForArith(stmt) {
@@ -36299,12 +36624,15 @@ function updateToGetQueryForArith(stmt) {
36299
36624
  for (const { value } of stmt.assignments) {
36300
36625
  if (value.type === "ARITH") {
36301
36626
  collectArithFields2(value, refFields);
36627
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
36628
+ collectScalarValueFields2(value, refFields);
36302
36629
  } else if (value.type === "STRING_FUNC") {
36303
36630
  collectStringFuncFields2(value, refFields);
36304
36631
  } else if (value.type === "CASE_VALUE") {
36305
36632
  collectCaseFields(value.expr, refFields);
36306
36633
  }
36307
36634
  }
36635
+ collectUpdateCheckTargetFields(stmt).forEach((field) => refFields.add(field));
36308
36636
  return {
36309
36637
  app: stmt.appId,
36310
36638
  query: whereToKintone(stmt.where),
@@ -36325,16 +36653,27 @@ function collectStringFuncFields2(expr, out) {
36325
36653
  for (const arg of expr.args) collectStringFuncArgFields2(arg, out);
36326
36654
  }
36327
36655
  function collectStringFuncArgFields2(arg, out) {
36328
- if (arg.type === "STRING") return;
36329
- if (arg.type === "STRING_FUNC") {
36330
- collectStringFuncFields2(arg, out);
36331
- return;
36332
- }
36333
36656
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
36334
36657
  collectAggOperandFields2(arg, out);
36335
36658
  return;
36336
36659
  }
36337
- collectArithNode2(arg, out);
36660
+ collectScalarValueFields2(arg, out);
36661
+ }
36662
+ function collectScalarValueFields2(expr, out) {
36663
+ if (expr.type === "FIELD") {
36664
+ out.add(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
36665
+ return;
36666
+ }
36667
+ if (expr.type === "STRING_FUNC") {
36668
+ collectStringFuncFields2(expr, out);
36669
+ return;
36670
+ }
36671
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
36672
+ collectScalarValueFields2(expr.left, out);
36673
+ collectScalarValueFields2(expr.right, out);
36674
+ return;
36675
+ }
36676
+ if (expr.type === "CASE_WHEN") collectCaseFields(expr, out);
36338
36677
  }
36339
36678
  function collectAggOperandFields2(node, out) {
36340
36679
  if (node.type === "AGG_REF") {
@@ -36347,9 +36686,12 @@ function collectAggOperandFields2(node, out) {
36347
36686
  }
36348
36687
  }
36349
36688
  function collectCaseResultFields(result, out) {
36350
- if (result.type === "STRING") return;
36351
36689
  if (result.type === "ARRAY") return;
36352
- collectArithNode2(result, out);
36690
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
36691
+ collectArithNode2(result, out);
36692
+ return;
36693
+ }
36694
+ collectScalarValueFields2(result, out);
36353
36695
  }
36354
36696
  function collectCaseFields(expr, out) {
36355
36697
  for (const branch of expr.branches) {
@@ -36387,6 +36729,8 @@ function updateToPutBatchesArith(stmt, records, fieldTypes = /* @__PURE__ */ new
36387
36729
  for (const { field, value } of stmt.assignments) {
36388
36730
  if (value.type === "ARITH") {
36389
36731
  record2[field] = { value: String(evalArith(value, raw)) };
36732
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
36733
+ record2[field] = { value: String(evalScalarValueExpr(value, row)) };
36390
36734
  } else if (value.type === "STRING_FUNC") {
36391
36735
  record2[field] = { value: evalStringFunc(value, row) };
36392
36736
  } else if (value.type === "CASE_VALUE") {
@@ -36441,6 +36785,8 @@ function updateFromToPutBatches(stmt, matched, fieldTypes = /* @__PURE__ */ new
36441
36785
  throw new DmlConvertError("UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
36442
36786
  } else if (value.type === "ARITH") {
36443
36787
  record2[field] = { value: String(evalArith(value, target)) };
36788
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
36789
+ record2[field] = { value: String(evalScalarValueExpr(value, targetRow)) };
36444
36790
  } else if (value.type === "CASE_VALUE") {
36445
36791
  record2[field] = { value: evalCaseWhenValue(value.expr, targetRow, fieldType) };
36446
36792
  } else {
@@ -36551,7 +36897,15 @@ function evalCaseResultValue(result, row, fieldType) {
36551
36897
  if (result.type === "STRING_FUNC") {
36552
36898
  return evalStringFunc(result, row);
36553
36899
  }
36554
- return String(evalArithExpr(result, row));
36900
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
36901
+ return String(evalArithExpr(result, row));
36902
+ }
36903
+ return String(evalScalarValueExpr(result, row));
36904
+ }
36905
+ function collectUpdateCheckTargetFields(stmt) {
36906
+ if (!stmt.checkGroups) return [];
36907
+ const targetAlias = `app${stmt.appId}`.toLowerCase();
36908
+ return [...new Set(collectCheckFieldRefs(stmt.checkGroups).filter((ref) => ref.tableAlias === null || ref.tableAlias.toLowerCase() === targetAlias).map((ref) => ref.field).filter((field) => field !== "$id"))];
36555
36909
  }
36556
36910
  function evalCaseWhenValue(expr, row, fieldType) {
36557
36911
  for (const branch of expr.branches) {
@@ -37104,7 +37458,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
37104
37458
  }
37105
37459
  function hasAggregateColumns(columns) {
37106
37460
  return columns.some(
37107
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr)
37461
+ (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
37108
37462
  );
37109
37463
  }
37110
37464
  function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
@@ -37141,6 +37495,10 @@ function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
37141
37495
  const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
37142
37496
  const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
37143
37497
  outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
37498
+ } else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
37499
+ const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
37500
+ const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
37501
+ outRow[outputKey] = String(evalScalarValueExpr(resolvedExpr, outRow));
37144
37502
  }
37145
37503
  }
37146
37504
  result.push(outRow);
@@ -37471,6 +37829,13 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
37471
37829
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
37472
37830
  break;
37473
37831
  }
37832
+ case "SCALAR_VALUE_COL": {
37833
+ const key = outputKeys?.[colIdx] ?? col.alias ?? scalarValueDefaultKey(col.expr);
37834
+ const srcKey = scalarValueDefaultKey(col.expr);
37835
+ out[key] = scalarValueHasAggregate2(col.expr) ? row[col.alias ?? srcKey] ?? row[srcKey] ?? "" : String(evalScalarValueExpr(col.expr, row));
37836
+ if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
37837
+ break;
37838
+ }
37474
37839
  case "SCALAR_SUBQUERY_COL": {
37475
37840
  const key = outputKeys?.[colIdx] ?? col.alias ?? "(subquery)";
37476
37841
  out[key] = scalarCache?.get(colIdx) ?? "";
@@ -37521,6 +37886,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
37521
37886
  return col.alias ?? "case";
37522
37887
  case "STRFUNC_COL":
37523
37888
  return col.alias ?? stringFuncDefaultKey(col.expr);
37889
+ case "SCALAR_VALUE_COL":
37890
+ return col.alias ?? scalarValueDefaultKey(col.expr);
37524
37891
  case "SCALAR_SUBQUERY_COL":
37525
37892
  return col.alias ?? "(subquery)";
37526
37893
  case "WINDOW_COL":
@@ -37576,18 +37943,49 @@ function arithColDefaultKey(expr) {
37576
37943
  }
37577
37944
  function stringFuncDefaultKey(expr) {
37578
37945
  const argStrs = expr.args.map((a) => {
37579
- if (a.type === "STRING") return `'${a.value}'`;
37580
- if (a.type === "STRING_FUNC") return stringFuncDefaultKey(a);
37581
37946
  if (a.type === "AGG_REF" || a.type === "AGG_ARITH") return aggArithDefaultKey(a);
37582
- return arithColDefaultKey(a);
37947
+ return scalarValueDefaultKey(a);
37583
37948
  });
37584
37949
  return `${expr.func}(${argStrs.join(",")})`;
37585
37950
  }
37951
+ function scalarValueDefaultKey(expr) {
37952
+ switch (expr.type) {
37953
+ case "STRING":
37954
+ return `'${expr.value}'`;
37955
+ case "NUMBER":
37956
+ return numberLiteralText(expr);
37957
+ case "VARIABLE":
37958
+ return `@${expr.name}`;
37959
+ case "FIELD":
37960
+ return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
37961
+ case "STRING_FUNC":
37962
+ return stringFuncDefaultKey(expr);
37963
+ case "CASE_WHEN":
37964
+ return "case";
37965
+ case "SCALAR_ARITH":
37966
+ return `${scalarValueDefaultKey(expr.left)}${expr.op}${scalarValueDefaultKey(expr.right)}`;
37967
+ case "CONCAT_OP":
37968
+ return `${scalarValueDefaultKey(expr.left)}||${scalarValueDefaultKey(expr.right)}`;
37969
+ }
37970
+ }
37586
37971
  function hasAggregateInStringFuncArg(arg) {
37587
37972
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
37588
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(arg);
37973
+ return scalarValueHasAggregate2(arg);
37974
+ }
37975
+ function scalarValueHasAggregate2(expr) {
37976
+ if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(expr);
37977
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
37978
+ return scalarValueHasAggregate2(expr.left) || scalarValueHasAggregate2(expr.right);
37979
+ }
37980
+ if (expr.type === "CASE_WHEN") {
37981
+ return expr.branches.some((branch) => caseResultHasAggregate2(branch.result)) || expr.elseResult !== null && caseResultHasAggregate2(expr.elseResult);
37982
+ }
37589
37983
  return false;
37590
37984
  }
37985
+ function caseResultHasAggregate2(result) {
37986
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
37987
+ return scalarValueHasAggregate2(result);
37988
+ }
37591
37989
  function hasAggregateInStringFuncExpr2(expr) {
37592
37990
  return expr.args.some((arg) => hasAggregateInStringFuncArg(arg));
37593
37991
  }
@@ -37603,7 +38001,18 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
37603
38001
  if (arg.type === "STRING_FUNC") {
37604
38002
  return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
37605
38003
  }
37606
- return arg;
38004
+ return resolveAggInScalarValue(arg, rows, resolveAggSortKind);
38005
+ }
38006
+ function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
38007
+ if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
38008
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
38009
+ return {
38010
+ ...expr,
38011
+ left: resolveAggInScalarValue(expr.left, rows, resolveAggSortKind),
38012
+ right: resolveAggInScalarValue(expr.right, rows, resolveAggSortKind)
38013
+ };
38014
+ }
38015
+ return expr;
37607
38016
  }
37608
38017
  function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
37609
38018
  return {
@@ -37624,7 +38033,7 @@ function deriveOutputOrderSemantics(columns) {
37624
38033
  } else if (column.func === "GROUP_CONCAT") {
37625
38034
  result.set(column.alias, syntheticSemantics("string"));
37626
38035
  }
37627
- } else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL") {
38036
+ } else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "SCALAR_VALUE_COL") {
37628
38037
  result.set(column.alias, syntheticSemantics("string"));
37629
38038
  } else if (column.type === "STRFUNC_COL") {
37630
38039
  result.set(column.alias, syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(column.expr.func) ? "number" : "string"));
@@ -37897,19 +38306,20 @@ var VALIDATION_META_COLUMNS = [
37897
38306
  "$err_code",
37898
38307
  "$err_message"
37899
38308
  ];
37900
- function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision) {
38309
+ function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true) {
37901
38310
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
37902
38311
  const errors = [];
37903
38312
  const invalid = /* @__PURE__ */ new Set();
38313
+ let firstEvaluationError;
37904
38314
  for (const candidate of candidates) {
37905
38315
  candidate.record ??= {};
37906
- const rowErrors = [...candidate.preErrors];
38316
+ const rowErrors = includePreErrors ? [...candidate.preErrors] : [];
37907
38317
  for (const code of targetFields) {
37908
38318
  const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
37909
38319
  if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
37910
38320
  else candidate.record[code] = { value: result.value };
37911
38321
  }
37912
- if (candidate.mode === "create") {
38322
+ if (validateMissingCreateFields && candidate.mode === "create") {
37913
38323
  for (const info of fieldInfos) {
37914
38324
  if (info.inSubtable) continue;
37915
38325
  if (candidate.payload.has(info.code)) continue;
@@ -37931,6 +38341,23 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37931
38341
  }
37932
38342
  }
37933
38343
  }
38344
+ if (checkGroups.length > 0) {
38345
+ const row = candidate.evaluationRow ?? Object.fromEntries(
38346
+ [...candidate.payload].map(([field, value]) => [field, renderValidationValue(value)])
38347
+ );
38348
+ const types = candidate.evaluationFieldTypes;
38349
+ const resolveType = (field) => {
38350
+ const qualified = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
38351
+ return types?.get(qualified) ?? types?.get(field.field);
38352
+ };
38353
+ try {
38354
+ for (const custom2 of evaluateCustomChecks(checkGroups, row, resolveType)) {
38355
+ rowErrors.push({ field: "", code: "ERR_CHECK", message: custom2.message });
38356
+ }
38357
+ } catch (error51) {
38358
+ firstEvaluationError ??= error51;
38359
+ }
38360
+ }
37934
38361
  if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
37935
38362
  for (const error51 of rowErrors) {
37936
38363
  const row = {};
@@ -37944,6 +38371,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
37944
38371
  errors.push(row);
37945
38372
  }
37946
38373
  }
38374
+ if (firstEvaluationError !== void 0) throw firstEvaluationError;
37947
38375
  return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid };
37948
38376
  }
37949
38377
  function renderValidationValue(value) {
@@ -39000,7 +39428,7 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
39000
39428
  }
39001
39429
  } else if (column.type === "STRFUNC_COL") {
39002
39430
  semantics = stringFunctionColumnMeta(column.expr).semantics;
39003
- } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL") {
39431
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL" || column.type === "SCALAR_VALUE_COL") {
39004
39432
  semantics = syntheticSemantics("string");
39005
39433
  }
39006
39434
  if (semantics) aliases.set(column.alias, semantics);
@@ -39115,10 +39543,19 @@ function arithHasFieldRef(node) {
39115
39543
  return false;
39116
39544
  }
39117
39545
  function stringFuncArgHasFieldRef(arg) {
39118
- if (arg.type === "FIELD_REF") return true;
39119
- if (arg.type === "ARITH") return arithHasFieldRef(arg);
39120
- if (arg.type === "STRING_FUNC") return stringFuncHasFieldRef(arg);
39121
39546
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
39547
+ return scalarValueHasFieldRef(arg);
39548
+ }
39549
+ function scalarValueHasFieldRef(expr) {
39550
+ if (expr.type === "FIELD") return true;
39551
+ if (expr.type === "STRING_FUNC") return stringFuncHasFieldRef(expr);
39552
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
39553
+ return scalarValueHasFieldRef(expr.left) || scalarValueHasFieldRef(expr.right);
39554
+ }
39555
+ if (expr.type === "CASE_WHEN") {
39556
+ const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
39557
+ return results.some((result) => result.type !== "ARRAY" && (result.type === "FIELD_REF" || result.type === "ARITH" ? arithHasFieldRef(result) : scalarValueHasFieldRef(result)));
39558
+ }
39122
39559
  return false;
39123
39560
  }
39124
39561
  function stringFuncHasFieldRef(expr) {
@@ -39139,6 +39576,11 @@ function validateNoFromColumns(stmt) {
39139
39576
  throw new Error("ArgumentError: field reference is not allowed without FROM.");
39140
39577
  }
39141
39578
  break;
39579
+ case "SCALAR_VALUE_COL":
39580
+ if (scalarValueHasFieldRef(col.expr)) {
39581
+ throw new Error("ArgumentError: field reference is not allowed without FROM.");
39582
+ }
39583
+ break;
39142
39584
  case "WINDOW_COL":
39143
39585
  if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
39144
39586
  throw new Error("ArgumentError: field reference is not allowed without FROM.");
@@ -39425,8 +39867,26 @@ function collectStringFuncAggregateRefs(expr, out) {
39425
39867
  for (const arg of expr.args) {
39426
39868
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
39427
39869
  collectAggregateOperandRefs(arg, out);
39428
- } else if (arg.type === "STRING_FUNC") {
39429
- collectStringFuncAggregateRefs(arg, out);
39870
+ } else {
39871
+ collectScalarAggregateRefs(arg, out);
39872
+ }
39873
+ }
39874
+ }
39875
+ function collectScalarAggregateRefs(expr, out) {
39876
+ if (expr.type === "STRING_FUNC") {
39877
+ collectStringFuncAggregateRefs(expr, out);
39878
+ return;
39879
+ }
39880
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
39881
+ collectScalarAggregateRefs(expr.left, out);
39882
+ collectScalarAggregateRefs(expr.right, out);
39883
+ return;
39884
+ }
39885
+ if (expr.type === "CASE_WHEN") {
39886
+ const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
39887
+ for (const result of results) {
39888
+ if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
39889
+ else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
39430
39890
  }
39431
39891
  }
39432
39892
  }
@@ -39439,6 +39899,8 @@ function collectSelectAggregateSortRefs(columns) {
39439
39899
  collectAggregateOperandRefs(column.expr, refs);
39440
39900
  } else if (column.type === "STRFUNC_COL") {
39441
39901
  collectStringFuncAggregateRefs(column.expr, refs);
39902
+ } else if (column.type === "SCALAR_VALUE_COL") {
39903
+ collectScalarAggregateRefs(column.expr, refs);
39442
39904
  }
39443
39905
  }
39444
39906
  return refs;
@@ -39604,10 +40066,11 @@ function stringFunctionColumnMeta(expr) {
39604
40066
  function caseResultColumnMeta(result, resolveField2) {
39605
40067
  if (result.type === "STRING") return syntheticColumnMeta("string");
39606
40068
  if (result.type === "ARRAY") return unsupportedColumnMeta();
39607
- if (result.type === "NUMBER" || result.type === "ARITH") return syntheticColumnMeta("number");
40069
+ if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
39608
40070
  if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
39609
- const source = resolveField2(aggregateFieldRef(result.field));
39610
- return source ?? unknownStringColumnMeta();
40071
+ if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();
40072
+ if (result.type === "FIELD") return resolveField2(result) ?? unknownStringColumnMeta();
40073
+ return unknownStringColumnMeta();
39611
40074
  }
39612
40075
  function mergeExpressionColumnMeta(candidates) {
39613
40076
  if (candidates.length === 0) return unknownStringColumnMeta();
@@ -39709,7 +40172,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
39709
40172
  }
39710
40173
  } else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
39711
40174
  meta3 = syntheticColumnMeta("number");
39712
- } else if (column.type === "LITERAL_COL") {
40175
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") {
39713
40176
  meta3 = syntheticColumnMeta("string");
39714
40177
  } else if (column.type === "STRFUNC_COL") {
39715
40178
  meta3 = stringFunctionColumnMeta(column.expr);
@@ -40416,7 +40879,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
40416
40879
  if (column.type === "FIELD") meta3 = resolveField2(aggregateFieldRef(column.field));
40417
40880
  else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
40418
40881
  meta3 = syntheticColumnMeta("number");
40419
- } else if (column.type === "LITERAL_COL") meta3 = syntheticColumnMeta("string");
40882
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta3 = syntheticColumnMeta("string");
40420
40883
  else if (column.type === "STRFUNC_COL") meta3 = stringFunctionColumnMeta(column.expr);
40421
40884
  else if (column.type === "SCALAR_SUBQUERY_COL") meta3 = unknownStringColumnMeta();
40422
40885
  else if (column.type === "CASE_COL") {
@@ -40604,7 +41067,7 @@ var RejectLimitExceededError = class extends Error {
40604
41067
  this.name = "RejectLimitExceededError";
40605
41068
  }
40606
41069
  };
40607
- async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
41070
+ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber, validateMissingCreateFields = true, includePreErrors = true) {
40608
41071
  const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
40609
41072
  const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
40610
41073
  if (new Set(payloadFields).size !== payloadFields.length) {
@@ -40636,7 +41099,10 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
40636
41099
  targetFields,
40637
41100
  fieldInfos,
40638
41101
  statementNumber,
40639
- numberPrecision
41102
+ numberPrecision,
41103
+ stmt.checkGroups ?? [],
41104
+ validateMissingCreateFields,
41105
+ includePreErrors
40640
41106
  );
40641
41107
  const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
40642
41108
  const result = {
@@ -40746,15 +41212,33 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
40746
41212
  async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode) {
40747
41213
  if (stmt.type === "UPDATE") return materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables);
40748
41214
  let rows;
41215
+ let sourceRows;
41216
+ let evaluationTypes;
40749
41217
  if (stmt.type === "INSERT" || stmt.type === "UPSERT") {
41218
+ assertInsertCheckRefs(stmt, stmt.fields);
41219
+ evaluationTypes = new Map(stmt.fields.map((field) => [field, infoByCode.get(field)?.fieldType ?? ""]));
41220
+ assertCheckComparisonTypes(stmt, evaluationTypes);
40750
41221
  rows = stmt.values.map((row) => row.map(
40751
41222
  (value, i) => value.type === "CASE_VALUE" ? evalCaseWhenValue(value.expr, {}, infoByCode.get(stmt.fields[i])?.fieldType) : value
40752
41223
  ));
40753
41224
  } else {
40754
- const selectResult = tempTables && tempTables.size > 0 ? await executeQueryWithCte(stmt.select, client, { ...options, onLimitReached: "error" }, tempTables, cacheContext) : await executeSelect(stmt.select, client, { ...options, onLimitReached: "error" }, cacheContext);
40755
- if (selectResult.columns.length !== stmt.fields.length) {
41225
+ const selectResult = tempTables && tempTables.size > 0 ? await executeQueryWithCte(stmt.select, client, { ...options, onLimitReached: "error" }, tempTables, cacheContext) : await executeSelect(stmt.select, client, { ...options, onLimitReached: "error" }, cacheContext, void 0, true);
41226
+ const hasChecks = (stmt.checkGroups?.length ?? 0) > 0;
41227
+ if (selectResult.columns.length < stmt.fields.length || !hasChecks && selectResult.columns.length !== stmt.fields.length) {
40756
41228
  throw new Error(`SELECT \u306E\u5217\u6570\uFF08${selectResult.columns.length}\uFF09\u3068 DML \u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u6570\uFF08${stmt.fields.length}\uFF09\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093`);
40757
41229
  }
41230
+ if (hasChecks && new Set(selectResult.columns).size !== selectResult.columns.length) {
41231
+ throw customCheckParseError("CHECK \u4ED8\u304D DML \u30BD\u30FC\u30B9 SELECT \u306E\u51FA\u529B\u540D\u306F\u4E00\u610F\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
41232
+ }
41233
+ assertInsertCheckRefs(stmt, selectResult.columns);
41234
+ sourceRows = selectResult.rows;
41235
+ const meta3 = materializedMetaBySelectResult.get(selectResult);
41236
+ evaluationTypes = new Map(selectResult.columns.map((column) => {
41237
+ const columnMeta = meta3?.get(column);
41238
+ const type = columnMeta?.fieldType ?? (columnMeta?.semantics?.compareMode === "number" || columnMeta?.sortKind === "number" ? "NUMBER" : "SINGLE_LINE_TEXT");
41239
+ return [column, type];
41240
+ }));
41241
+ assertCheckComparisonTypes(stmt, evaluationTypes);
40758
41242
  rows = selectResult.rows.map((row) => selectResult.columns.map((column) => row[column] ?? ""));
40759
41243
  }
40760
41244
  const candidates = rows.map((values, index) => ({
@@ -40763,7 +41247,11 @@ async function materializeValidationCandidates(stmt, operation, client, options,
40763
41247
  mode: "create",
40764
41248
  payload: new Map(stmt.fields.map((field, i) => [field, values[i]])),
40765
41249
  preErrors: [],
40766
- record: {}
41250
+ record: {},
41251
+ evaluationRow: sourceRows?.[index] ?? Object.fromEntries(
41252
+ stmt.fields.map((field, i) => [field, renderValidationValue(values[i])])
41253
+ ),
41254
+ evaluationFieldTypes: evaluationTypes
40767
41255
  }));
40768
41256
  if (stmt.type !== "UPSERT" && stmt.type !== "UPSERT_SELECT") return candidates;
40769
41257
  for (const key of stmt.keyFields) {
@@ -40792,26 +41280,74 @@ async function materializeValidationCandidates(stmt, operation, client, options,
40792
41280
  });
40793
41281
  return candidates;
40794
41282
  }
41283
+ function checkRefs(stmt) {
41284
+ return stmt.checkGroups ? collectCheckFieldRefs(stmt.checkGroups) : [];
41285
+ }
41286
+ function assertInsertCheckRefs(stmt, available) {
41287
+ const names = new Set(available);
41288
+ for (const ref of checkRefs(stmt)) {
41289
+ if (ref.tableAlias !== null) {
41290
+ throw customCheckParseError(`CHECK \u306E\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.tableAlias}.${ref.field} \u306F\u3053\u306E\u8A55\u4FA1\u884C\u3067\u306F\u4FEE\u98FE\u3067\u304D\u307E\u305B\u3093`);
41291
+ }
41292
+ if (!names.has(ref.field)) {
41293
+ throw customCheckParseError(`CHECK \u306E\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u8A55\u4FA1\u884C\u306B\u5B58\u5728\u3057\u307E\u305B\u3093`);
41294
+ }
41295
+ }
41296
+ }
41297
+ var CHECK_UNSUPPORTED_COMPARISON_TYPES = /* @__PURE__ */ new Set([
41298
+ "CHECK_BOX",
41299
+ "MULTI_SELECT",
41300
+ "USER_SELECT",
41301
+ "ORGANIZATION_SELECT",
41302
+ "GROUP_SELECT",
41303
+ "FILE",
41304
+ "KSQL_ARRAY"
41305
+ ]);
41306
+ function assertCheckComparisonTypes(stmt, types) {
41307
+ if (!stmt.checkGroups) return;
41308
+ for (const ref of collectCheckComparisonFieldRefs(stmt.checkGroups)) {
41309
+ const key = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
41310
+ const type = types.get(key) ?? types.get(ref.field);
41311
+ if (CHECK_UNSUPPORTED_COMPARISON_TYPES.has(type ?? "")) {
41312
+ throw customCheckParseError(`CHECK \u306E\u6BD4\u8F03\u3067\u306F ${type} \u30D5\u30A3\u30FC\u30EB\u30C9 ${key} \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
41313
+ }
41314
+ }
41315
+ }
40795
41316
  async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables) {
40796
41317
  if (stmt.from) return materializeUpdateFromValidationCandidates(stmt, stmt.from, client, options, cacheContext, tempTables);
40797
41318
  await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
40798
41319
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
41320
+ const checkTargetFields = assertUpdateCheckRefs(stmt, fieldTypes);
41321
+ assertCheckComparisonTypes(stmt, updateEvaluationTypes(fieldTypes, stmt.appId));
40799
41322
  let records;
41323
+ let evaluationById = /* @__PURE__ */ new Map();
40800
41324
  if (hasRowDependentAssignment(stmt)) {
40801
41325
  const getParams = updateToGetQueryForArith(stmt);
40802
- const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [...getParams.fields], {
41326
+ const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields])];
41327
+ const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
40803
41328
  maxRecords: options.maxRecords ?? 1e4,
40804
41329
  parallel: options.fetchParallel ?? 1,
40805
41330
  onLimit: "error"
40806
41331
  });
41332
+ evaluationById = new Map(resolved.records.map((record2) => [Number(record2["$id"]?.value), record2]));
40807
41333
  records = updateToPutBatchesArith(stmt, resolved.records, fieldTypes).flatMap((batch) => batch.records);
40808
41334
  } else {
40809
41335
  const getParams = updateToGetQuery(stmt);
40810
- const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
40811
- maxRecords: options.maxRecords ?? 1e4,
40812
- parallel: options.fetchParallel ?? 1
40813
- });
40814
- records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
41336
+ if (checkTargetFields.length > 0) {
41337
+ const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields])], {
41338
+ maxRecords: options.maxRecords ?? 1e4,
41339
+ parallel: options.fetchParallel ?? 1,
41340
+ onLimit: "error"
41341
+ });
41342
+ evaluationById = new Map(resolved.records.map((record2) => [Number(record2["$id"]?.value), record2]));
41343
+ records = updateToPutBatches(stmt, [...evaluationById.keys()], fieldTypes).flatMap((batch) => batch.records);
41344
+ } else {
41345
+ const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
41346
+ maxRecords: options.maxRecords ?? 1e4,
41347
+ parallel: options.fetchParallel ?? 1
41348
+ });
41349
+ records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
41350
+ }
40815
41351
  }
40816
41352
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
40817
41353
  rowNumber: index + 1,
@@ -40820,13 +41356,48 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
40820
41356
  payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
40821
41357
  preErrors: [],
40822
41358
  record: entry.record,
40823
- targetId: entry.id
41359
+ targetId: entry.id,
41360
+ evaluationRow: updateEvaluationRow(evaluationById.get(entry.id), stmt.appId),
41361
+ evaluationFieldTypes: updateEvaluationTypes(fieldTypes, stmt.appId)
40824
41362
  }));
40825
41363
  }
41364
+ function assertUpdateCheckRefs(stmt, targetTypes) {
41365
+ if (stmt.from) return [];
41366
+ const fields = /* @__PURE__ */ new Set();
41367
+ for (const ref of checkRefs(stmt)) {
41368
+ if (ref.tableAlias !== null && ref.tableAlias.toLowerCase() !== `app${stmt.appId}`.toLowerCase()) {
41369
+ throw customCheckParseError(`CHECK \u306E\u4FEE\u98FE\u5B50 ${ref.tableAlias} \u306F\u66F4\u65B0\u5148 APP${stmt.appId} \u3067\u306F\u3042\u308A\u307E\u305B\u3093`);
41370
+ }
41371
+ if (ref.field !== "$id" && !targetTypes.has(ref.field)) {
41372
+ throw customCheckParseError(`CHECK \u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
41373
+ }
41374
+ fields.add(ref.field);
41375
+ }
41376
+ return [...fields];
41377
+ }
41378
+ function updateEvaluationRow(record2, appId) {
41379
+ if (!record2) return {};
41380
+ const plain = flatten(record2, null);
41381
+ return Object.fromEntries([
41382
+ ...Object.entries(plain),
41383
+ ...Object.entries(plain).map(([field, value]) => [`APP${appId}.${field}`, value])
41384
+ ]);
41385
+ }
41386
+ function updateEvaluationTypes(types, appId) {
41387
+ return new Map([
41388
+ ...types,
41389
+ ...[...types].map(([field, type]) => [`APP${appId}.${field}`, type]),
41390
+ ["$id", "RECORD_NUMBER"],
41391
+ [`APP${appId}.$id`, "RECORD_NUMBER"]
41392
+ ]);
41393
+ }
40826
41394
  async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables) {
41395
+ const scope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
41396
+ assertCheckComparisonTypes(stmt, scope.evaluationTypes);
40827
41397
  const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
40828
41398
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
40829
41399
  const records = updateFromToPutBatches(stmt, matched, fieldTypes).flatMap((batch) => batch.records);
41400
+ const matchedById = new Map(matched.map((pair) => [Number(pair.target["$id"]?.value), pair]));
40830
41401
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
40831
41402
  rowNumber: index + 1,
40832
41403
  operation: "UPDATE",
@@ -40834,7 +41405,9 @@ async function materializeUpdateFromValidationCandidates(stmt, from, client, opt
40834
41405
  payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
40835
41406
  preErrors: [],
40836
41407
  record: entry.record,
40837
- targetId: entry.id
41408
+ targetId: entry.id,
41409
+ evaluationRow: updateFromEvaluationRow(matchedById.get(entry.id), stmt.appId, from.alias),
41410
+ evaluationFieldTypes: scope.evaluationTypes
40838
41411
  }));
40839
41412
  }
40840
41413
  var UPDATE_FROM_KEY_CHUNK_SIZE = UPSERT_IN_CHUNK_SIZE;
@@ -40848,7 +41421,8 @@ var UPDATE_FROM_UNSUPPORTED_SOURCE_TYPES = /* @__PURE__ */ new Set([
40848
41421
  ]);
40849
41422
  async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables) {
40850
41423
  const joinKind = await resolveUpdateFromTargetJoinKind(stmt, from, client, cacheContext);
40851
- const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : ""))];
41424
+ const checkScope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
41425
+ const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : "").concat(checkScope.sourceFields))];
40852
41426
  const requiredSourceFields = [.../* @__PURE__ */ new Set([from.joinKeyField, ...sourceFields])];
40853
41427
  const sourceRows = await loadUpdateFromSourceRows(
40854
41428
  from,
@@ -40874,8 +41448,8 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
40874
41448
  }
40875
41449
  if (sourceByKey.size === 0) return [];
40876
41450
  const maxRecords2 = options.maxRecords ?? 1e4;
40877
- const targetFields = collectUpdateFromTargetFields(stmt);
40878
- const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter }).query;
41451
+ const targetFields = [.../* @__PURE__ */ new Set([...collectUpdateFromTargetFields(stmt), ...checkScope.targetFields])];
41452
+ const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter, checkGroups: void 0 }).query;
40879
41453
  const targetRecords = [];
40880
41454
  const seenTargetIds = /* @__PURE__ */ new Set();
40881
41455
  let fetchedTargetCount = 0;
@@ -40993,7 +41567,54 @@ function normalizeUpdateFromJoinKey(raw, kind, side) {
40993
41567
  }
40994
41568
  return JSON.stringify(decimal);
40995
41569
  }
41570
+ async function executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables) {
41571
+ const prepared = await prepareDmlValidation(
41572
+ stmt,
41573
+ client,
41574
+ options,
41575
+ cacheContext,
41576
+ tempTables,
41577
+ 1,
41578
+ false,
41579
+ false
41580
+ );
41581
+ if (prepared.result.errors.length > 0) {
41582
+ const first = prepared.result.errors[0];
41583
+ throw new Error(
41584
+ `DmlValidationError: ${first["$err_code"]} ${first["$err_message"]} (row=${first["$err_row"]}, field=${first["$err_field"]})`
41585
+ );
41586
+ }
41587
+ const candidates = prepared.candidates;
41588
+ const confirmOperation = stmt.type.startsWith("INSERT") ? "INSERT" : "UPDATE";
41589
+ if (options.confirm && candidates.length > 0) {
41590
+ const ok = await options.confirm(candidates.length, confirmOperation);
41591
+ if (!ok) throw new OperationCancelledError(confirmOperation, candidates.length);
41592
+ }
41593
+ if (stmt.type === "INSERT" || stmt.type === "INSERT_SELECT") {
41594
+ const createdIds = [];
41595
+ for (let i = 0; i < candidates.length; i += 100) {
41596
+ const response = await client.postRecords({ app: stmt.appId, records: candidates.slice(i, i + 100).map((c) => c.record) });
41597
+ createdIds.push(response.ids);
41598
+ }
41599
+ return { type: "INSERT", createdIds, insertedCount: createdIds.flat().length };
41600
+ }
41601
+ if (stmt.type === "UPDATE") {
41602
+ const updates2 = candidates.map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
41603
+ for (let i = 0; i < updates2.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates2.slice(i, i + 100) });
41604
+ return { type: "UPDATE", updatedCount: updates2.length };
41605
+ }
41606
+ const inserts = candidates.filter((candidate) => candidate.mode === "create");
41607
+ const updates = candidates.filter((candidate) => candidate.mode === "update").map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
41608
+ let insertedCount = 0;
41609
+ for (let i = 0; i < inserts.length; i += 100) {
41610
+ const response = await client.postRecords({ app: stmt.appId, records: inserts.slice(i, i + 100).map((c) => c.record) });
41611
+ insertedCount += response.ids.length;
41612
+ }
41613
+ for (let i = 0; i < updates.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates.slice(i, i + 100) });
41614
+ return { type: "UPSERT", insertedCount, updatedCount: updates.length };
41615
+ }
40996
41616
  async function executeInsert(stmt, client, options, cacheContext) {
41617
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
40997
41618
  if (stmt.subtableCode) {
40998
41619
  return executeInsertSubtable(stmt, client, options, cacheContext);
40999
41620
  }
@@ -41014,6 +41635,7 @@ async function executeInsert(stmt, client, options, cacheContext) {
41014
41635
  };
41015
41636
  }
41016
41637
  async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
41638
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
41017
41639
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41018
41640
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
41019
41641
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
@@ -41051,6 +41673,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
41051
41673
  };
41052
41674
  }
41053
41675
  async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
41676
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables);
41054
41677
  if (stmt.subtableCode) {
41055
41678
  await assertDmlWhereCapability(stmt, client, cacheContext);
41056
41679
  return executeUpdateSubtable(stmt, client, options, cacheContext);
@@ -41176,6 +41799,7 @@ async function executeDelete(stmt, client, options, cacheContext) {
41176
41799
  return { type: "DELETE", deletedCount: ids.length };
41177
41800
  }
41178
41801
  async function executeUpsert(stmt, client, options, cacheContext) {
41802
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
41179
41803
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41180
41804
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
41181
41805
  const toInsert = [];
@@ -41610,6 +42234,7 @@ function evalOrderKeyForRow(key, row) {
41610
42234
  }
41611
42235
  }
41612
42236
  async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
42237
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
41613
42238
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
41614
42239
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
41615
42240
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
@@ -42357,6 +42982,7 @@ function collectArithRefFields(stmt) {
42357
42982
  for (const { value } of stmt.assignments) {
42358
42983
  if (value.type === "ARITH") collectArithNodeRefs(value, refs);
42359
42984
  if (value.type === "STRING_FUNC") collectArithNodeRefs(value, refs);
42985
+ if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") collectScalarNodeRefs(value, refs);
42360
42986
  }
42361
42987
  return [...refs];
42362
42988
  }
@@ -42371,10 +42997,74 @@ function collectArithNodeRefs(node, out) {
42371
42997
  }
42372
42998
  if (node.type === "STRING_FUNC") {
42373
42999
  for (const arg of node.args) {
42374
- if (arg.type !== "STRING" && arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") {
42375
- collectArithNodeRefs(arg, out);
43000
+ if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
43001
+ }
43002
+ }
43003
+ }
43004
+ async function resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables) {
43005
+ const refs = checkRefs(stmt);
43006
+ const targetTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
43007
+ const sourceTableName = from.cteName;
43008
+ const sourceTypes = sourceTableName !== null ? new Map((tempTables?.get(sourceTableName)?.columns ?? []).map((column) => [
43009
+ column,
43010
+ tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.fieldType ?? (tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.semantics?.compareMode === "number" ? "NUMBER" : "SINGLE_LINE_TEXT")
43011
+ ])) : await getFieldTypeMap(from.appId, client, cacheContext);
43012
+ const targetFields = /* @__PURE__ */ new Set();
43013
+ const sourceFields = /* @__PURE__ */ new Set();
43014
+ for (const ref of refs) {
43015
+ if (ref.tableAlias !== null) {
43016
+ if (ref.tableAlias.toLowerCase() === `app${stmt.appId}`.toLowerCase()) {
43017
+ if (ref.field !== "$id" && !targetTypes.has(ref.field)) throw customCheckParseError(`CHECK \u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
43018
+ targetFields.add(ref.field);
43019
+ } else if (ref.tableAlias.toLowerCase() === from.alias.toLowerCase()) {
43020
+ if (ref.field !== "$id" && !sourceTypes.has(ref.field)) throw customCheckParseError(`CHECK \u306E\u30BD\u30FC\u30B9\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
43021
+ sourceFields.add(ref.field);
43022
+ } else {
43023
+ throw customCheckParseError(`CHECK \u306E\u4FEE\u98FE\u5B50 ${ref.tableAlias} \u306F\u66F4\u65B0\u5148\u307E\u305F\u306F FROM alias \u3067\u306F\u3042\u308A\u307E\u305B\u3093`);
42376
43024
  }
43025
+ continue;
42377
43026
  }
43027
+ const inTarget = ref.field === "$id" || targetTypes.has(ref.field);
43028
+ const inSource = ref.field === "$id" || sourceTypes.has(ref.field);
43029
+ if (!inTarget) {
43030
+ throw customCheckParseError(`UPDATE FROM \u306E CHECK \u3067\u306F\u30BD\u30FC\u30B9\u5217 ${ref.field} \u3092\u4FEE\u98FE\u3057\u3066\u304F\u3060\u3055\u3044`);
43031
+ }
43032
+ if (inSource) {
43033
+ throw customCheckParseError(`UPDATE FROM \u306E CHECK \u306E\u975E\u4FEE\u98FE\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u66D6\u6627\u3067\u3059`);
43034
+ }
43035
+ targetFields.add(ref.field);
43036
+ }
43037
+ const evaluationTypes = /* @__PURE__ */ new Map();
43038
+ for (const [field, type] of targetTypes) {
43039
+ evaluationTypes.set(field, type);
43040
+ evaluationTypes.set(`APP${stmt.appId}.${field}`, type);
43041
+ }
43042
+ evaluationTypes.set("$id", "RECORD_NUMBER");
43043
+ evaluationTypes.set(`APP${stmt.appId}.$id`, "RECORD_NUMBER");
43044
+ for (const [field, type] of sourceTypes) evaluationTypes.set(`${from.alias}.${field}`, type);
43045
+ return { targetFields: [...targetFields], sourceFields: [...sourceFields], evaluationTypes };
43046
+ }
43047
+ function updateFromEvaluationRow(pair, appId, sourceAlias) {
43048
+ if (!pair) return {};
43049
+ const target = flatten(pair.target, null);
43050
+ return Object.fromEntries([
43051
+ ...Object.entries(target),
43052
+ ...Object.entries(target).map(([field, value]) => [`APP${appId}.${field}`, value]),
43053
+ ...Object.entries(pair.source).map(([field, value]) => [`${sourceAlias}.${field}`, value])
43054
+ ]);
43055
+ }
43056
+ function collectScalarNodeRefs(node, out) {
43057
+ if (node.type === "FIELD") {
43058
+ out.add(node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field);
43059
+ return;
43060
+ }
43061
+ if (node.type === "STRING_FUNC") {
43062
+ for (const arg of node.args) if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
43063
+ return;
43064
+ }
43065
+ if (node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP") {
43066
+ collectScalarNodeRefs(node.left, out);
43067
+ collectScalarNodeRefs(node.right, out);
42378
43068
  }
42379
43069
  }
42380
43070
  function formatAssignment(a) {
@@ -44998,7 +45688,7 @@ Options:
44998
45688
  -h, --help Show help
44999
45689
  `);
45000
45690
  }
45001
- var SERVER_VERSION = true ? "3.3.0" : "0.0.0-dev";
45691
+ var SERVER_VERSION = true ? "3.4.0" : "0.0.0-dev";
45002
45692
  function createServer(args) {
45003
45693
  const server = new McpServer({
45004
45694
  name: "ksql-mcp",