biz-a-cli 2.3.80-15357 → 2.3.80-15359
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/engine/orm/executeBlock.js +53 -3
- package/package.json +1 -1
|
@@ -521,8 +521,7 @@ const coerceOne = (table, column, value, dbIndex) => {
|
|
|
521
521
|
};
|
|
522
522
|
|
|
523
523
|
/* `INSERT INTO t (a, b) VALUES (x, y)` — positional, so a column/value count mismatch means the
|
|
524
|
-
alignment cannot be trusted and nothing is touched.
|
|
525
|
-
and is left alone by construction. */
|
|
524
|
+
alignment cannot be trusted and nothing is touched. */
|
|
526
525
|
const INSERT_VALUES = /^(INSERT\s+INTO\s+([\w$."]+)\s*\(([^)]*)\)\s*VALUES\s*\()([\s\S]*)(\)\s*)$/i;
|
|
527
526
|
const coerceInsert = (statement, dbIndex) => {
|
|
528
527
|
const match = INSERT_VALUES.exec(statement.trim());
|
|
@@ -534,6 +533,52 @@ const coerceInsert = (statement, dbIndex) => {
|
|
|
534
533
|
return head + values.map((v, i) => coerceOne(table, columns[i], v, dbIndex)).join(",") + tail;
|
|
535
534
|
};
|
|
536
535
|
|
|
536
|
+
/*
|
|
537
|
+
* `INSERT INTO t (a, b) SELECT <literals> [WHERE …]` — the guarded-insert idiom.
|
|
538
|
+
*
|
|
539
|
+
* ⚠️⚠️ THIS FORM WAS LEFT ALONE ON PURPOSE AND THAT WAS WRONG. The note here used to read "an
|
|
540
|
+
* `INSERT … SELECT` has no list to align to", which is true of a SELECT reading a real table and
|
|
541
|
+
* false of the shape applications actually write:
|
|
542
|
+
*
|
|
543
|
+
* INSERT INTO ST_ITEM_CATEGORY (ID, CODE, NAME, ACTIVE, …)
|
|
544
|
+
* SELECT '{…}', 'makanan', 'makanan', 1, NULL, NULL
|
|
545
|
+
* WHERE NOT EXISTS (SELECT 1 FROM ST_ITEM_CATEGORY WHERE ID = '{…}')
|
|
546
|
+
*
|
|
547
|
+
* That select list IS a fixed tuple aligned to the column list — which `stampAuthorshipLiterals`
|
|
548
|
+
* below had already concluded, and has been relying on for months, **on these very statements**.
|
|
549
|
+
* The two halves of this module simply disagreed about whether the form was safe to align, and QA
|
|
550
|
+
* found the disagreement: `column "active" is of type boolean but expression is of type integer`.
|
|
551
|
+
*
|
|
552
|
+
* ⚠️ THE SAFETY CONDITION IS BORROWED VERBATIM from that function, because it is the part that
|
|
553
|
+
* matters: nothing may read from a real table (no top-level FROM, once the translator has stripped
|
|
554
|
+
* Firebird's `FROM RDB$DATABASE`), and the tuple must split to exactly the column count. Outside
|
|
555
|
+
* those two conditions the alignment is a guess, and a wrong guess quotes somebody else's value.
|
|
556
|
+
*/
|
|
557
|
+
const INSERT_SELECT = /^INSERT\s+INTO\s+([\w$."]+)\s*\(([^)]*)\)\s*(SELECT\s[\s\S]*)$/i;
|
|
558
|
+
const coerceInsertSelect = (statement, dbIndex) => {
|
|
559
|
+
const match = INSERT_SELECT.exec(statement.trim());
|
|
560
|
+
if (!match) return statement;
|
|
561
|
+
const [, table, columnText, rest] = match;
|
|
562
|
+
|
|
563
|
+
/* ⚠️ Reading a real table means the select list is expressions, not a tuple. */
|
|
564
|
+
if (topLevelIndexOf(rest, "FROM") !== -1) return statement;
|
|
565
|
+
|
|
566
|
+
const whereAt = topLevelIndexOf(rest, "WHERE");
|
|
567
|
+
const selectList = whereAt === -1 ? rest.slice("SELECT".length) : rest.slice("SELECT".length, whereAt);
|
|
568
|
+
/* whereAt points AT the keyword, so the separating space belongs to the tail. */
|
|
569
|
+
const tail = whereAt === -1 ? "" : " " + rest.slice(whereAt);
|
|
570
|
+
|
|
571
|
+
const columns = columnText.split(",").map((c) => c.trim().replace(/^"|"$/g, ""));
|
|
572
|
+
const values = splitValueList(selectList);
|
|
573
|
+
if (columns.length !== values.length) return statement;
|
|
574
|
+
|
|
575
|
+
return (
|
|
576
|
+
"INSERT INTO " + table + " (" + columnText + ") SELECT" +
|
|
577
|
+
values.map((v, i) => coerceOne(table, columns[i], v, dbIndex)).join(",") +
|
|
578
|
+
tail
|
|
579
|
+
);
|
|
580
|
+
};
|
|
581
|
+
|
|
537
582
|
/* `UPDATE t SET a = x, b = y [WHERE …]` — ASSIGNMENTS ONLY. The WHERE clause is a filter, handled
|
|
538
583
|
where filters are built; rewriting it here too risks corrupting a comparison meant literally. */
|
|
539
584
|
const UPDATE_SET = /^(UPDATE\s+([\w$."]+)\s+SET\s+)([\s\S]*?)(\s+WHERE[\s\S]*)?$/i;
|
|
@@ -687,7 +732,12 @@ const coerceBooleanLiterals = (statement, dbIndex) => {
|
|
|
687
732
|
if (/^\s*INSERT\s/i.test(statement)) {
|
|
688
733
|
/* ⚠️ Booleans FIRST, then the stamps. Coercion aligns values to the ORIGINAL column list, so
|
|
689
734
|
appending first would shift every value one place and quote the wrong one. */
|
|
690
|
-
|
|
735
|
+
/* ⚠️ Both INSERT shapes, then the stamps. Coercion aligns values to the ORIGINAL column
|
|
736
|
+
list, so appending the stamp columns first would shift every value one place. */
|
|
737
|
+
return stampAuthorshipLiterals(
|
|
738
|
+
coerceInsertSelect(coerceInsert(statement, dbIndex), dbIndex),
|
|
739
|
+
dbIndex,
|
|
740
|
+
);
|
|
691
741
|
}
|
|
692
742
|
if (/^\s*UPDATE\s/i.test(statement)) return coerceUpdate(statement, dbIndex);
|
|
693
743
|
return statement;
|