@crvouga/mockingbird-service-postgres 3.7.0 → 3.8.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/CHANGELOG.md +7 -1
- package/COMPATIBILITY.md +2 -1
- package/dist/admin.js +243 -78
- package/dist/admin.js.map +3 -3
- package/dist/ast/nodes.d.ts +5 -0
- package/dist/constraints/enforce.d.ts +7 -1
- package/dist/executor/triggers.d.ts +13 -0
- package/dist/functions/pgtrgm.d.ts +4 -4
- package/dist/index.js +127 -12
- package/dist/index.js.map +2 -2
- package/dist/server.js +126 -11
- package/dist/server.js.map +3 -3
- package/dist/storage/database-state.d.ts +4 -0
- package/dist/unstable.js +126 -11
- package/dist/unstable.js.map +2 -2
- package/dist/wire/cli.js +236 -21
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/fleet.d.ts +18 -0
- package/dist/wire/index.js +126 -11
- package/dist/wire/index.js.map +3 -3
- package/package.json +1 -1
package/dist/ast/nodes.d.ts
CHANGED
|
@@ -645,6 +645,11 @@ export interface CreateTriggerStmt {
|
|
|
645
645
|
readonly when: Expr | null;
|
|
646
646
|
readonly funcName: string[];
|
|
647
647
|
readonly funcArgs: string[];
|
|
648
|
+
/** `REFERENCING { OLD | NEW } TABLE [AS] name` items in source order; validated when the trigger is created */
|
|
649
|
+
readonly transitions?: ReadonlyArray<{
|
|
650
|
+
isNew: boolean;
|
|
651
|
+
name: string;
|
|
652
|
+
}>;
|
|
648
653
|
}
|
|
649
654
|
export type AlterTableAction = {
|
|
650
655
|
kind: "add_column";
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import type { Expr } from "../ast/nodes.js";
|
|
1
2
|
import type { ExecEnv } from "../executor/relation.js";
|
|
2
3
|
import type { IndexMeta, TableData } from "../storage/database-state.js";
|
|
3
|
-
import { type Datum } from "../types/value.js";
|
|
4
|
+
import { type Datum, type TypeId } from "../types/value.js";
|
|
5
|
+
/**
|
|
6
|
+
* The type an expression over `table` yields, found by evaluating it against an all-NULL row.
|
|
7
|
+
* Binding errors (unknown column or function) surface as they would when PostgreSQL parses the expression.
|
|
8
|
+
*/
|
|
9
|
+
export declare function expressionTypeOf(env: ExecEnv, table: TableData, expr: Expr): TypeId;
|
|
4
10
|
/** NOT NULL column constraints (23502). */
|
|
5
11
|
export declare function checkNotNull(env: ExecEnv, table: TableData, row: Datum[]): void;
|
|
6
12
|
/** CHECK constraints (23514); NULL results pass. */
|
|
@@ -16,5 +16,18 @@ export type TriggerExecutor = (env: ExecEnv, table: TableData, trigger: TriggerM
|
|
|
16
16
|
export declare function setTriggerExecutor(e: TriggerExecutor): void;
|
|
17
17
|
export declare function fireRowTriggers(env: ExecEnv, table: TableData, timing: "before" | "after" | "instead_of", event: TriggerEvent, oldRow: Datum[] | null, newRow: Datum[] | null): TriggerFireResult;
|
|
18
18
|
export declare function hasRowTriggers(table: TableData, timing: "before" | "after" | "instead_of", event: TriggerEvent): boolean;
|
|
19
|
+
/** The rows a statement changed, as the `REFERENCING` transition tables of its AFTER statement triggers. */
|
|
20
|
+
export interface TransitionRows {
|
|
21
|
+
/** rows before the change (UPDATE, DELETE) */
|
|
22
|
+
oldRows: Datum[][];
|
|
23
|
+
/** rows after the change (INSERT, UPDATE); position-aligned with `oldRows` for UPDATE */
|
|
24
|
+
newRows: Datum[][];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fire the statement-level triggers of `table` for `event`, once, in trigger-name order. AFTER triggers
|
|
28
|
+
* that declare transition tables read them as relations named by their `REFERENCING` clause; the
|
|
29
|
+
* function body sees nothing else of the statement (no outer CTEs, parameters or scope).
|
|
30
|
+
*/
|
|
31
|
+
export declare function fireStatementTriggers(env: ExecEnv, table: TableData, timing: "before" | "after", event: TriggerEvent, transitions?: TransitionRows): void;
|
|
19
32
|
export declare function flushConstraintTriggers(state: DatabaseState, all?: boolean): void;
|
|
20
33
|
export declare function setConstraints(state: DatabaseState, stmt: SetConstraintsStmt): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { CreateIndexStmt } from "../ast/nodes.js";
|
|
1
|
+
import type { CreateIndexStmt, Expr } from "../ast/nodes.js";
|
|
2
2
|
import type { EngineCtx } from "../expressions/context.js";
|
|
3
3
|
import type { DatabaseState, FunctionData, TableData } from "../storage/database-state.js";
|
|
4
|
-
import { type TypedValue } from "../types/value.js";
|
|
4
|
+
import { type TypedValue, type TypeId } from "../types/value.js";
|
|
5
5
|
export declare function pgTrgmSchema(state: DatabaseState): string | null;
|
|
6
6
|
export declare function pgTrgmInstalled(state: DatabaseState): boolean;
|
|
7
7
|
export declare function installPgTrgm(state: DatabaseState, schemaName: string): void;
|
|
@@ -11,10 +11,10 @@ export declare function evalPgTrgmFunction(ctx: EngineCtx, fn: FunctionData, arg
|
|
|
11
11
|
export declare function evalTrgmWordSimilar(ctx: EngineCtx, left: TypedValue, right: TypedValue): TypedValue;
|
|
12
12
|
/**
|
|
13
13
|
* Reject `gin_trgm_ops` unless pg_trgm is installed for access method gin.
|
|
14
|
-
* A single text/varchar column is stored as an ordinary non-unique index:
|
|
14
|
+
* A single text/varchar column or expression is stored as an ordinary non-unique index:
|
|
15
15
|
* lookup speed is not modelled.
|
|
16
16
|
*/
|
|
17
|
-
export declare function assertGinTrgmIndex(state: DatabaseState, table: TableData, stmt: CreateIndexStmt): void;
|
|
17
|
+
export declare function assertGinTrgmIndex(state: DatabaseState, table: TableData, stmt: CreateIndexStmt, expressionType: (expr: Expr) => TypeId): void;
|
|
18
18
|
/** `|intersection| / |union|` as float4. Either empty trigram set yields 0. */
|
|
19
19
|
export declare function trigramSimilarity(left: string, right: string): number;
|
|
20
20
|
/**
|
package/dist/index.js
CHANGED
|
@@ -9955,7 +9955,7 @@ function evalTrgmWordSimilar(ctx, left, right) {
|
|
|
9955
9955
|
const score = wordSimilarity(a.v, b.v);
|
|
9956
9956
|
return tv("bool", score >= WORD_SIMILARITY_THRESHOLD);
|
|
9957
9957
|
}
|
|
9958
|
-
function assertGinTrgmIndex(state, table, stmt) {
|
|
9958
|
+
function assertGinTrgmIndex(state, table, stmt, expressionType) {
|
|
9959
9959
|
const trgmCols = stmt.columns.filter((col2) => isGinTrgmOpclass(col2.opclass));
|
|
9960
9960
|
if (trgmCols.length === 0) return;
|
|
9961
9961
|
if (trgmCols.length !== stmt.columns.length || stmt.columns.length !== 1) {
|
|
@@ -9975,11 +9975,7 @@ function assertGinTrgmIndex(state, table, stmt) {
|
|
|
9975
9975
|
if (stmt.unique) {
|
|
9976
9976
|
throw pgError("feature_not_supported", `access method "gin" does not support unique indexes`, "0A000");
|
|
9977
9977
|
}
|
|
9978
|
-
|
|
9979
|
-
throw unsupported("expression gin_trgm_ops");
|
|
9980
|
-
}
|
|
9981
|
-
const index = table.columnIndex(col.expr.parts[0]);
|
|
9982
|
-
const typeId = table.columns[index].type.id;
|
|
9978
|
+
const typeId = col.expr.type === "colref" && col.expr.parts.length === 1 ? table.columns[table.columnIndex(col.expr.parts[0])].type.id : expressionType(col.expr);
|
|
9983
9979
|
if (!GIN_TRGM_TYPES.has(typeId)) {
|
|
9984
9980
|
throw pgError(
|
|
9985
9981
|
"datatype_mismatch",
|
|
@@ -13617,6 +13613,17 @@ function tableScope(table, row) {
|
|
|
13617
13613
|
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
13618
13614
|
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
13619
13615
|
}
|
|
13616
|
+
function expressionTypeOf(env, table, expr) {
|
|
13617
|
+
const scope = makeEvalScope(
|
|
13618
|
+
env,
|
|
13619
|
+
tableScope(
|
|
13620
|
+
table,
|
|
13621
|
+
table.columns.map(() => null)
|
|
13622
|
+
)
|
|
13623
|
+
);
|
|
13624
|
+
const v = evalExpr(env.ctx, scope, expr);
|
|
13625
|
+
return v.t === "unknown" ? "text" : v.t;
|
|
13626
|
+
}
|
|
13620
13627
|
function checkNotNull(env, table, row) {
|
|
13621
13628
|
void env;
|
|
13622
13629
|
for (let i = 0; i < table.columns.length; i++) {
|
|
@@ -16539,7 +16546,6 @@ var Parser = class {
|
|
|
16539
16546
|
} while (this.eatKw("or"));
|
|
16540
16547
|
this.expectKw("on");
|
|
16541
16548
|
const table = this.qualifiedName();
|
|
16542
|
-
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
16543
16549
|
let deferrable = false;
|
|
16544
16550
|
let initiallyDeferred = false;
|
|
16545
16551
|
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
@@ -16552,6 +16558,23 @@ var Parser = class {
|
|
|
16552
16558
|
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
16553
16559
|
if (initiallyDeferred && !deferrable)
|
|
16554
16560
|
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
16561
|
+
const transitions = [];
|
|
16562
|
+
if (!constraint && this.eatKw("referencing")) {
|
|
16563
|
+
do {
|
|
16564
|
+
const isNew = this.eatKw("new");
|
|
16565
|
+
if (!isNew) this.expectKw("old");
|
|
16566
|
+
if (this.eatKw("row")) {
|
|
16567
|
+
throw pgError(
|
|
16568
|
+
"feature_not_supported",
|
|
16569
|
+
"ROW variable naming in the REFERENCING clause is not supported",
|
|
16570
|
+
"0A000"
|
|
16571
|
+
);
|
|
16572
|
+
}
|
|
16573
|
+
this.expectKw("table");
|
|
16574
|
+
this.eatKw("as");
|
|
16575
|
+
transitions.push({ isNew, name: this.ident() });
|
|
16576
|
+
} while (this.atKw("new") || this.atKw("old"));
|
|
16577
|
+
}
|
|
16555
16578
|
let forEachRow = false;
|
|
16556
16579
|
if (this.eatKw("for")) {
|
|
16557
16580
|
this.eatKw("each");
|
|
@@ -16589,7 +16612,8 @@ var Parser = class {
|
|
|
16589
16612
|
forEachRow,
|
|
16590
16613
|
when,
|
|
16591
16614
|
funcName,
|
|
16592
|
-
funcArgs
|
|
16615
|
+
funcArgs,
|
|
16616
|
+
...transitions.length > 0 ? { transitions } : {}
|
|
16593
16617
|
};
|
|
16594
16618
|
}
|
|
16595
16619
|
// --- ALTER --------------------------------------------------------------------
|
|
@@ -21135,6 +21159,29 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
21135
21159
|
}
|
|
21136
21160
|
return { row };
|
|
21137
21161
|
}
|
|
21162
|
+
function transitionRelation(table, name, rows) {
|
|
21163
|
+
return {
|
|
21164
|
+
columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: name })),
|
|
21165
|
+
rows
|
|
21166
|
+
};
|
|
21167
|
+
}
|
|
21168
|
+
function fireStatementTriggers(env, table, timing, event, transitions) {
|
|
21169
|
+
const fired = table.triggers.filter((t) => !t.forEachRow && t.timing === timing && matches(t, event)).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
21170
|
+
for (const t of fired) {
|
|
21171
|
+
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
21172
|
+
const ctes = /* @__PURE__ */ new Map();
|
|
21173
|
+
if (t.oldTable !== void 0)
|
|
21174
|
+
ctes.set(t.oldTable, transitionRelation(table, t.oldTable, transitions?.oldRows ?? []));
|
|
21175
|
+
if (t.newTable !== void 0)
|
|
21176
|
+
ctes.set(t.newTable, transitionRelation(table, t.newTable, transitions?.newRows ?? []));
|
|
21177
|
+
const changes = env.ctx.state.changes;
|
|
21178
|
+
try {
|
|
21179
|
+
executor({ ctx: env.ctx, params: null, ctes, outer: null }, table, t, event, null, null);
|
|
21180
|
+
} finally {
|
|
21181
|
+
env.ctx.state.changes = changes;
|
|
21182
|
+
}
|
|
21183
|
+
}
|
|
21184
|
+
}
|
|
21138
21185
|
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
21139
21186
|
function flushConstraintTriggers(state, all = false) {
|
|
21140
21187
|
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
@@ -21518,7 +21565,13 @@ function executeInsert(env0, stmt) {
|
|
|
21518
21565
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
21519
21566
|
const insertedRows = [];
|
|
21520
21567
|
let insertedCount = 0;
|
|
21568
|
+
const addedRows = [];
|
|
21569
|
+
const conflictOldRows = [];
|
|
21570
|
+
const conflictNewRows = [];
|
|
21571
|
+
const updatesOnConflict = stmt.onConflict !== null && stmt.onConflict.action !== "nothing";
|
|
21521
21572
|
return withStatementRollback(env, () => {
|
|
21573
|
+
fireStatementTriggers(env, table, "before", "insert");
|
|
21574
|
+
if (updatesOnConflict) fireStatementTriggers(env, table, "before", "update");
|
|
21522
21575
|
for (const srcRow of sourceRows) {
|
|
21523
21576
|
const row = table.columns.map(() => null);
|
|
21524
21577
|
const provided = /* @__PURE__ */ new Set();
|
|
@@ -21564,6 +21617,7 @@ function executeInsert(env0, stmt) {
|
|
|
21564
21617
|
}
|
|
21565
21618
|
if (conflictIdx !== null && conflictWhereOk) {
|
|
21566
21619
|
if (stmt.onConflict.action === "nothing") continue;
|
|
21620
|
+
const replaced = rows[conflictIdx];
|
|
21567
21621
|
const did = applyOnConflictUpdate(
|
|
21568
21622
|
env,
|
|
21569
21623
|
table,
|
|
@@ -21576,6 +21630,8 @@ function executeInsert(env0, stmt) {
|
|
|
21576
21630
|
if (did) {
|
|
21577
21631
|
insertedCount++;
|
|
21578
21632
|
insertedRows.push(rows[conflictIdx]);
|
|
21633
|
+
conflictOldRows.push(replaced);
|
|
21634
|
+
conflictNewRows.push(rows[conflictIdx]);
|
|
21579
21635
|
fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
|
|
21580
21636
|
}
|
|
21581
21637
|
continue;
|
|
@@ -21590,8 +21646,13 @@ function executeInsert(env0, stmt) {
|
|
|
21590
21646
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
21591
21647
|
insertedCount++;
|
|
21592
21648
|
insertedRows.push(newRow);
|
|
21649
|
+
addedRows.push(newRow);
|
|
21593
21650
|
fireRowTriggers(env, table, "after", "insert", null, newRow);
|
|
21594
21651
|
}
|
|
21652
|
+
fireStatementTriggers(env, table, "after", "insert", { oldRows: [], newRows: addedRows });
|
|
21653
|
+
if (updatesOnConflict) {
|
|
21654
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: conflictOldRows, newRows: conflictNewRows });
|
|
21655
|
+
}
|
|
21595
21656
|
env.ctx.state.changes = insertedCount;
|
|
21596
21657
|
if (stmt.returning) {
|
|
21597
21658
|
const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
|
|
@@ -21672,10 +21733,12 @@ function executeUpdate(env0, stmt) {
|
|
|
21672
21733
|
const env = applyWith(env0, stmt.with);
|
|
21673
21734
|
const table = requireTargetTable(env, stmt.table, "update");
|
|
21674
21735
|
const label = stmt.alias ?? table.name;
|
|
21736
|
+
fireStatementTriggers(env, table, "before", "update");
|
|
21675
21737
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
21676
21738
|
const rows = table.mutableRows();
|
|
21677
21739
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
21678
21740
|
const updatedRows = [];
|
|
21741
|
+
const replacedRows = [];
|
|
21679
21742
|
let updateCount = 0;
|
|
21680
21743
|
for (let ri = 0; ri < rows.length; ri++) {
|
|
21681
21744
|
const oldRow = rows[ri];
|
|
@@ -21718,8 +21781,10 @@ function executeUpdate(env0, stmt) {
|
|
|
21718
21781
|
handleReferencedUpdate(env, table, [oldRow], [finalRow]);
|
|
21719
21782
|
updateCount++;
|
|
21720
21783
|
updatedRows.push(finalRow);
|
|
21784
|
+
replacedRows.push(oldRow);
|
|
21721
21785
|
fireRowTriggers(env, table, "after", "update", oldRow, finalRow);
|
|
21722
21786
|
}
|
|
21787
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: replacedRows, newRows: updatedRows });
|
|
21723
21788
|
env.ctx.state.changes = updateCount;
|
|
21724
21789
|
if (stmt.returning) {
|
|
21725
21790
|
const res = evalReturning(env, table, label, stmt.returning, updatedRows, "UPDATE");
|
|
@@ -21731,6 +21796,7 @@ function executeDelete(env0, stmt) {
|
|
|
21731
21796
|
const env = applyWith(env0, stmt.with);
|
|
21732
21797
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
21733
21798
|
const label = stmt.alias ?? table.name;
|
|
21799
|
+
fireStatementTriggers(env, table, "before", "delete");
|
|
21734
21800
|
const rows = table.mutableRows();
|
|
21735
21801
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
21736
21802
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
@@ -21768,6 +21834,7 @@ function executeDelete(env0, stmt) {
|
|
|
21768
21834
|
fireRowTriggers(env, table, "after", "delete", row, null);
|
|
21769
21835
|
}
|
|
21770
21836
|
if (deletedRows.length > 0) rebuildTableIndexes(env, table);
|
|
21837
|
+
fireStatementTriggers(env, table, "after", "delete", { oldRows: deletedRows, newRows: [] });
|
|
21771
21838
|
env.ctx.state.changes = deletedRows.length;
|
|
21772
21839
|
if (stmt.returning) {
|
|
21773
21840
|
const res = evalReturning(env, table, label, stmt.returning, deletedRows, "DELETE");
|
|
@@ -23910,7 +23977,7 @@ function pgTrigger(ctx) {
|
|
|
23910
23977
|
let oid = 4e4;
|
|
23911
23978
|
for (const t of allTables(ctx.state)) {
|
|
23912
23979
|
for (const tr of t.triggers) {
|
|
23913
|
-
rows.push([oid++, tr.name, t.oid, !tr.forEachRow]);
|
|
23980
|
+
rows.push([oid++, tr.name, t.oid, !tr.forEachRow, tr.oldTable ?? null, tr.newTable ?? null]);
|
|
23914
23981
|
}
|
|
23915
23982
|
}
|
|
23916
23983
|
return rel2(
|
|
@@ -23918,7 +23985,9 @@ function pgTrigger(ctx) {
|
|
|
23918
23985
|
["oid", "oid"],
|
|
23919
23986
|
["tgname", "name"],
|
|
23920
23987
|
["tgrelid", "oid"],
|
|
23921
|
-
["tgisinternal", "bool"]
|
|
23988
|
+
["tgisinternal", "bool"],
|
|
23989
|
+
["tgoldtable", "name"],
|
|
23990
|
+
["tgnewtable", "name"]
|
|
23922
23991
|
],
|
|
23923
23992
|
rows,
|
|
23924
23993
|
"pg_trigger"
|
|
@@ -25342,7 +25411,7 @@ function executeCreateIndex(env, stmt) {
|
|
|
25342
25411
|
}
|
|
25343
25412
|
}
|
|
25344
25413
|
}
|
|
25345
|
-
assertGinTrgmIndex(state, table, stmt);
|
|
25414
|
+
assertGinTrgmIndex(state, table, stmt, (expr) => expressionTypeOf(env, table, expr));
|
|
25346
25415
|
const method = stmt.using ?? "btree";
|
|
25347
25416
|
if (!ACCESS_METHODS.has(method) || method === "heap") {
|
|
25348
25417
|
throw pgError("undefined_object", `access method "${method}" does not exist`, "42704");
|
|
@@ -25597,6 +25666,50 @@ function executeCreateFunction(env, stmt) {
|
|
|
25597
25666
|
schema.functions.set(name, existing);
|
|
25598
25667
|
return commandResult("CREATE FUNCTION", 0);
|
|
25599
25668
|
}
|
|
25669
|
+
function validateTransitionTables(stmt) {
|
|
25670
|
+
const transitions = stmt.transitions ?? [];
|
|
25671
|
+
if (transitions.length === 0) return {};
|
|
25672
|
+
const invalid = (message) => pgError("invalid_table_definition", message, "42P17");
|
|
25673
|
+
const unsupportedClause = (message) => pgError("feature_not_supported", message, "0A000");
|
|
25674
|
+
if (stmt.timing !== "after") throw invalid("transition table name can only be specified for an AFTER trigger");
|
|
25675
|
+
if (stmt.events.some((e) => e.event === "truncate")) {
|
|
25676
|
+
throw unsupportedClause("TRUNCATE triggers with transition tables are not supported");
|
|
25677
|
+
}
|
|
25678
|
+
if (stmt.events.some((e) => e.columns !== null)) {
|
|
25679
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with column lists");
|
|
25680
|
+
}
|
|
25681
|
+
if (stmt.events.length > 1) {
|
|
25682
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with more than one event");
|
|
25683
|
+
}
|
|
25684
|
+
const event = stmt.events[0].event;
|
|
25685
|
+
let oldTable;
|
|
25686
|
+
let newTable;
|
|
25687
|
+
for (const transition of transitions) {
|
|
25688
|
+
if (transition.isNew) {
|
|
25689
|
+
if (event !== "insert" && event !== "update") {
|
|
25690
|
+
throw invalid("NEW TABLE can only be specified for an INSERT or UPDATE trigger");
|
|
25691
|
+
}
|
|
25692
|
+
if (newTable !== void 0) throw invalid("NEW TABLE cannot be specified multiple times");
|
|
25693
|
+
newTable = transition.name;
|
|
25694
|
+
} else {
|
|
25695
|
+
if (event !== "delete" && event !== "update") {
|
|
25696
|
+
throw invalid("OLD TABLE can only be specified for a DELETE or UPDATE trigger");
|
|
25697
|
+
}
|
|
25698
|
+
if (oldTable !== void 0) throw invalid("OLD TABLE cannot be specified multiple times");
|
|
25699
|
+
oldTable = transition.name;
|
|
25700
|
+
}
|
|
25701
|
+
}
|
|
25702
|
+
if (oldTable !== void 0 && oldTable === newTable) {
|
|
25703
|
+
throw invalid("OLD TABLE name and NEW TABLE name cannot be the same");
|
|
25704
|
+
}
|
|
25705
|
+
if (stmt.forEachRow) {
|
|
25706
|
+
throw pgError("unsupported", "transition tables on FOR EACH ROW triggers are not supported", "0A000");
|
|
25707
|
+
}
|
|
25708
|
+
return {
|
|
25709
|
+
...oldTable !== void 0 ? { oldTable } : {},
|
|
25710
|
+
...newTable !== void 0 ? { newTable } : {}
|
|
25711
|
+
};
|
|
25712
|
+
}
|
|
25600
25713
|
function executeCreateTrigger(env, stmt) {
|
|
25601
25714
|
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
25602
25715
|
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
@@ -25606,6 +25719,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25606
25719
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
25607
25720
|
}
|
|
25608
25721
|
const table = state.ensureWritableTable(found);
|
|
25722
|
+
const transitionTables = validateTransitionTables(stmt);
|
|
25609
25723
|
const fnSchema = stmt.funcName.length >= 2 ? stmt.funcName[stmt.funcName.length - 2] : null;
|
|
25610
25724
|
const fnName = stmt.funcName[stmt.funcName.length - 1];
|
|
25611
25725
|
const fns = state.findFunctions(stmt.funcName);
|
|
@@ -25624,6 +25738,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25624
25738
|
timing: stmt.timing,
|
|
25625
25739
|
events: stmt.events,
|
|
25626
25740
|
forEachRow: stmt.forEachRow,
|
|
25741
|
+
...transitionTables,
|
|
25627
25742
|
when: stmt.when,
|
|
25628
25743
|
funcSchema: fnSchema ?? fns[0].schema,
|
|
25629
25744
|
funcName: fnName,
|
|
@@ -28246,7 +28361,7 @@ function analyzeSchema(sql, options = {}) {
|
|
|
28246
28361
|
const diagnosticLimit = bounded(options.maxDiagnostics, 100, 1e3);
|
|
28247
28362
|
const report = {
|
|
28248
28363
|
engine: "mockingbird-postgres",
|
|
28249
|
-
version: true ? "3.
|
|
28364
|
+
version: true ? "3.8.0" : "source-tree",
|
|
28250
28365
|
statements: 0,
|
|
28251
28366
|
accepted: 0,
|
|
28252
28367
|
compatible: null,
|