@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.
package/dist-cli/ksql.js CHANGED
@@ -307,6 +307,10 @@ var Lexer = class {
307
307
  this.pos += 2;
308
308
  return this.makeToken("<=" /* LTE */, "<=", start);
309
309
  }
310
+ if (ch === "|" && ch2 === "|") {
311
+ this.pos += 2;
312
+ return this.makeToken("||" /* CONCAT_OP */, "||", start);
313
+ }
310
314
  switch (ch) {
311
315
  case "=":
312
316
  this.pos++;
@@ -650,6 +654,8 @@ var Parser = class {
650
654
  constructor(tokens) {
651
655
  this.tokens = tokens;
652
656
  this.allowUnaryPlusNumber = false;
657
+ this.scalarAllowsAggregateArgs = true;
658
+ this.scalarAllowsCase = true;
653
659
  this.pos = 0;
654
660
  /** WITH 句で定義された CTE 名のセット(parseTableRef で参照) */
655
661
  this.cteNames = /* @__PURE__ */ new Set();
@@ -818,17 +824,19 @@ var Parser = class {
818
824
  }
819
825
  rejectNonScalarExpr(node, tok, context) {
820
826
  if (node.type === "STRING" || node.type === "NUMBER") return;
821
- if (node.type === "FIELD_REF" || node.type === "AGG_REF") {
827
+ if (node.type === "FIELD_REF" || node.type === "FIELD" || node.type === "VARIABLE" || node.type === "AGG_REF") {
822
828
  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);
823
829
  }
824
- if (node.type === "ARITH" || node.type === "AGG_ARITH") {
830
+ if (node.type === "ARITH" || node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP" || node.type === "AGG_ARITH") {
825
831
  this.rejectNonScalarExpr(node.left, tok, context);
826
832
  this.rejectNonScalarExpr(node.right, tok, context);
827
833
  return;
828
834
  }
829
835
  if (node.type === "STRING_FUNC") {
830
836
  for (const arg of node.args) this.rejectNonScalarExpr(arg, tok, context);
837
+ return;
831
838
  }
839
+ throw new ParseError(`${context} \u306E\u53F3\u8FBA\u3067\u306F CASE \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`, tok);
832
840
  }
833
841
  // ----------------------------------------------------------
834
842
  // CREATE TEMP TABLE / DROP TEMP TABLE(バッチ内一時テーブル)
@@ -1199,6 +1207,11 @@ var Parser = class {
1199
1207
  if (this.consume("*" /* STAR */)) {
1200
1208
  return { type: "WILDCARD" };
1201
1209
  }
1210
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
1211
+ const expr = this.parseScalarValueExpr({ allowAggregateArgs: true });
1212
+ const alias2 = this.consume("AS" /* AS */) ? this.parseAliasName() : null;
1213
+ return { type: "SCALAR_VALUE_COL", expr, alias: alias2 };
1214
+ }
1202
1215
  const windowFunc = this.tryWindowFunc();
1203
1216
  if (windowFunc !== null) {
1204
1217
  return this.parseWindowColumn(windowFunc);
@@ -1314,13 +1327,25 @@ var Parser = class {
1314
1327
  }
1315
1328
  selectColumnHasAggregate(column) {
1316
1329
  if (column.type === "AGGREGATE" || column.type === "ARITH_AGG_COL") return true;
1317
- if (column.type !== "STRFUNC_COL") return false;
1318
- return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
1330
+ if (column.type === "STRFUNC_COL") return column.expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
1331
+ if (column.type === "SCALAR_VALUE_COL") return this.scalarValueHasAggregate(column.expr);
1332
+ return false;
1319
1333
  }
1320
1334
  stringFuncArgHasAggregate(arg) {
1321
1335
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
1322
- if (arg.type === "STRING_FUNC") {
1323
- return arg.args.some((nested) => this.stringFuncArgHasAggregate(nested));
1336
+ return this.scalarValueHasAggregate(arg);
1337
+ }
1338
+ scalarValueHasAggregate(expr) {
1339
+ if (expr.type === "STRING_FUNC") return expr.args.some((arg) => this.stringFuncArgHasAggregate(arg));
1340
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
1341
+ return this.scalarValueHasAggregate(expr.left) || this.scalarValueHasAggregate(expr.right);
1342
+ }
1343
+ if (expr.type === "CASE_WHEN") {
1344
+ const results = [...expr.branches.map((b) => b.result), ...expr.elseResult ? [expr.elseResult] : []];
1345
+ return results.some((result) => {
1346
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
1347
+ return this.scalarValueHasAggregate(result);
1348
+ });
1324
1349
  }
1325
1350
  return false;
1326
1351
  }
@@ -1378,6 +1403,105 @@ var Parser = class {
1378
1403
  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());
1379
1404
  }
1380
1405
  // ──────────────────────────────────────────────────
1406
+ // 汎用スカラー値式パーサー(B38)
1407
+ // ──────────────────────────────────────────────────
1408
+ /** 比較・述語・集約・サブクエリを含まない値式の公開入口。 */
1409
+ parseScalarValueExpr(options = {}) {
1410
+ const previousAggregateArgs = this.scalarAllowsAggregateArgs;
1411
+ const previousCase = this.scalarAllowsCase;
1412
+ this.scalarAllowsAggregateArgs = options.allowAggregateArgs === true;
1413
+ this.scalarAllowsCase = options.allowCase !== false;
1414
+ let expr;
1415
+ try {
1416
+ expr = this.parseScalarAddSubConcat(this.scalarAllowsCase);
1417
+ } finally {
1418
+ this.scalarAllowsAggregateArgs = previousAggregateArgs;
1419
+ this.scalarAllowsCase = previousCase;
1420
+ }
1421
+ const next = this.peek();
1422
+ 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);
1423
+ return expr;
1424
+ }
1425
+ parseScalarAddSubConcat(allowCase) {
1426
+ let left = this.parseScalarMulDiv(allowCase);
1427
+ while (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */ || this.peek().kind === "||" /* CONCAT_OP */) {
1428
+ const token = this.advance();
1429
+ const right = this.parseScalarMulDiv(allowCase);
1430
+ left = token.kind === "||" /* CONCAT_OP */ ? { type: "CONCAT_OP", left, right } : { type: "SCALAR_ARITH", left, op: token.kind === "+" /* PLUS */ ? "+" : "-", right };
1431
+ }
1432
+ return left;
1433
+ }
1434
+ parseScalarMulDiv(allowCase) {
1435
+ let left = this.parseScalarPrimary(allowCase);
1436
+ while (this.peek().kind === "*" /* STAR */ || this.peek().kind === "/" /* SLASH */ || this.peek().kind === "%" /* PERCENT */) {
1437
+ const token = this.advance();
1438
+ const op = token.kind === "*" /* STAR */ ? "*" : token.kind === "/" /* SLASH */ ? "/" : "%";
1439
+ left = { type: "SCALAR_ARITH", left, op, right: this.parseScalarPrimary(allowCase) };
1440
+ }
1441
+ return left;
1442
+ }
1443
+ parseScalarPrimary(allowCase) {
1444
+ const tok = this.peek();
1445
+ if (tok.kind === "(" /* LPAREN */) {
1446
+ 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);
1447
+ this.advance();
1448
+ const expr = this.parseScalarAddSubConcat(allowCase);
1449
+ this.expect(")" /* RPAREN */);
1450
+ return expr;
1451
+ }
1452
+ if (tok.kind === "+" /* PLUS */ || tok.kind === "-" /* MINUS */) {
1453
+ this.advance();
1454
+ if (this.peek().kind === "+" /* PLUS */ || this.peek().kind === "-" /* MINUS */) {
1455
+ 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());
1456
+ }
1457
+ const operand = this.parseScalarPrimary(allowCase);
1458
+ if (operand.type === "NUMBER") {
1459
+ return makeNumberLiteral(`${tok.kind === "-" /* MINUS */ ? "-" : "+"}${numberLiteralText(operand)}`);
1460
+ }
1461
+ 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);
1462
+ return { type: "SCALAR_ARITH", left: makeNumberLiteral("0"), op: "-", right: operand };
1463
+ }
1464
+ if (tok.kind === "STRING" /* STRING */) {
1465
+ this.advance();
1466
+ return { type: "STRING", value: tok.value };
1467
+ }
1468
+ if (tok.kind === "NUMBER" /* NUMBER */) {
1469
+ this.advance();
1470
+ return makeNumberLiteral(tok.value);
1471
+ }
1472
+ if (tok.kind === "VARIABLE" /* VARIABLE */) {
1473
+ this.advance();
1474
+ return { type: "VARIABLE", name: tok.value.slice(1).toLowerCase() };
1475
+ }
1476
+ if (tok.kind === "CASE" /* CASE */) {
1477
+ 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);
1478
+ return this.parseCaseWhenExpr();
1479
+ }
1480
+ 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);
1481
+ if (this.tryStringFuncName() !== null) return this.parseStringFuncExpr();
1482
+ if (tok.kind === "IDENT" /* IDENT */ || tok.kind === "BIDENT" /* BIDENT */) {
1483
+ this.advance();
1484
+ if (this.consume("." /* DOT */)) return { type: "FIELD", tableAlias: tok.value, field: this.parseIdentifier() };
1485
+ return { type: "FIELD", tableAlias: null, field: tok.value };
1486
+ }
1487
+ throw new ParseError("\u30B9\u30AB\u30E9\u30FC\u5024\u5F0F\u306E\u30AA\u30DA\u30E9\u30F3\u30C9\u304C\u5FC5\u8981\u3067\u3059", tok);
1488
+ }
1489
+ /** 現在の値の終端までに指定トークンがあるか(括弧内も対象)。 */
1490
+ hasTopLevelTokenBeforeValueEnd(target) {
1491
+ let depth = 0;
1492
+ for (let i = this.pos; i < this.tokens.length; i++) {
1493
+ const kind = this.tokens[i].kind;
1494
+ if (kind === "(" /* LPAREN */ || kind === "[" /* LBRACKET */) depth++;
1495
+ else if (kind === ")" /* RPAREN */ || kind === "]" /* RBRACKET */) {
1496
+ if (depth === 0) break;
1497
+ depth--;
1498
+ }
1499
+ if (kind === target) return true;
1500
+ 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;
1501
+ }
1502
+ return false;
1503
+ }
1504
+ // ──────────────────────────────────────────────────
1381
1505
  // 算術式パーサー(演算子優先順位: * / > + -)
1382
1506
  //
1383
1507
  // parseArithAddSub : + -(左結合・低優先度)
@@ -1499,12 +1623,15 @@ var Parser = class {
1499
1623
  this.expect("END" /* END */);
1500
1624
  return { type: "CASE_WHEN", branches, elseResult };
1501
1625
  }
1502
- /** THEN / ELSE の結果値: 文字列リテラル / 配列リテラル / 文字列関数 / 算術式 */
1626
+ /** THEN / ELSE の結果値。`||` を含む場合だけ新スカラー文法へ渡す。 */
1503
1627
  parseCaseResult() {
1504
1628
  const tok = this.peek();
1505
1629
  if (tok.kind === "[" /* LBRACKET */) {
1506
1630
  return this.parseArrayLiteral();
1507
1631
  }
1632
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
1633
+ return this.parseScalarValueExpr({ allowAggregateArgs: true });
1634
+ }
1508
1635
  if (tok.kind === "STRING" /* STRING */) {
1509
1636
  this.advance();
1510
1637
  return { type: "STRING", value: tok.value };
@@ -1652,25 +1779,19 @@ var Parser = class {
1652
1779
  }
1653
1780
  return { type: "STRING", value: normalized };
1654
1781
  }
1655
- /** 文字列関数の引数: 文字列リテラル / ネスト文字列関数 / 算術式 / 集計算術式 */
1782
+ /** 文字列関数の引数: ScalarValueExpr / 集計算術式 */
1656
1783
  parseStringFuncArg() {
1657
- const tok = this.peek();
1658
- if (tok.kind === "STRING" /* STRING */) {
1659
- this.advance();
1660
- return { type: "STRING", value: tok.value };
1661
- }
1662
- if (this.tryStringFuncName() !== null) {
1663
- return this.parseStringFuncExpr();
1664
- }
1665
- const startPos = this.pos;
1666
- try {
1667
- const left = this.parseAggPrimary();
1668
- const expr = this.continueAggArith(left);
1669
- if (this.hasAggregateOperand(expr)) return expr;
1670
- } catch {
1784
+ if (this.scalarAllowsAggregateArgs) {
1785
+ const startPos = this.pos;
1786
+ try {
1787
+ const left = this.parseAggPrimary();
1788
+ const expr = this.continueAggArith(left);
1789
+ if (this.hasAggregateOperand(expr)) return expr;
1790
+ } catch {
1791
+ }
1792
+ this.pos = startPos;
1671
1793
  }
1672
- this.pos = startPos;
1673
- return this.parseArithAddSub();
1794
+ return this.parseScalarAddSubConcat(this.scalarAllowsCase);
1674
1795
  }
1675
1796
  hasAggregateOperand(node) {
1676
1797
  if (node.type === "AGG_REF") return true;
@@ -1758,6 +1879,7 @@ var Parser = class {
1758
1879
  const k = this.peek().kind;
1759
1880
  if (k === "IDENT" /* IDENT */ || k === "BIDENT" /* BIDENT */) {
1760
1881
  if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "VALIDATE" && this.peekAt(1).kind === "IDENT" /* IDENT */ && this.peekAt(1).value.toUpperCase() === "ONLY") return null;
1882
+ if (k === "IDENT" /* IDENT */ && this.peek().value.toUpperCase() === "CHECK" && this.peekAt(1).kind === "WHEN" /* WHEN */) return null;
1761
1883
  return this.parseTableAliasName();
1762
1884
  }
1763
1885
  return null;
@@ -2223,8 +2345,9 @@ var Parser = class {
2223
2345
  if (subtableCode) {
2224
2346
  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());
2225
2347
  }
2348
+ const checkGroups2 = this.parseCheckGroups();
2226
2349
  const validation2 = this.parseDmlControlSuffix();
2227
- return { type: "INSERT_SELECT", appId, fields, select, ...validation2 };
2350
+ return { type: "INSERT_SELECT", appId, fields, select, ...checkGroups2, ...validation2 };
2228
2351
  }
2229
2352
  this.expect("VALUES" /* VALUES */);
2230
2353
  const values = [];
@@ -2234,11 +2357,15 @@ var Parser = class {
2234
2357
  this.expect(")" /* RPAREN */);
2235
2358
  values.push(row);
2236
2359
  } while (this.consume("," /* COMMA */));
2360
+ const checkGroups = this.parseCheckGroups();
2237
2361
  const validation = this.parseDmlControlSuffix();
2362
+ if (subtableCode && checkGroups.checkGroups) {
2363
+ throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB INSERT \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
2364
+ }
2238
2365
  if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
2239
2366
  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());
2240
2367
  }
2241
- return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...validation } : { type: "INSERT", appId, fields, values, ...validation };
2368
+ return subtableCode ? { type: "INSERT", appId, subtableCode, fields, values, ...checkGroups, ...validation } : { type: "INSERT", appId, fields, values, ...checkGroups, ...validation };
2242
2369
  }
2243
2370
  parseUpsert() {
2244
2371
  this.expect("UPSERT" /* UPSERT */);
@@ -2255,8 +2382,9 @@ var Parser = class {
2255
2382
  if (this.peek().kind === "SELECT" /* SELECT */) {
2256
2383
  const select = this.parseSelect();
2257
2384
  const keyFields2 = this.parseOnDuplicate();
2385
+ const checkGroups2 = this.parseCheckGroups();
2258
2386
  const validation2 = this.parseDmlControlSuffix();
2259
- return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...validation2 };
2387
+ return { type: "UPSERT_SELECT", appId, fields, select, keyFields: keyFields2, ...checkGroups2, ...validation2 };
2260
2388
  }
2261
2389
  this.expect("VALUES" /* VALUES */);
2262
2390
  const values = [];
@@ -2266,8 +2394,9 @@ var Parser = class {
2266
2394
  this.expect(")" /* RPAREN */);
2267
2395
  } while (this.consume("," /* COMMA */));
2268
2396
  const keyFields = this.parseOnDuplicate();
2397
+ const checkGroups = this.parseCheckGroups();
2269
2398
  const validation = this.parseDmlControlSuffix();
2270
- return { type: "UPSERT", appId, fields, values, keyFields, ...validation };
2399
+ return { type: "UPSERT", appId, fields, values, keyFields, ...checkGroups, ...validation };
2271
2400
  }
2272
2401
  parseOnDuplicate() {
2273
2402
  this.expectKeyword("ON" /* ON */, "UPSERT \u306B\u306F ON DUPLICATE (\u30AD\u30FC\u30D5\u30A3\u30FC\u30EB\u30C9) \u304C\u5FC5\u8981\u3067\u3059");
@@ -2399,12 +2528,33 @@ var Parser = class {
2399
2528
  whereTok
2400
2529
  );
2401
2530
  }
2531
+ const checkGroups = this.parseCheckGroups();
2402
2532
  const validation = this.parseDmlControlSuffix();
2533
+ if (subtableCode && checkGroups.checkGroups) {
2534
+ throw new ParseError("CHECK \u306F\u30B5\u30D6\u30C6\u30FC\u30D6\u30EB UPDATE \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093", this.prev());
2535
+ }
2403
2536
  if (subtableCode && (validation.validateOnly || validation.onErrorSkip)) {
2404
2537
  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());
2405
2538
  }
2406
- if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...validation };
2407
- return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...validation } : { type: "UPDATE", appId, assignments, where, ...validation };
2539
+ if (from !== null) return { type: "UPDATE", appId, assignments, where, from, ...checkGroups, ...validation };
2540
+ return subtableCode ? { type: "UPDATE", appId, subtableCode, assignments, where, ...checkGroups, ...validation } : { type: "UPDATE", appId, assignments, where, ...checkGroups, ...validation };
2541
+ }
2542
+ /** CHECK WHEN ... THEN ... blocks. CHECK is a soft keyword. */
2543
+ parseCheckGroups() {
2544
+ const groups = [];
2545
+ while (this.isSoftKeyword("CHECK") && this.peekAt(1).kind === "WHEN" /* WHEN */) {
2546
+ const check = this.advance();
2547
+ const rules = [];
2548
+ while (this.consume("WHEN" /* WHEN */)) {
2549
+ const condition = this.parseWhereExpr();
2550
+ this.expect("THEN" /* THEN */, "CHECK WHEN \u306E\u6761\u4EF6\u306E\u5F8C\u306B\u306F THEN \u304C\u5FC5\u8981\u3067\u3059");
2551
+ const message = this.parseScalarValueExpr({ allowCase: false });
2552
+ rules.push({ condition, message });
2553
+ }
2554
+ if (rules.length === 0) throw new ParseError("CHECK \u306E\u5F8C\u306B\u306F WHEN \u304C\u6700\u4F4E 1 \u3064\u5FC5\u8981\u3067\u3059", check);
2555
+ groups.push({ rules });
2556
+ }
2557
+ return groups.length > 0 ? { checkGroups: groups } : {};
2408
2558
  }
2409
2559
  /** DML末尾の VALIDATE ONLY または ON ERROR SKIP。各語はsoft keyword。 */
2410
2560
  parseDmlControlSuffix() {
@@ -2593,6 +2743,12 @@ var Parser = class {
2593
2743
  */
2594
2744
  parseAssignmentValue() {
2595
2745
  const tok = this.peek();
2746
+ if (this.hasTopLevelTokenBeforeValueEnd("||" /* CONCAT_OP */)) {
2747
+ const expr = this.parseScalarValueExpr();
2748
+ if (expr.type === "CONCAT_OP" || expr.type === "SCALAR_ARITH" || expr.type === "STRING_FUNC") return expr;
2749
+ if (expr.type === "CASE_WHEN") return { type: "CASE_VALUE", expr };
2750
+ 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);
2751
+ }
2596
2752
  if (tok.kind === "VARIABLE" /* VARIABLE */) return this.parseSqlValue();
2597
2753
  if (tok.kind === "STRING" /* STRING */) return this.parseSqlValue();
2598
2754
  if (tok.kind === "TODAY" /* TODAY */ || tok.kind === "NOW" /* NOW */ || tok.kind === "LOGINUSER" /* LOGINUSER */) return this.parseSqlValue();
@@ -3216,7 +3372,7 @@ function resolveSelectMode(stmt) {
3216
3372
  if (stmt.distinct) return "FULL_SCAN";
3217
3373
  if (hasWindowColumns(stmt.columns)) return "FULL_SCAN";
3218
3374
  if (stmt.columns.some(
3219
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "SCALAR_SUBQUERY_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr(c.expr)
3375
+ (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)
3220
3376
  )) return "FULL_SCAN";
3221
3377
  if (whereRequiresJsEval(stmt.where)) return "FULL_SCAN";
3222
3378
  if (stmt.orderBy.some((o) => o.key.type !== "FIELD_NAME")) return "FULL_SCAN";
@@ -3311,6 +3467,8 @@ function extractFields(columns) {
3311
3467
  collectArithNode(col.expr, fields);
3312
3468
  } else if (col.type === "STRFUNC_COL") {
3313
3469
  collectStringFuncFields(col.expr, fields);
3470
+ } else if (col.type === "SCALAR_VALUE_COL") {
3471
+ collectScalarValueFields(col.expr, fields);
3314
3472
  }
3315
3473
  }
3316
3474
  return [...new Set(fields)];
@@ -3336,16 +3494,38 @@ function collectStringFuncFields(expr, out) {
3336
3494
  }
3337
3495
  }
3338
3496
  function collectStringFuncArgFields(arg, out) {
3339
- if (arg.type === "STRING") return;
3340
- if (arg.type === "STRING_FUNC") {
3341
- collectStringFuncFields(arg, out);
3342
- return;
3343
- }
3344
3497
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
3345
3498
  collectAggOperandFields(arg, out);
3346
3499
  return;
3347
3500
  }
3348
- collectArithNode(arg, out);
3501
+ collectScalarValueFields(arg, out);
3502
+ }
3503
+ function collectScalarValueFields(expr, out) {
3504
+ if (expr.type === "FIELD") {
3505
+ out.push(normalizeSimpleFieldRef(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field));
3506
+ return;
3507
+ }
3508
+ if (expr.type === "STRING_FUNC") {
3509
+ collectStringFuncFields(expr, out);
3510
+ return;
3511
+ }
3512
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
3513
+ collectScalarValueFields(expr.left, out);
3514
+ collectScalarValueFields(expr.right, out);
3515
+ return;
3516
+ }
3517
+ if (expr.type === "CASE_WHEN") {
3518
+ for (const branch of expr.branches) collectCaseResultScalarFields(branch.result, out);
3519
+ if (expr.elseResult) collectCaseResultScalarFields(expr.elseResult, out);
3520
+ }
3521
+ }
3522
+ function collectCaseResultScalarFields(result, out) {
3523
+ if (result.type === "ARRAY") return;
3524
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
3525
+ collectArithNode(result, out);
3526
+ return;
3527
+ }
3528
+ collectScalarValueFields(result, out);
3349
3529
  }
3350
3530
  function collectAggOperandFields(node, out) {
3351
3531
  if (node.type === "AGG_REF") {
@@ -3360,10 +3540,23 @@ function collectAggOperandFields(node, out) {
3360
3540
  function hasAggregateInStringFuncExpr(expr) {
3361
3541
  return expr.args.some((arg) => {
3362
3542
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
3363
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(arg);
3364
- return false;
3543
+ return scalarValueHasAggregate(arg);
3365
3544
  });
3366
3545
  }
3546
+ function scalarValueHasAggregate(expr) {
3547
+ if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr(expr);
3548
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
3549
+ return scalarValueHasAggregate(expr.left) || scalarValueHasAggregate(expr.right);
3550
+ }
3551
+ if (expr.type === "CASE_WHEN") {
3552
+ return expr.branches.some((b) => caseResultHasAggregate(b.result)) || expr.elseResult !== null && caseResultHasAggregate(expr.elseResult);
3553
+ }
3554
+ return false;
3555
+ }
3556
+ function caseResultHasAggregate(result) {
3557
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
3558
+ return scalarValueHasAggregate(result);
3559
+ }
3367
3560
  function collectRequiredFieldsByTable(stmt) {
3368
3561
  const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
3369
3562
  const states = /* @__PURE__ */ new Map();
@@ -3498,28 +3691,38 @@ function collectRequiredFieldsByTable(stmt) {
3498
3691
  }
3499
3692
  };
3500
3693
  const walkStringArg = (arg, phase = "select") => {
3501
- if (arg.type === "STRING") return;
3502
- if (arg.type === "STRING_FUNC") {
3503
- walkStringFunc(arg, phase);
3504
- return;
3505
- }
3506
3694
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
3507
3695
  walkAgg(arg, phase);
3508
3696
  return;
3509
3697
  }
3510
- walkArith(arg, phase);
3698
+ walkScalar(arg, phase);
3511
3699
  };
3512
3700
  const walkStringFunc = (expr, phase = "select") => {
3513
3701
  for (const arg of expr.args) walkStringArg(arg, phase);
3514
3702
  };
3703
+ const walkScalar = (expr, phase = "select") => {
3704
+ if (expr.type === "FIELD") {
3705
+ addFieldRef(expr.field, expr.tableAlias, phase);
3706
+ return;
3707
+ }
3708
+ if (expr.type === "STRING_FUNC") {
3709
+ walkStringFunc(expr, phase);
3710
+ return;
3711
+ }
3712
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
3713
+ walkScalar(expr.left, phase);
3714
+ walkScalar(expr.right, phase);
3715
+ return;
3716
+ }
3717
+ if (expr.type === "CASE_WHEN") walkCase(expr, phase);
3718
+ };
3515
3719
  const walkCaseResult = (result, phase = "select") => {
3516
- if (result.type === "STRING") return;
3517
3720
  if (result.type === "ARRAY") return;
3518
- if (result.type === "STRING_FUNC") {
3519
- walkStringFunc(result, phase);
3721
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
3722
+ walkArith(result, phase);
3520
3723
  return;
3521
3724
  }
3522
- walkArith(result, phase);
3725
+ walkScalar(result, phase);
3523
3726
  };
3524
3727
  const walkCase = (expr, phase = "select") => {
3525
3728
  for (const b of expr.branches) {
@@ -3625,6 +3828,9 @@ function collectRequiredFieldsByTable(stmt) {
3625
3828
  case "STRFUNC_COL":
3626
3829
  walkStringFunc(col.expr, "select");
3627
3830
  break;
3831
+ case "SCALAR_VALUE_COL":
3832
+ walkScalar(col.expr, "select");
3833
+ break;
3628
3834
  case "SCALAR_SUBQUERY_COL":
3629
3835
  break;
3630
3836
  case "WINDOW_COL":
@@ -3675,6 +3881,10 @@ function collectSelectOutputNames(columns) {
3675
3881
  if (col.alias) names.add(col.alias);
3676
3882
  continue;
3677
3883
  }
3884
+ if (col.type === "SCALAR_VALUE_COL") {
3885
+ if (col.alias) names.add(col.alias);
3886
+ continue;
3887
+ }
3678
3888
  if (col.type === "SCALAR_SUBQUERY_COL") {
3679
3889
  names.add(col.alias ?? "(subquery)");
3680
3890
  continue;
@@ -3697,14 +3907,32 @@ function arithNodeLabel(node) {
3697
3907
  }
3698
3908
  function stringFuncLabel(expr) {
3699
3909
  const args = expr.args.map((a) => {
3700
- if (a.type === "STRING") return `'${a.value}'`;
3701
- if (a.type === "STRING_FUNC") return stringFuncLabel(a);
3702
3910
  if (a.type === "AGG_REF") return aggregateSyntheticName(a.func, a.distinct, a.arg);
3703
3911
  if (a.type === "AGG_ARITH") return "agg_arith";
3704
- return arithNodeLabel(a);
3912
+ return scalarValueLabel(a);
3705
3913
  });
3706
3914
  return `${expr.func}(${args.join(",")})`;
3707
3915
  }
3916
+ function scalarValueLabel(expr) {
3917
+ switch (expr.type) {
3918
+ case "STRING":
3919
+ return `'${expr.value}'`;
3920
+ case "NUMBER":
3921
+ return numberLiteralText(expr);
3922
+ case "VARIABLE":
3923
+ return `@${expr.name}`;
3924
+ case "FIELD":
3925
+ return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
3926
+ case "STRING_FUNC":
3927
+ return stringFuncLabel(expr);
3928
+ case "CASE_WHEN":
3929
+ return "case";
3930
+ case "SCALAR_ARITH":
3931
+ return `(${scalarValueLabel(expr.left)}${expr.op}${scalarValueLabel(expr.right)})`;
3932
+ case "CONCAT_OP":
3933
+ return `(${scalarValueLabel(expr.left)}||${scalarValueLabel(expr.right)})`;
3934
+ }
3935
+ }
3708
3936
  function isAggregateSyntheticName(name) {
3709
3937
  return /^(COUNT|SUM|AVG|MAX|MIN|GROUP_CONCAT)\(/i.test(name);
3710
3938
  }
@@ -4647,6 +4875,45 @@ function evalArithExpr(expr, row) {
4647
4875
  return r !== 0 ? l % r : NaN;
4648
4876
  }
4649
4877
  }
4878
+ function evalScalarValueExpr(expr, row) {
4879
+ switch (expr.type) {
4880
+ case "STRING":
4881
+ return expr.value;
4882
+ case "NUMBER":
4883
+ return expr.value;
4884
+ case "FIELD":
4885
+ return resolveFieldRef(row, expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
4886
+ case "VARIABLE":
4887
+ throw new Error(`ArgumentError: unresolved variable @${expr.name} reached scalar evaluator.`);
4888
+ case "STRING_FUNC":
4889
+ return evalStringFunc(expr, row);
4890
+ case "CASE_WHEN":
4891
+ return evalCaseWhen(expr, row);
4892
+ case "CONCAT_OP": {
4893
+ return evalStringFunc({
4894
+ type: "STRING_FUNC",
4895
+ func: "CONCAT",
4896
+ args: [expr.left, expr.right]
4897
+ }, row);
4898
+ }
4899
+ case "SCALAR_ARITH": {
4900
+ const left = Number(evalScalarValueExpr(expr.left, row));
4901
+ const right = Number(evalScalarValueExpr(expr.right, row));
4902
+ switch (expr.op) {
4903
+ case "+":
4904
+ return left + right;
4905
+ case "-":
4906
+ return left - right;
4907
+ case "*":
4908
+ return left * right;
4909
+ case "/":
4910
+ return right !== 0 ? left / right : NaN;
4911
+ case "%":
4912
+ return right !== 0 ? left % right : NaN;
4913
+ }
4914
+ }
4915
+ }
4916
+ }
4650
4917
  function applyRoundOp(op, num, digits) {
4651
4918
  const factor = Math.pow(10, digits);
4652
4919
  const raw = Math[op](num * factor) / factor;
@@ -5049,12 +5316,9 @@ function formatWithComma(num, digits) {
5049
5316
  return decStr ? `${intFmt}.${decStr}` : intFmt;
5050
5317
  }
5051
5318
  function evalStringFuncArg(arg, row) {
5052
- if (arg.type === "STRING") return arg.value;
5053
- if (arg.type === "STRING_FUNC") return evalStringFunc(arg, row);
5054
- if (arg.type === "FIELD_REF") return resolveFieldRef(row, arg.field);
5055
- if (arg.type === "NUMBER") return numberLiteralText(arg);
5056
5319
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return "";
5057
- return String(evalArithExpr(arg, row));
5320
+ if (arg.type === "NUMBER") return numberLiteralText(arg);
5321
+ return String(evalScalarValueExpr(arg, row));
5058
5322
  }
5059
5323
  function resolveFieldRef(row, field) {
5060
5324
  const direct = row[field];
@@ -5277,10 +5541,13 @@ function evalCaseWhen(expr, row, resolveFieldType, resolveFieldSemantics2) {
5277
5541
  }
5278
5542
  function evalCaseResult(result, row) {
5279
5543
  if (result.type === "ARRAY") return result.elements.map((e) => e.value).join(",");
5280
- if (result.type === "STRING") return result.value;
5281
- if (result.type === "STRING_FUNC") return evalStringFunc(result, row);
5282
- if (result.type === "FIELD_REF") return row[result.field] ?? "";
5283
- return String(evalArithExpr(result, row));
5544
+ if (result.type === "FIELD_REF") {
5545
+ return row[result.field] ?? "";
5546
+ }
5547
+ if (result.type === "ARITH") {
5548
+ return String(evalArithExpr(result, row));
5549
+ }
5550
+ return String(evalScalarValueExpr(result, row));
5284
5551
  }
5285
5552
  function resolveKintoneFunc(name) {
5286
5553
  const now = /* @__PURE__ */ new Date();
@@ -5324,6 +5591,63 @@ function matchLike(value, pattern) {
5324
5591
  return regex.test(value);
5325
5592
  }
5326
5593
 
5594
+ // src/core/dmlCustomCheck.ts
5595
+ function collectCheckFieldRefs(groups) {
5596
+ return collectRefs2(groups);
5597
+ }
5598
+ function collectCheckComparisonFieldRefs(groups) {
5599
+ return collectRefs2(groups.flatMap((group) => group.rules.map((rule) => rule.condition)));
5600
+ }
5601
+ function collectRefs2(root) {
5602
+ const refs = [];
5603
+ const seen = /* @__PURE__ */ new Set();
5604
+ const visit = (node) => {
5605
+ if (Array.isArray(node)) {
5606
+ node.forEach(visit);
5607
+ return;
5608
+ }
5609
+ if (node === null || typeof node !== "object") return;
5610
+ const obj = node;
5611
+ if (obj.type === "EXISTS" || obj.type === "SUBQUERY_IN_LIST" || obj.type === "SCALAR_SUBQUERY") {
5612
+ throw customCheckParseError("CHECK \u306B\u30B5\u30D6\u30AF\u30A8\u30EA\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
5613
+ }
5614
+ if (obj.type === "FIELD" && typeof obj.field === "string") {
5615
+ add(typeof obj.tableAlias === "string" ? obj.tableAlias : null, obj.field);
5616
+ } else if (obj.type === "FIELD_REF" && typeof obj.field === "string") {
5617
+ const dot = obj.field.indexOf(".");
5618
+ add(dot > 0 ? obj.field.slice(0, dot) : null, dot > 0 ? obj.field.slice(dot + 1) : obj.field);
5619
+ }
5620
+ for (const value of Object.values(obj)) visit(value);
5621
+ };
5622
+ const add = (tableAlias, field) => {
5623
+ if (/^(COUNT|SUM|AVG|MIN|MAX|GROUP_CONCAT)\(/i.test(field)) {
5624
+ throw customCheckParseError("CHECK \u306B\u96C6\u7D04\u95A2\u6570\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
5625
+ }
5626
+ const key = `${tableAlias ?? ""}\0${field}`;
5627
+ if (!seen.has(key)) {
5628
+ seen.add(key);
5629
+ refs.push({ tableAlias, field });
5630
+ }
5631
+ };
5632
+ visit(root);
5633
+ return refs;
5634
+ }
5635
+ function customCheckParseError(message) {
5636
+ return new ParseError(message, { kind: "EOF" /* EOF */, value: "CHECK", pos: 0 });
5637
+ }
5638
+ function evaluateCustomChecks(groups, row, resolveFieldType) {
5639
+ const errors = [];
5640
+ groups.forEach((group, groupIndex) => {
5641
+ for (const rule of group.rules) {
5642
+ if (!evalWhere(rule.condition, row, resolveFieldType)) continue;
5643
+ const value = evalScalarValueExpr(rule.message, row);
5644
+ errors.push({ groupIndex, message: value == null ? "" : String(value) });
5645
+ break;
5646
+ }
5647
+ });
5648
+ return errors;
5649
+ }
5650
+
5327
5651
  // src/converter/dmlToKintone.ts
5328
5652
  function assertDmlWhereIsSafe(where) {
5329
5653
  if (whereHasKlike(where)) {
@@ -5361,10 +5685,11 @@ function buildInsertRecord(fields, row, fieldTypes) {
5361
5685
  }
5362
5686
  function updateToGetQuery(stmt) {
5363
5687
  assertDmlWhereIsSafe(stmt.where);
5688
+ const checkFields = collectUpdateCheckTargetFields(stmt);
5364
5689
  return {
5365
5690
  app: stmt.appId,
5366
5691
  query: whereToKintone(stmt.where),
5367
- fields: ["$id"],
5692
+ fields: ["$id", ...checkFields],
5368
5693
  totalCount: false
5369
5694
  };
5370
5695
  }
@@ -5378,19 +5703,19 @@ function updateToPutBatches(stmt, ids, fieldTypes = /* @__PURE__ */ new Map()) {
5378
5703
  function buildUpdateRecord(assignments, fieldTypes) {
5379
5704
  const record = {};
5380
5705
  for (const { field, value } of assignments) {
5381
- if (value.type === "ARITH" || value.type === "CASE_VALUE" || value.type === "STRING_FUNC" || value.type === "SOURCE_FIELD") continue;
5706
+ 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;
5382
5707
  record[field] = { value: toKintoneValue(value, fieldTypes.get(field)) };
5383
5708
  }
5384
5709
  return record;
5385
5710
  }
5386
5711
  function hasArithAssignment(stmt) {
5387
5712
  return stmt.assignments.some(
5388
- (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE"
5713
+ (a) => a.value.type === "ARITH" || a.value.type === "SCALAR_ARITH" || a.value.type === "CONCAT_OP" || a.value.type === "CASE_VALUE"
5389
5714
  );
5390
5715
  }
5391
5716
  function hasRowDependentAssignment(stmt) {
5392
5717
  return stmt.assignments.some(
5393
- (a) => a.value.type === "ARITH" || a.value.type === "CASE_VALUE" || a.value.type === "STRING_FUNC"
5718
+ (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"
5394
5719
  );
5395
5720
  }
5396
5721
  function updateToGetQueryForArith(stmt) {
@@ -5399,12 +5724,15 @@ function updateToGetQueryForArith(stmt) {
5399
5724
  for (const { value } of stmt.assignments) {
5400
5725
  if (value.type === "ARITH") {
5401
5726
  collectArithFields2(value, refFields);
5727
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
5728
+ collectScalarValueFields2(value, refFields);
5402
5729
  } else if (value.type === "STRING_FUNC") {
5403
5730
  collectStringFuncFields2(value, refFields);
5404
5731
  } else if (value.type === "CASE_VALUE") {
5405
5732
  collectCaseFields(value.expr, refFields);
5406
5733
  }
5407
5734
  }
5735
+ collectUpdateCheckTargetFields(stmt).forEach((field) => refFields.add(field));
5408
5736
  return {
5409
5737
  app: stmt.appId,
5410
5738
  query: whereToKintone(stmt.where),
@@ -5425,16 +5753,27 @@ function collectStringFuncFields2(expr, out) {
5425
5753
  for (const arg of expr.args) collectStringFuncArgFields2(arg, out);
5426
5754
  }
5427
5755
  function collectStringFuncArgFields2(arg, out) {
5428
- if (arg.type === "STRING") return;
5429
- if (arg.type === "STRING_FUNC") {
5430
- collectStringFuncFields2(arg, out);
5431
- return;
5432
- }
5433
5756
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
5434
5757
  collectAggOperandFields2(arg, out);
5435
5758
  return;
5436
5759
  }
5437
- collectArithNode2(arg, out);
5760
+ collectScalarValueFields2(arg, out);
5761
+ }
5762
+ function collectScalarValueFields2(expr, out) {
5763
+ if (expr.type === "FIELD") {
5764
+ out.add(expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field);
5765
+ return;
5766
+ }
5767
+ if (expr.type === "STRING_FUNC") {
5768
+ collectStringFuncFields2(expr, out);
5769
+ return;
5770
+ }
5771
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
5772
+ collectScalarValueFields2(expr.left, out);
5773
+ collectScalarValueFields2(expr.right, out);
5774
+ return;
5775
+ }
5776
+ if (expr.type === "CASE_WHEN") collectCaseFields(expr, out);
5438
5777
  }
5439
5778
  function collectAggOperandFields2(node, out) {
5440
5779
  if (node.type === "AGG_REF") {
@@ -5447,9 +5786,12 @@ function collectAggOperandFields2(node, out) {
5447
5786
  }
5448
5787
  }
5449
5788
  function collectCaseResultFields(result, out) {
5450
- if (result.type === "STRING") return;
5451
5789
  if (result.type === "ARRAY") return;
5452
- collectArithNode2(result, out);
5790
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
5791
+ collectArithNode2(result, out);
5792
+ return;
5793
+ }
5794
+ collectScalarValueFields2(result, out);
5453
5795
  }
5454
5796
  function collectCaseFields(expr, out) {
5455
5797
  for (const branch of expr.branches) {
@@ -5487,6 +5829,8 @@ function updateToPutBatchesArith(stmt, records, fieldTypes = /* @__PURE__ */ new
5487
5829
  for (const { field, value } of stmt.assignments) {
5488
5830
  if (value.type === "ARITH") {
5489
5831
  record[field] = { value: String(evalArith(value, raw)) };
5832
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
5833
+ record[field] = { value: String(evalScalarValueExpr(value, row)) };
5490
5834
  } else if (value.type === "STRING_FUNC") {
5491
5835
  record[field] = { value: evalStringFunc(value, row) };
5492
5836
  } else if (value.type === "CASE_VALUE") {
@@ -5541,6 +5885,8 @@ function updateFromToPutBatches(stmt, matched, fieldTypes = /* @__PURE__ */ new
5541
5885
  throw new DmlConvertError("UPDATE ... FROM \u306E SET \u3067\u306F\u6587\u5B57\u5217\u95A2\u6570\u3092\u76F4\u63A5\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
5542
5886
  } else if (value.type === "ARITH") {
5543
5887
  record[field] = { value: String(evalArith(value, target)) };
5888
+ } else if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") {
5889
+ record[field] = { value: String(evalScalarValueExpr(value, targetRow)) };
5544
5890
  } else if (value.type === "CASE_VALUE") {
5545
5891
  record[field] = { value: evalCaseWhenValue(value.expr, targetRow, fieldType) };
5546
5892
  } else {
@@ -5651,7 +5997,15 @@ function evalCaseResultValue(result, row, fieldType) {
5651
5997
  if (result.type === "STRING_FUNC") {
5652
5998
  return evalStringFunc(result, row);
5653
5999
  }
5654
- return String(evalArithExpr(result, row));
6000
+ if (result.type === "FIELD_REF" || result.type === "ARITH") {
6001
+ return String(evalArithExpr(result, row));
6002
+ }
6003
+ return String(evalScalarValueExpr(result, row));
6004
+ }
6005
+ function collectUpdateCheckTargetFields(stmt) {
6006
+ if (!stmt.checkGroups) return [];
6007
+ const targetAlias = `app${stmt.appId}`.toLowerCase();
6008
+ return [...new Set(collectCheckFieldRefs(stmt.checkGroups).filter((ref) => ref.tableAlias === null || ref.tableAlias.toLowerCase() === targetAlias).map((ref) => ref.field).filter((field) => field !== "$id"))];
5655
6009
  }
5656
6010
  function evalCaseWhenValue(expr, row, fieldType) {
5657
6011
  for (const branch of expr.branches) {
@@ -6204,7 +6558,7 @@ function applyFilter(rows, where, resolveFieldType, appliedKlikes, resolveFieldS
6204
6558
  }
6205
6559
  function hasAggregateColumns(columns) {
6206
6560
  return columns.some(
6207
- (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr)
6561
+ (c) => c.type === "AGGREGATE" || c.type === "ARITH_AGG_COL" || c.type === "STRFUNC_COL" && hasAggregateInStringFuncExpr2(c.expr) || c.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(c.expr)
6208
6562
  );
6209
6563
  }
6210
6564
  function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
@@ -6241,6 +6595,10 @@ function applyGroupBy(rows, groupByKeys, columns, resolveAggSortKind) {
6241
6595
  const outputKey = col.alias ?? stringFuncDefaultKey(col.expr);
6242
6596
  const resolvedExpr = resolveAggInStringFuncExpr(col.expr, groupRows, resolveAggSortKind);
6243
6597
  outRow[outputKey] = evalStringFunc(resolvedExpr, outRow);
6598
+ } else if (col.type === "SCALAR_VALUE_COL" && scalarValueHasAggregate2(col.expr)) {
6599
+ const outputKey = col.alias ?? scalarValueDefaultKey(col.expr);
6600
+ const resolvedExpr = resolveAggInScalarValue(col.expr, groupRows, resolveAggSortKind);
6601
+ outRow[outputKey] = String(evalScalarValueExpr(resolvedExpr, outRow));
6244
6602
  }
6245
6603
  }
6246
6604
  result.push(outRow);
@@ -6571,6 +6929,13 @@ function project(rows, columns, scalarCache, resolveFieldType, sourceColumns, re
6571
6929
  if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
6572
6930
  break;
6573
6931
  }
6932
+ case "SCALAR_VALUE_COL": {
6933
+ const key = outputKeys?.[colIdx] ?? col.alias ?? scalarValueDefaultKey(col.expr);
6934
+ const srcKey = scalarValueDefaultKey(col.expr);
6935
+ out[key] = scalarValueHasAggregate2(col.expr) ? row[col.alias ?? srcKey] ?? row[srcKey] ?? "" : String(evalScalarValueExpr(col.expr, row));
6936
+ if (outputKeys === null && rowIdx === 0) orderedKeys.push(key);
6937
+ break;
6938
+ }
6574
6939
  case "SCALAR_SUBQUERY_COL": {
6575
6940
  const key = outputKeys?.[colIdx] ?? col.alias ?? "(subquery)";
6576
6941
  out[key] = scalarCache?.get(colIdx) ?? "";
@@ -6621,6 +6986,8 @@ function computeOutputKey(col, colIdx, defaultFieldKeys) {
6621
6986
  return col.alias ?? "case";
6622
6987
  case "STRFUNC_COL":
6623
6988
  return col.alias ?? stringFuncDefaultKey(col.expr);
6989
+ case "SCALAR_VALUE_COL":
6990
+ return col.alias ?? scalarValueDefaultKey(col.expr);
6624
6991
  case "SCALAR_SUBQUERY_COL":
6625
6992
  return col.alias ?? "(subquery)";
6626
6993
  case "WINDOW_COL":
@@ -6676,18 +7043,49 @@ function arithColDefaultKey(expr) {
6676
7043
  }
6677
7044
  function stringFuncDefaultKey(expr) {
6678
7045
  const argStrs = expr.args.map((a) => {
6679
- if (a.type === "STRING") return `'${a.value}'`;
6680
- if (a.type === "STRING_FUNC") return stringFuncDefaultKey(a);
6681
7046
  if (a.type === "AGG_REF" || a.type === "AGG_ARITH") return aggArithDefaultKey(a);
6682
- return arithColDefaultKey(a);
7047
+ return scalarValueDefaultKey(a);
6683
7048
  });
6684
7049
  return `${expr.func}(${argStrs.join(",")})`;
6685
7050
  }
7051
+ function scalarValueDefaultKey(expr) {
7052
+ switch (expr.type) {
7053
+ case "STRING":
7054
+ return `'${expr.value}'`;
7055
+ case "NUMBER":
7056
+ return numberLiteralText(expr);
7057
+ case "VARIABLE":
7058
+ return `@${expr.name}`;
7059
+ case "FIELD":
7060
+ return expr.tableAlias ? `${expr.tableAlias}.${expr.field}` : expr.field;
7061
+ case "STRING_FUNC":
7062
+ return stringFuncDefaultKey(expr);
7063
+ case "CASE_WHEN":
7064
+ return "case";
7065
+ case "SCALAR_ARITH":
7066
+ return `${scalarValueDefaultKey(expr.left)}${expr.op}${scalarValueDefaultKey(expr.right)}`;
7067
+ case "CONCAT_OP":
7068
+ return `${scalarValueDefaultKey(expr.left)}||${scalarValueDefaultKey(expr.right)}`;
7069
+ }
7070
+ }
6686
7071
  function hasAggregateInStringFuncArg(arg) {
6687
7072
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
6688
- if (arg.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(arg);
7073
+ return scalarValueHasAggregate2(arg);
7074
+ }
7075
+ function scalarValueHasAggregate2(expr) {
7076
+ if (expr.type === "STRING_FUNC") return hasAggregateInStringFuncExpr2(expr);
7077
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
7078
+ return scalarValueHasAggregate2(expr.left) || scalarValueHasAggregate2(expr.right);
7079
+ }
7080
+ if (expr.type === "CASE_WHEN") {
7081
+ return expr.branches.some((branch) => caseResultHasAggregate2(branch.result)) || expr.elseResult !== null && caseResultHasAggregate2(expr.elseResult);
7082
+ }
6689
7083
  return false;
6690
7084
  }
7085
+ function caseResultHasAggregate2(result) {
7086
+ if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
7087
+ return scalarValueHasAggregate2(result);
7088
+ }
6691
7089
  function hasAggregateInStringFuncExpr2(expr) {
6692
7090
  return expr.args.some((arg) => hasAggregateInStringFuncArg(arg));
6693
7091
  }
@@ -6703,7 +7101,18 @@ function resolveAggInStringFuncArg(arg, rows, resolveAggSortKind) {
6703
7101
  if (arg.type === "STRING_FUNC") {
6704
7102
  return resolveAggInStringFuncExpr(arg, rows, resolveAggSortKind);
6705
7103
  }
6706
- return arg;
7104
+ return resolveAggInScalarValue(arg, rows, resolveAggSortKind);
7105
+ }
7106
+ function resolveAggInScalarValue(expr, rows, resolveAggSortKind) {
7107
+ if (expr.type === "STRING_FUNC") return resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind);
7108
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
7109
+ return {
7110
+ ...expr,
7111
+ left: resolveAggInScalarValue(expr.left, rows, resolveAggSortKind),
7112
+ right: resolveAggInScalarValue(expr.right, rows, resolveAggSortKind)
7113
+ };
7114
+ }
7115
+ return expr;
6707
7116
  }
6708
7117
  function resolveAggInStringFuncExpr(expr, rows, resolveAggSortKind) {
6709
7118
  return {
@@ -6724,7 +7133,7 @@ function deriveOutputOrderSemantics(columns) {
6724
7133
  } else if (column.func === "GROUP_CONCAT") {
6725
7134
  result.set(column.alias, syntheticSemantics("string"));
6726
7135
  }
6727
- } else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL") {
7136
+ } else if (column.type === "LITERAL_COL" || column.type === "CASE_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "SCALAR_VALUE_COL") {
6728
7137
  result.set(column.alias, syntheticSemantics("string"));
6729
7138
  } else if (column.type === "STRFUNC_COL") {
6730
7139
  result.set(column.alias, syntheticSemantics(NUMERIC_ORDER_FUNCTIONS.has(column.expr.func) ? "number" : "string"));
@@ -6997,19 +7406,20 @@ var VALIDATION_META_COLUMNS = [
6997
7406
  "$err_code",
6998
7407
  "$err_message"
6999
7408
  ];
7000
- function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision) {
7409
+ function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true) {
7001
7410
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
7002
7411
  const errors = [];
7003
7412
  const invalid = /* @__PURE__ */ new Set();
7413
+ let firstEvaluationError;
7004
7414
  for (const candidate of candidates) {
7005
7415
  candidate.record ??= {};
7006
- const rowErrors = [...candidate.preErrors];
7416
+ const rowErrors = includePreErrors ? [...candidate.preErrors] : [];
7007
7417
  for (const code of targetFields) {
7008
7418
  const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
7009
7419
  if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
7010
7420
  else candidate.record[code] = { value: result.value };
7011
7421
  }
7012
- if (candidate.mode === "create") {
7422
+ if (validateMissingCreateFields && candidate.mode === "create") {
7013
7423
  for (const info of fieldInfos) {
7014
7424
  if (info.inSubtable) continue;
7015
7425
  if (candidate.payload.has(info.code)) continue;
@@ -7031,6 +7441,23 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7031
7441
  }
7032
7442
  }
7033
7443
  }
7444
+ if (checkGroups.length > 0) {
7445
+ const row = candidate.evaluationRow ?? Object.fromEntries(
7446
+ [...candidate.payload].map(([field, value]) => [field, renderValidationValue(value)])
7447
+ );
7448
+ const types = candidate.evaluationFieldTypes;
7449
+ const resolveType = (field) => {
7450
+ const qualified = field.tableAlias ? `${field.tableAlias}.${field.field}` : field.field;
7451
+ return types?.get(qualified) ?? types?.get(field.field);
7452
+ };
7453
+ try {
7454
+ for (const custom of evaluateCustomChecks(checkGroups, row, resolveType)) {
7455
+ rowErrors.push({ field: "", code: "ERR_CHECK", message: custom.message });
7456
+ }
7457
+ } catch (error) {
7458
+ firstEvaluationError ??= error;
7459
+ }
7460
+ }
7034
7461
  if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
7035
7462
  for (const error of rowErrors) {
7036
7463
  const row = {};
@@ -7044,6 +7471,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7044
7471
  errors.push(row);
7045
7472
  }
7046
7473
  }
7474
+ if (firstEvaluationError !== void 0) throw firstEvaluationError;
7047
7475
  return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid };
7048
7476
  }
7049
7477
  function renderValidationValue(value) {
@@ -8100,7 +8528,7 @@ function buildHavingFieldSemanticsResolver(stmt, rowResolver) {
8100
8528
  }
8101
8529
  } else if (column.type === "STRFUNC_COL") {
8102
8530
  semantics = stringFunctionColumnMeta(column.expr).semantics;
8103
- } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL") {
8531
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_SUBQUERY_COL" || column.type === "CASE_COL" || column.type === "SCALAR_VALUE_COL") {
8104
8532
  semantics = syntheticSemantics("string");
8105
8533
  }
8106
8534
  if (semantics) aliases.set(column.alias, semantics);
@@ -8215,10 +8643,19 @@ function arithHasFieldRef(node) {
8215
8643
  return false;
8216
8644
  }
8217
8645
  function stringFuncArgHasFieldRef(arg) {
8218
- if (arg.type === "FIELD_REF") return true;
8219
- if (arg.type === "ARITH") return arithHasFieldRef(arg);
8220
- if (arg.type === "STRING_FUNC") return stringFuncHasFieldRef(arg);
8221
8646
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") return true;
8647
+ return scalarValueHasFieldRef(arg);
8648
+ }
8649
+ function scalarValueHasFieldRef(expr) {
8650
+ if (expr.type === "FIELD") return true;
8651
+ if (expr.type === "STRING_FUNC") return stringFuncHasFieldRef(expr);
8652
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
8653
+ return scalarValueHasFieldRef(expr.left) || scalarValueHasFieldRef(expr.right);
8654
+ }
8655
+ if (expr.type === "CASE_WHEN") {
8656
+ const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
8657
+ return results.some((result) => result.type !== "ARRAY" && (result.type === "FIELD_REF" || result.type === "ARITH" ? arithHasFieldRef(result) : scalarValueHasFieldRef(result)));
8658
+ }
8222
8659
  return false;
8223
8660
  }
8224
8661
  function stringFuncHasFieldRef(expr) {
@@ -8239,6 +8676,11 @@ function validateNoFromColumns(stmt) {
8239
8676
  throw new Error("ArgumentError: field reference is not allowed without FROM.");
8240
8677
  }
8241
8678
  break;
8679
+ case "SCALAR_VALUE_COL":
8680
+ if (scalarValueHasFieldRef(col.expr)) {
8681
+ throw new Error("ArgumentError: field reference is not allowed without FROM.");
8682
+ }
8683
+ break;
8242
8684
  case "WINDOW_COL":
8243
8685
  if (col.partitionBy.length > 0 || col.orderBy.length > 0) {
8244
8686
  throw new Error("ArgumentError: field reference is not allowed without FROM.");
@@ -8525,8 +8967,26 @@ function collectStringFuncAggregateRefs(expr, out) {
8525
8967
  for (const arg of expr.args) {
8526
8968
  if (arg.type === "AGG_REF" || arg.type === "AGG_ARITH") {
8527
8969
  collectAggregateOperandRefs(arg, out);
8528
- } else if (arg.type === "STRING_FUNC") {
8529
- collectStringFuncAggregateRefs(arg, out);
8970
+ } else {
8971
+ collectScalarAggregateRefs(arg, out);
8972
+ }
8973
+ }
8974
+ }
8975
+ function collectScalarAggregateRefs(expr, out) {
8976
+ if (expr.type === "STRING_FUNC") {
8977
+ collectStringFuncAggregateRefs(expr, out);
8978
+ return;
8979
+ }
8980
+ if (expr.type === "SCALAR_ARITH" || expr.type === "CONCAT_OP") {
8981
+ collectScalarAggregateRefs(expr.left, out);
8982
+ collectScalarAggregateRefs(expr.right, out);
8983
+ return;
8984
+ }
8985
+ if (expr.type === "CASE_WHEN") {
8986
+ const results = [...expr.branches.map((branch) => branch.result), ...expr.elseResult ? [expr.elseResult] : []];
8987
+ for (const result of results) {
8988
+ if (result.type === "STRING_FUNC") collectStringFuncAggregateRefs(result, out);
8989
+ else if (result.type !== "ARRAY" && result.type !== "FIELD_REF" && result.type !== "ARITH") collectScalarAggregateRefs(result, out);
8530
8990
  }
8531
8991
  }
8532
8992
  }
@@ -8539,6 +8999,8 @@ function collectSelectAggregateSortRefs(columns) {
8539
8999
  collectAggregateOperandRefs(column.expr, refs);
8540
9000
  } else if (column.type === "STRFUNC_COL") {
8541
9001
  collectStringFuncAggregateRefs(column.expr, refs);
9002
+ } else if (column.type === "SCALAR_VALUE_COL") {
9003
+ collectScalarAggregateRefs(column.expr, refs);
8542
9004
  }
8543
9005
  }
8544
9006
  return refs;
@@ -8704,10 +9166,11 @@ function stringFunctionColumnMeta(expr) {
8704
9166
  function caseResultColumnMeta(result, resolveField2) {
8705
9167
  if (result.type === "STRING") return syntheticColumnMeta("string");
8706
9168
  if (result.type === "ARRAY") return unsupportedColumnMeta();
8707
- if (result.type === "NUMBER" || result.type === "ARITH") return syntheticColumnMeta("number");
9169
+ if (result.type === "NUMBER" || result.type === "ARITH" || result.type === "SCALAR_ARITH") return syntheticColumnMeta("number");
8708
9170
  if (result.type === "STRING_FUNC") return stringFunctionColumnMeta(result);
8709
- const source = resolveField2(aggregateFieldRef(result.field));
8710
- return source ?? unknownStringColumnMeta();
9171
+ if (result.type === "FIELD_REF") return resolveField2(aggregateFieldRef(result.field)) ?? unknownStringColumnMeta();
9172
+ if (result.type === "FIELD") return resolveField2(result) ?? unknownStringColumnMeta();
9173
+ return unknownStringColumnMeta();
8711
9174
  }
8712
9175
  function mergeExpressionColumnMeta(candidates) {
8713
9176
  if (candidates.length === 0) return unknownStringColumnMeta();
@@ -8809,7 +9272,7 @@ async function inferSelectColumnMeta(stmt, outputColumns, client, cacheContext,
8809
9272
  }
8810
9273
  } else if (column.type === "ARITH_AGG_COL" || column.type === "ARITH_COL") {
8811
9274
  meta = syntheticColumnMeta("number");
8812
- } else if (column.type === "LITERAL_COL") {
9275
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") {
8813
9276
  meta = syntheticColumnMeta("string");
8814
9277
  } else if (column.type === "STRFUNC_COL") {
8815
9278
  meta = stringFunctionColumnMeta(column.expr);
@@ -9516,7 +9979,7 @@ async function buildOrderSemanticsForSelect(stmt, client, cacheContext, material
9516
9979
  if (column.type === "FIELD") meta = resolveField2(aggregateFieldRef(column.field));
9517
9980
  else if (column.type === "ARITH_COL" || column.type === "ARITH_AGG_COL" || column.type === "WINDOW_COL") {
9518
9981
  meta = syntheticColumnMeta("number");
9519
- } else if (column.type === "LITERAL_COL") meta = syntheticColumnMeta("string");
9982
+ } else if (column.type === "LITERAL_COL" || column.type === "SCALAR_VALUE_COL") meta = syntheticColumnMeta("string");
9520
9983
  else if (column.type === "STRFUNC_COL") meta = stringFunctionColumnMeta(column.expr);
9521
9984
  else if (column.type === "SCALAR_SUBQUERY_COL") meta = unknownStringColumnMeta();
9522
9985
  else if (column.type === "CASE_COL") {
@@ -9704,7 +10167,7 @@ var RejectLimitExceededError = class extends Error {
9704
10167
  this.name = "RejectLimitExceededError";
9705
10168
  }
9706
10169
  };
9707
- async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber) {
10170
+ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTables, statementNumber, validateMissingCreateFields = true, includePreErrors = true) {
9708
10171
  const operation = stmt.type === "UPDATE" ? "UPDATE" : stmt.type.startsWith("UPSERT") ? "UPSERT" : "INSERT";
9709
10172
  const payloadFields = stmt.type === "UPDATE" ? ["$id", ...stmt.assignments.map((a) => a.field)] : [...stmt.fields];
9710
10173
  if (new Set(payloadFields).size !== payloadFields.length) {
@@ -9736,7 +10199,10 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
9736
10199
  targetFields,
9737
10200
  fieldInfos,
9738
10201
  statementNumber,
9739
- numberPrecision
10202
+ numberPrecision,
10203
+ stmt.checkGroups ?? [],
10204
+ validateMissingCreateFields,
10205
+ includePreErrors
9740
10206
  );
9741
10207
  const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
9742
10208
  const result = {
@@ -9846,15 +10312,33 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
9846
10312
  async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode) {
9847
10313
  if (stmt.type === "UPDATE") return materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables);
9848
10314
  let rows;
10315
+ let sourceRows;
10316
+ let evaluationTypes;
9849
10317
  if (stmt.type === "INSERT" || stmt.type === "UPSERT") {
10318
+ assertInsertCheckRefs(stmt, stmt.fields);
10319
+ evaluationTypes = new Map(stmt.fields.map((field) => [field, infoByCode.get(field)?.fieldType ?? ""]));
10320
+ assertCheckComparisonTypes(stmt, evaluationTypes);
9850
10321
  rows = stmt.values.map((row) => row.map(
9851
10322
  (value, i) => value.type === "CASE_VALUE" ? evalCaseWhenValue(value.expr, {}, infoByCode.get(stmt.fields[i])?.fieldType) : value
9852
10323
  ));
9853
10324
  } else {
9854
- 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);
9855
- if (selectResult.columns.length !== stmt.fields.length) {
10325
+ 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);
10326
+ const hasChecks = (stmt.checkGroups?.length ?? 0) > 0;
10327
+ if (selectResult.columns.length < stmt.fields.length || !hasChecks && selectResult.columns.length !== stmt.fields.length) {
9856
10328
  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`);
9857
10329
  }
10330
+ if (hasChecks && new Set(selectResult.columns).size !== selectResult.columns.length) {
10331
+ 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");
10332
+ }
10333
+ assertInsertCheckRefs(stmt, selectResult.columns);
10334
+ sourceRows = selectResult.rows;
10335
+ const meta = materializedMetaBySelectResult.get(selectResult);
10336
+ evaluationTypes = new Map(selectResult.columns.map((column) => {
10337
+ const columnMeta = meta?.get(column);
10338
+ const type = columnMeta?.fieldType ?? (columnMeta?.semantics?.compareMode === "number" || columnMeta?.sortKind === "number" ? "NUMBER" : "SINGLE_LINE_TEXT");
10339
+ return [column, type];
10340
+ }));
10341
+ assertCheckComparisonTypes(stmt, evaluationTypes);
9858
10342
  rows = selectResult.rows.map((row) => selectResult.columns.map((column) => row[column] ?? ""));
9859
10343
  }
9860
10344
  const candidates = rows.map((values, index) => ({
@@ -9863,7 +10347,11 @@ async function materializeValidationCandidates(stmt, operation, client, options,
9863
10347
  mode: "create",
9864
10348
  payload: new Map(stmt.fields.map((field, i) => [field, values[i]])),
9865
10349
  preErrors: [],
9866
- record: {}
10350
+ record: {},
10351
+ evaluationRow: sourceRows?.[index] ?? Object.fromEntries(
10352
+ stmt.fields.map((field, i) => [field, renderValidationValue(values[i])])
10353
+ ),
10354
+ evaluationFieldTypes: evaluationTypes
9867
10355
  }));
9868
10356
  if (stmt.type !== "UPSERT" && stmt.type !== "UPSERT_SELECT") return candidates;
9869
10357
  for (const key of stmt.keyFields) {
@@ -9892,26 +10380,74 @@ async function materializeValidationCandidates(stmt, operation, client, options,
9892
10380
  });
9893
10381
  return candidates;
9894
10382
  }
10383
+ function checkRefs(stmt) {
10384
+ return stmt.checkGroups ? collectCheckFieldRefs(stmt.checkGroups) : [];
10385
+ }
10386
+ function assertInsertCheckRefs(stmt, available) {
10387
+ const names = new Set(available);
10388
+ for (const ref of checkRefs(stmt)) {
10389
+ if (ref.tableAlias !== null) {
10390
+ 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`);
10391
+ }
10392
+ if (!names.has(ref.field)) {
10393
+ throw customCheckParseError(`CHECK \u306E\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u8A55\u4FA1\u884C\u306B\u5B58\u5728\u3057\u307E\u305B\u3093`);
10394
+ }
10395
+ }
10396
+ }
10397
+ var CHECK_UNSUPPORTED_COMPARISON_TYPES = /* @__PURE__ */ new Set([
10398
+ "CHECK_BOX",
10399
+ "MULTI_SELECT",
10400
+ "USER_SELECT",
10401
+ "ORGANIZATION_SELECT",
10402
+ "GROUP_SELECT",
10403
+ "FILE",
10404
+ "KSQL_ARRAY"
10405
+ ]);
10406
+ function assertCheckComparisonTypes(stmt, types) {
10407
+ if (!stmt.checkGroups) return;
10408
+ for (const ref of collectCheckComparisonFieldRefs(stmt.checkGroups)) {
10409
+ const key = ref.tableAlias ? `${ref.tableAlias}.${ref.field}` : ref.field;
10410
+ const type = types.get(key) ?? types.get(ref.field);
10411
+ if (CHECK_UNSUPPORTED_COMPARISON_TYPES.has(type ?? "")) {
10412
+ throw customCheckParseError(`CHECK \u306E\u6BD4\u8F03\u3067\u306F ${type} \u30D5\u30A3\u30FC\u30EB\u30C9 ${key} \u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`);
10413
+ }
10414
+ }
10415
+ }
9895
10416
  async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables) {
9896
10417
  if (stmt.from) return materializeUpdateFromValidationCandidates(stmt, stmt.from, client, options, cacheContext, tempTables);
9897
10418
  await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
9898
10419
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
10420
+ const checkTargetFields = assertUpdateCheckRefs(stmt, fieldTypes);
10421
+ assertCheckComparisonTypes(stmt, updateEvaluationTypes(fieldTypes, stmt.appId));
9899
10422
  let records;
10423
+ let evaluationById = /* @__PURE__ */ new Map();
9900
10424
  if (hasRowDependentAssignment(stmt)) {
9901
10425
  const getParams = updateToGetQueryForArith(stmt);
9902
- const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [...getParams.fields], {
10426
+ const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields])];
10427
+ const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
9903
10428
  maxRecords: options.maxRecords ?? 1e4,
9904
10429
  parallel: options.fetchParallel ?? 1,
9905
10430
  onLimit: "error"
9906
10431
  });
10432
+ evaluationById = new Map(resolved.records.map((record) => [Number(record["$id"]?.value), record]));
9907
10433
  records = updateToPutBatchesArith(stmt, resolved.records, fieldTypes).flatMap((batch) => batch.records);
9908
10434
  } else {
9909
10435
  const getParams = updateToGetQuery(stmt);
9910
- const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
9911
- maxRecords: options.maxRecords ?? 1e4,
9912
- parallel: options.fetchParallel ?? 1
9913
- });
9914
- records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
10436
+ if (checkTargetFields.length > 0) {
10437
+ const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields])], {
10438
+ maxRecords: options.maxRecords ?? 1e4,
10439
+ parallel: options.fetchParallel ?? 1,
10440
+ onLimit: "error"
10441
+ });
10442
+ evaluationById = new Map(resolved.records.map((record) => [Number(record["$id"]?.value), record]));
10443
+ records = updateToPutBatches(stmt, [...evaluationById.keys()], fieldTypes).flatMap((batch) => batch.records);
10444
+ } else {
10445
+ const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
10446
+ maxRecords: options.maxRecords ?? 1e4,
10447
+ parallel: options.fetchParallel ?? 1
10448
+ });
10449
+ records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
10450
+ }
9915
10451
  }
9916
10452
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
9917
10453
  rowNumber: index + 1,
@@ -9920,13 +10456,48 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
9920
10456
  payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
9921
10457
  preErrors: [],
9922
10458
  record: entry.record,
9923
- targetId: entry.id
10459
+ targetId: entry.id,
10460
+ evaluationRow: updateEvaluationRow(evaluationById.get(entry.id), stmt.appId),
10461
+ evaluationFieldTypes: updateEvaluationTypes(fieldTypes, stmt.appId)
9924
10462
  }));
9925
10463
  }
10464
+ function assertUpdateCheckRefs(stmt, targetTypes) {
10465
+ if (stmt.from) return [];
10466
+ const fields = /* @__PURE__ */ new Set();
10467
+ for (const ref of checkRefs(stmt)) {
10468
+ if (ref.tableAlias !== null && ref.tableAlias.toLowerCase() !== `app${stmt.appId}`.toLowerCase()) {
10469
+ throw customCheckParseError(`CHECK \u306E\u4FEE\u98FE\u5B50 ${ref.tableAlias} \u306F\u66F4\u65B0\u5148 APP${stmt.appId} \u3067\u306F\u3042\u308A\u307E\u305B\u3093`);
10470
+ }
10471
+ if (ref.field !== "$id" && !targetTypes.has(ref.field)) {
10472
+ throw customCheckParseError(`CHECK \u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u5B58\u5728\u3057\u307E\u305B\u3093`);
10473
+ }
10474
+ fields.add(ref.field);
10475
+ }
10476
+ return [...fields];
10477
+ }
10478
+ function updateEvaluationRow(record, appId) {
10479
+ if (!record) return {};
10480
+ const plain = flatten(record, null);
10481
+ return Object.fromEntries([
10482
+ ...Object.entries(plain),
10483
+ ...Object.entries(plain).map(([field, value]) => [`APP${appId}.${field}`, value])
10484
+ ]);
10485
+ }
10486
+ function updateEvaluationTypes(types, appId) {
10487
+ return new Map([
10488
+ ...types,
10489
+ ...[...types].map(([field, type]) => [`APP${appId}.${field}`, type]),
10490
+ ["$id", "RECORD_NUMBER"],
10491
+ [`APP${appId}.$id`, "RECORD_NUMBER"]
10492
+ ]);
10493
+ }
9926
10494
  async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables) {
10495
+ const scope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
10496
+ assertCheckComparisonTypes(stmt, scope.evaluationTypes);
9927
10497
  const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
9928
10498
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
9929
10499
  const records = updateFromToPutBatches(stmt, matched, fieldTypes).flatMap((batch) => batch.records);
10500
+ const matchedById = new Map(matched.map((pair) => [Number(pair.target["$id"]?.value), pair]));
9930
10501
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
9931
10502
  rowNumber: index + 1,
9932
10503
  operation: "UPDATE",
@@ -9934,7 +10505,9 @@ async function materializeUpdateFromValidationCandidates(stmt, from, client, opt
9934
10505
  payload: new Map([["$id", String(entry.id)], ...stmt.assignments.map((a) => [a.field, entry.record[a.field]?.value ?? ""])]),
9935
10506
  preErrors: [],
9936
10507
  record: entry.record,
9937
- targetId: entry.id
10508
+ targetId: entry.id,
10509
+ evaluationRow: updateFromEvaluationRow(matchedById.get(entry.id), stmt.appId, from.alias),
10510
+ evaluationFieldTypes: scope.evaluationTypes
9938
10511
  }));
9939
10512
  }
9940
10513
  var UPDATE_FROM_KEY_CHUNK_SIZE = UPSERT_IN_CHUNK_SIZE;
@@ -9948,7 +10521,8 @@ var UPDATE_FROM_UNSUPPORTED_SOURCE_TYPES = /* @__PURE__ */ new Set([
9948
10521
  ]);
9949
10522
  async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables) {
9950
10523
  const joinKind = await resolveUpdateFromTargetJoinKind(stmt, from, client, cacheContext);
9951
- const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : ""))];
10524
+ const checkScope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
10525
+ 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))];
9952
10526
  const requiredSourceFields = [.../* @__PURE__ */ new Set([from.joinKeyField, ...sourceFields])];
9953
10527
  const sourceRows = await loadUpdateFromSourceRows(
9954
10528
  from,
@@ -9974,8 +10548,8 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
9974
10548
  }
9975
10549
  if (sourceByKey.size === 0) return [];
9976
10550
  const maxRecords = options.maxRecords ?? 1e4;
9977
- const targetFields = collectUpdateFromTargetFields(stmt);
9978
- const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter }).query;
10551
+ const targetFields = [.../* @__PURE__ */ new Set([...collectUpdateFromTargetFields(stmt), ...checkScope.targetFields])];
10552
+ const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter, checkGroups: void 0 }).query;
9979
10553
  const targetRecords = [];
9980
10554
  const seenTargetIds = /* @__PURE__ */ new Set();
9981
10555
  let fetchedTargetCount = 0;
@@ -10093,7 +10667,54 @@ function normalizeUpdateFromJoinKey(raw, kind, side) {
10093
10667
  }
10094
10668
  return JSON.stringify(decimal);
10095
10669
  }
10670
+ async function executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables) {
10671
+ const prepared = await prepareDmlValidation(
10672
+ stmt,
10673
+ client,
10674
+ options,
10675
+ cacheContext,
10676
+ tempTables,
10677
+ 1,
10678
+ false,
10679
+ false
10680
+ );
10681
+ if (prepared.result.errors.length > 0) {
10682
+ const first = prepared.result.errors[0];
10683
+ throw new Error(
10684
+ `DmlValidationError: ${first["$err_code"]} ${first["$err_message"]} (row=${first["$err_row"]}, field=${first["$err_field"]})`
10685
+ );
10686
+ }
10687
+ const candidates = prepared.candidates;
10688
+ const confirmOperation = stmt.type.startsWith("INSERT") ? "INSERT" : "UPDATE";
10689
+ if (options.confirm && candidates.length > 0) {
10690
+ const ok = await options.confirm(candidates.length, confirmOperation);
10691
+ if (!ok) throw new OperationCancelledError(confirmOperation, candidates.length);
10692
+ }
10693
+ if (stmt.type === "INSERT" || stmt.type === "INSERT_SELECT") {
10694
+ const createdIds = [];
10695
+ for (let i = 0; i < candidates.length; i += 100) {
10696
+ const response = await client.postRecords({ app: stmt.appId, records: candidates.slice(i, i + 100).map((c) => c.record) });
10697
+ createdIds.push(response.ids);
10698
+ }
10699
+ return { type: "INSERT", createdIds, insertedCount: createdIds.flat().length };
10700
+ }
10701
+ if (stmt.type === "UPDATE") {
10702
+ const updates2 = candidates.map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
10703
+ for (let i = 0; i < updates2.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates2.slice(i, i + 100) });
10704
+ return { type: "UPDATE", updatedCount: updates2.length };
10705
+ }
10706
+ const inserts = candidates.filter((candidate) => candidate.mode === "create");
10707
+ const updates = candidates.filter((candidate) => candidate.mode === "update").map((candidate) => ({ id: candidate.targetId, record: candidate.record }));
10708
+ let insertedCount = 0;
10709
+ for (let i = 0; i < inserts.length; i += 100) {
10710
+ const response = await client.postRecords({ app: stmt.appId, records: inserts.slice(i, i + 100).map((c) => c.record) });
10711
+ insertedCount += response.ids.length;
10712
+ }
10713
+ for (let i = 0; i < updates.length; i += 100) await client.putRecords({ app: stmt.appId, records: updates.slice(i, i + 100) });
10714
+ return { type: "UPSERT", insertedCount, updatedCount: updates.length };
10715
+ }
10096
10716
  async function executeInsert(stmt, client, options, cacheContext) {
10717
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
10097
10718
  if (stmt.subtableCode) {
10098
10719
  return executeInsertSubtable(stmt, client, options, cacheContext);
10099
10720
  }
@@ -10114,6 +10735,7 @@ async function executeInsert(stmt, client, options, cacheContext) {
10114
10735
  };
10115
10736
  }
10116
10737
  async function executeInsertSelect(stmt, client, options, cacheContext, cteCache) {
10738
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
10117
10739
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
10118
10740
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
10119
10741
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
@@ -10151,6 +10773,7 @@ async function executeInsertSelect(stmt, client, options, cacheContext, cteCache
10151
10773
  };
10152
10774
  }
10153
10775
  async function executeUpdate(stmt, client, options, cacheContext, tempTables) {
10776
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, tempTables);
10154
10777
  if (stmt.subtableCode) {
10155
10778
  await assertDmlWhereCapability(stmt, client, cacheContext);
10156
10779
  return executeUpdateSubtable(stmt, client, options, cacheContext);
@@ -10276,6 +10899,7 @@ async function executeDelete(stmt, client, options, cacheContext) {
10276
10899
  return { type: "DELETE", deletedCount: ids.length };
10277
10900
  }
10278
10901
  async function executeUpsert(stmt, client, options, cacheContext) {
10902
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext);
10279
10903
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
10280
10904
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
10281
10905
  const toInsert = [];
@@ -10710,6 +11334,7 @@ function evalOrderKeyForRow(key, row) {
10710
11334
  }
10711
11335
  }
10712
11336
  async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache) {
11337
+ if (stmt.checkGroups?.length) return executeCheckedPlainDml(stmt, client, options, cacheContext, cteCache);
10713
11338
  const fieldInfos = await loadWritableTopLevelDmlFields(stmt.appId, stmt.fields, client, cacheContext);
10714
11339
  const numberPrecision = await loadNumberPrecisionForTargets(stmt.appId, stmt.fields, fieldInfos, client, cacheContext);
10715
11340
  const selectResult = cteCache !== void 0 && cteCache.size > 0 ? await executeQueryWithCte(stmt.select, client, options, cteCache, cacheContext) : await executeSelect(stmt.select, client, options, cacheContext);
@@ -11457,6 +12082,7 @@ function collectArithRefFields(stmt) {
11457
12082
  for (const { value } of stmt.assignments) {
11458
12083
  if (value.type === "ARITH") collectArithNodeRefs(value, refs);
11459
12084
  if (value.type === "STRING_FUNC") collectArithNodeRefs(value, refs);
12085
+ if (value.type === "SCALAR_ARITH" || value.type === "CONCAT_OP") collectScalarNodeRefs(value, refs);
11460
12086
  }
11461
12087
  return [...refs];
11462
12088
  }
@@ -11471,10 +12097,74 @@ function collectArithNodeRefs(node, out) {
11471
12097
  }
11472
12098
  if (node.type === "STRING_FUNC") {
11473
12099
  for (const arg of node.args) {
11474
- if (arg.type !== "STRING" && arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") {
11475
- collectArithNodeRefs(arg, out);
12100
+ if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
12101
+ }
12102
+ }
12103
+ }
12104
+ async function resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables) {
12105
+ const refs = checkRefs(stmt);
12106
+ const targetTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
12107
+ const sourceTableName = from.cteName;
12108
+ const sourceTypes = sourceTableName !== null ? new Map((tempTables?.get(sourceTableName)?.columns ?? []).map((column) => [
12109
+ column,
12110
+ tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.fieldType ?? (tempTables?.get(sourceTableName)?.columnMeta?.get(column)?.semantics?.compareMode === "number" ? "NUMBER" : "SINGLE_LINE_TEXT")
12111
+ ])) : await getFieldTypeMap(from.appId, client, cacheContext);
12112
+ const targetFields = /* @__PURE__ */ new Set();
12113
+ const sourceFields = /* @__PURE__ */ new Set();
12114
+ for (const ref of refs) {
12115
+ if (ref.tableAlias !== null) {
12116
+ if (ref.tableAlias.toLowerCase() === `app${stmt.appId}`.toLowerCase()) {
12117
+ 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`);
12118
+ targetFields.add(ref.field);
12119
+ } else if (ref.tableAlias.toLowerCase() === from.alias.toLowerCase()) {
12120
+ 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`);
12121
+ sourceFields.add(ref.field);
12122
+ } else {
12123
+ 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`);
11476
12124
  }
12125
+ continue;
11477
12126
  }
12127
+ const inTarget = ref.field === "$id" || targetTypes.has(ref.field);
12128
+ const inSource = ref.field === "$id" || sourceTypes.has(ref.field);
12129
+ if (!inTarget) {
12130
+ throw customCheckParseError(`UPDATE FROM \u306E CHECK \u3067\u306F\u30BD\u30FC\u30B9\u5217 ${ref.field} \u3092\u4FEE\u98FE\u3057\u3066\u304F\u3060\u3055\u3044`);
12131
+ }
12132
+ if (inSource) {
12133
+ throw customCheckParseError(`UPDATE FROM \u306E CHECK \u306E\u975E\u4FEE\u98FE\u30D5\u30A3\u30FC\u30EB\u30C9 ${ref.field} \u306F\u66D6\u6627\u3067\u3059`);
12134
+ }
12135
+ targetFields.add(ref.field);
12136
+ }
12137
+ const evaluationTypes = /* @__PURE__ */ new Map();
12138
+ for (const [field, type] of targetTypes) {
12139
+ evaluationTypes.set(field, type);
12140
+ evaluationTypes.set(`APP${stmt.appId}.${field}`, type);
12141
+ }
12142
+ evaluationTypes.set("$id", "RECORD_NUMBER");
12143
+ evaluationTypes.set(`APP${stmt.appId}.$id`, "RECORD_NUMBER");
12144
+ for (const [field, type] of sourceTypes) evaluationTypes.set(`${from.alias}.${field}`, type);
12145
+ return { targetFields: [...targetFields], sourceFields: [...sourceFields], evaluationTypes };
12146
+ }
12147
+ function updateFromEvaluationRow(pair, appId, sourceAlias) {
12148
+ if (!pair) return {};
12149
+ const target = flatten(pair.target, null);
12150
+ return Object.fromEntries([
12151
+ ...Object.entries(target),
12152
+ ...Object.entries(target).map(([field, value]) => [`APP${appId}.${field}`, value]),
12153
+ ...Object.entries(pair.source).map(([field, value]) => [`${sourceAlias}.${field}`, value])
12154
+ ]);
12155
+ }
12156
+ function collectScalarNodeRefs(node, out) {
12157
+ if (node.type === "FIELD") {
12158
+ out.add(node.tableAlias ? `${node.tableAlias}.${node.field}` : node.field);
12159
+ return;
12160
+ }
12161
+ if (node.type === "STRING_FUNC") {
12162
+ for (const arg of node.args) if (arg.type !== "AGG_REF" && arg.type !== "AGG_ARITH") collectScalarNodeRefs(arg, out);
12163
+ return;
12164
+ }
12165
+ if (node.type === "SCALAR_ARITH" || node.type === "CONCAT_OP") {
12166
+ collectScalarNodeRefs(node.left, out);
12167
+ collectScalarNodeRefs(node.right, out);
11478
12168
  }
11479
12169
  }
11480
12170
  function formatAssignment(a) {