Skip to content

Commit 0bb973b

Browse files
jianhe-funCommitfest Bot
authored andcommitted
refactor CreateTrigger and CreateTriggerFiringOn
discussion: https://postgr.es/m/
1 parent b4cbc10 commit 0bb973b

File tree

9 files changed

+212
-140
lines changed

9 files changed

+212
-140
lines changed

src/backend/catalog/index.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2039,10 +2039,11 @@ index_constraint_create(Relation heapRelation,
20392039
trigger->deferrable = true;
20402040
trigger->initdeferred = initdeferred;
20412041
trigger->constrrel = NULL;
2042+
trigger->transformed = true;
20422043

20432044
(void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
20442045
InvalidOid, conOid, indexRelationId, InvalidOid,
2045-
InvalidOid, NULL, true, false);
2046+
InvalidOid, true, false);
20462047
}
20472048

20482049
/*

src/backend/commands/tablecmds.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13826,10 +13826,11 @@ CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
1382613826
fk_trigger->deferrable = fkconstraint->deferrable;
1382713827
fk_trigger->initdeferred = fkconstraint->initdeferred;
1382813828
fk_trigger->constrrel = NULL;
13829+
fk_trigger->transformed = true;
1382913830

1383013831
trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
1383113832
constraintOid, indexOid, InvalidOid,
13832-
parentTrigOid, NULL, true, false);
13833+
parentTrigOid, true, false);
1383313834

1383413835
/* Make changes-so-far visible */
1383513836
CommandCounterIncrement();
@@ -13871,6 +13872,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
1387113872
fk_trigger->whenClause = NULL;
1387213873
fk_trigger->transitionRels = NIL;
1387313874
fk_trigger->constrrel = NULL;
13875+
fk_trigger->transformed = true;
1387413876

1387513877
switch (fkconstraint->fk_del_action)
1387613878
{
@@ -13907,7 +13909,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
1390713909

1390813910
trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid,
1390913911
constraintOid, indexOid, InvalidOid,
13910-
parentDelTrigger, NULL, true, false);
13912+
parentDelTrigger, true, false);
1391113913
if (deleteTrigOid)
1391213914
*deleteTrigOid = trigAddress.objectId;
1391313915

@@ -13931,6 +13933,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
1393113933
fk_trigger->whenClause = NULL;
1393213934
fk_trigger->transitionRels = NIL;
1393313935
fk_trigger->constrrel = NULL;
13936+
fk_trigger->transformed = true;
1393413937

1393513938
switch (fkconstraint->fk_upd_action)
1393613939
{
@@ -13967,7 +13970,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
1396713970

1396813971
trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid,
1396913972
constraintOid, indexOid, InvalidOid,
13970-
parentUpdTrigger, NULL, true, false);
13973+
parentUpdTrigger, true, false);
1397113974
if (updateTrigOid)
1397213975
*updateTrigOid = trigAddress.objectId;
1397313976
}
@@ -20857,15 +20860,16 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
2085720860
trigStmt->timing = trigForm->tgtype & TRIGGER_TYPE_TIMING_MASK;
2085820861
trigStmt->events = trigForm->tgtype & TRIGGER_TYPE_EVENT_MASK;
2085920862
trigStmt->columns = cols;
20860-
trigStmt->whenClause = NULL; /* passed separately */
20863+
trigStmt->whenClause = qual;
2086120864
trigStmt->transitionRels = NIL; /* not supported at present */
2086220865
trigStmt->deferrable = trigForm->tgdeferrable;
2086320866
trigStmt->initdeferred = trigForm->tginitdeferred;
2086420867
trigStmt->constrrel = NULL; /* passed separately */
20868+
trigStmt->transformed = true; /* whenClause alerady transformed */
2086520869

2086620870
CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
2086720871
trigForm->tgconstrrelid, InvalidOid, InvalidOid,
20868-
trigForm->tgfoid, trigForm->oid, qual,
20872+
trigForm->tgfoid, trigForm->oid,
2086920873
false, true, trigForm->tgenabled);
2087020874

2087120875
MemoryContextSwitchTo(oldcxt);

src/backend/commands/trigger.c

Lines changed: 49 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "parser/parse_collate.h"
4141
#include "parser/parse_func.h"
4242
#include "parser/parse_relation.h"
43+
#include "parser/parse_utilcmd.h"
4344
#include "partitioning/partdesc.h"
4445
#include "pgstat.h"
4546
#include "rewrite/rewriteHandler.h"
@@ -139,9 +140,6 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
139140
* create the trigger on partitions, 2) when creating child foreign key
140141
* triggers; see CreateFKCheckTrigger() and createForeignKeyActionTriggers().
141142
*
142-
* If whenClause is passed, it is an already-transformed expression for
143-
* WHEN. In this case, we ignore any that may come in stmt->whenClause.
144-
*
145143
* If isInternal is true then this is an internally-generated trigger.
146144
* This argument sets the tgisinternal field of the pg_trigger entry, and
147145
* if true causes us to modify the given trigger name to ensure uniqueness.
@@ -159,13 +157,13 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
159157
ObjectAddress
160158
CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
161159
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
162-
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
160+
Oid funcoid, Oid parentTriggerOid,
163161
bool isInternal, bool in_partition)
164162
{
165163
return
166164
CreateTriggerFiringOn(stmt, queryString, relOid, refRelOid,
167165
constraintOid, indexOid, funcoid,
168-
parentTriggerOid, whenClause, isInternal,
166+
parentTriggerOid, isInternal,
169167
in_partition, TRIGGER_FIRES_ON_ORIGIN);
170168
}
171169

@@ -177,15 +175,15 @@ ObjectAddress
177175
CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
178176
Oid relOid, Oid refRelOid, Oid constraintOid,
179177
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
180-
Node *whenClause, bool isInternal, bool in_partition,
178+
bool isInternal, bool in_partition,
181179
char trigger_fires_when)
182180
{
183181
int16 tgtype;
184182
int ncolumns;
185183
int16 *columns;
186184
int2vector *tgattr;
187-
List *whenRtable;
188-
char *qual;
185+
List *whenRtable = NIL;
186+
char *qual = NULL;
189187
Datum values[Natts_pg_trigger];
190188
bool nulls[Natts_pg_trigger];
191189
Relation rel;
@@ -207,6 +205,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
207205
Oid existing_constraint_oid = InvalidOid;
208206
bool existing_isInternal = false;
209207
bool existing_isClone = false;
208+
Node *whenClause = NULL;
210209

211210
if (OidIsValid(relOid))
212211
rel = table_open(relOid, ShareRowExclusiveLock);
@@ -557,133 +556,21 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
557556
/*
558557
* Parse the WHEN clause, if any and we weren't passed an already
559558
* transformed one.
560-
*
561-
* Note that as a side effect, we fill whenRtable when parsing. If we got
562-
* an already parsed clause, this does not occur, which is what we want --
563-
* no point in adding redundant dependencies below.
564559
*/
565-
if (!whenClause && stmt->whenClause)
560+
if (stmt->whenClause)
566561
{
567-
ParseState *pstate;
568-
ParseNamespaceItem *nsitem;
569-
List *varList;
570-
ListCell *lc;
571-
572-
/* Set up a pstate to parse with */
573-
pstate = make_parsestate(NULL);
574-
pstate->p_sourcetext = queryString;
575-
576-
/*
577-
* Set up nsitems for OLD and NEW references.
578-
*
579-
* 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
580-
*/
581-
nsitem = addRangeTableEntryForRelation(pstate, rel,
582-
AccessShareLock,
583-
makeAlias("old", NIL),
584-
false, false);
585-
addNSItemToQuery(pstate, nsitem, false, true, true);
586-
nsitem = addRangeTableEntryForRelation(pstate, rel,
587-
AccessShareLock,
588-
makeAlias("new", NIL),
589-
false, false);
590-
addNSItemToQuery(pstate, nsitem, false, true, true);
591-
592-
/* Transform expression. Copy to be sure we don't modify original */
593-
whenClause = transformWhereClause(pstate,
594-
copyObject(stmt->whenClause),
595-
EXPR_KIND_TRIGGER_WHEN,
596-
"WHEN");
597-
/* we have to fix its collations too */
598-
assign_expr_collations(pstate, whenClause);
599-
600-
/*
601-
* Check for disallowed references to OLD/NEW.
602-
*
603-
* NB: pull_var_clause is okay here only because we don't allow
604-
* subselects in WHEN clauses; it would fail to examine the contents
605-
* of subselects.
606-
*/
607-
varList = pull_var_clause(whenClause, 0);
608-
foreach(lc, varList)
562+
if (!stmt->transformed)
609563
{
610-
Var *var = (Var *) lfirst(lc);
564+
stmt = transformCreateTriggerStmt(RelationGetRelid(rel), stmt,
565+
queryString);
611566

612-
switch (var->varno)
613-
{
614-
case PRS2_OLD_VARNO:
615-
if (!TRIGGER_FOR_ROW(tgtype))
616-
ereport(ERROR,
617-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
618-
errmsg("statement trigger's WHEN condition cannot reference column values"),
619-
parser_errposition(pstate, var->location)));
620-
if (TRIGGER_FOR_INSERT(tgtype))
621-
ereport(ERROR,
622-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
623-
errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
624-
parser_errposition(pstate, var->location)));
625-
/* system columns are okay here */
626-
break;
627-
case PRS2_NEW_VARNO:
628-
if (!TRIGGER_FOR_ROW(tgtype))
629-
ereport(ERROR,
630-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
631-
errmsg("statement trigger's WHEN condition cannot reference column values"),
632-
parser_errposition(pstate, var->location)));
633-
if (TRIGGER_FOR_DELETE(tgtype))
634-
ereport(ERROR,
635-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
636-
errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
637-
parser_errposition(pstate, var->location)));
638-
if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
639-
ereport(ERROR,
640-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
641-
errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
642-
parser_errposition(pstate, var->location)));
643-
if (TRIGGER_FOR_BEFORE(tgtype) &&
644-
var->varattno == 0 &&
645-
RelationGetDescr(rel)->constr &&
646-
(RelationGetDescr(rel)->constr->has_generated_stored ||
647-
RelationGetDescr(rel)->constr->has_generated_virtual))
648-
ereport(ERROR,
649-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
650-
errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
651-
errdetail("A whole-row reference is used and the table contains generated columns."),
652-
parser_errposition(pstate, var->location)));
653-
if (TRIGGER_FOR_BEFORE(tgtype) &&
654-
var->varattno > 0 &&
655-
TupleDescAttr(RelationGetDescr(rel), var->varattno - 1)->attgenerated)
656-
ereport(ERROR,
657-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
658-
errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
659-
errdetail("Column \"%s\" is a generated column.",
660-
NameStr(TupleDescAttr(RelationGetDescr(rel), var->varattno - 1)->attname)),
661-
parser_errposition(pstate, var->location)));
662-
break;
663-
default:
664-
/* can't happen without add_missing_from, so just elog */
665-
elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
666-
break;
667-
}
567+
whenClause = stmt->whenClause;
568+
Assert(whenClause != NULL);
668569
}
669-
670-
/* we'll need the rtable for recordDependencyOnExpr */
671-
whenRtable = pstate->p_rtable;
570+
else
571+
whenClause = stmt->whenClause;
672572

673573
qual = nodeToString(whenClause);
674-
675-
free_parsestate(pstate);
676-
}
677-
else if (!whenClause)
678-
{
679-
whenClause = NULL;
680-
whenRtable = NIL;
681-
qual = NULL;
682-
}
683-
else
684-
{
685-
qual = nodeToString(whenClause);
686-
whenRtable = NIL;
687574
}
688575

689576
/*
@@ -1129,10 +1016,40 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
11291016
* If it has a WHEN clause, add dependencies on objects mentioned in the
11301017
* expression (eg, functions, as well as any columns used).
11311018
*/
1132-
if (whenRtable != NIL)
1019+
if (whenClause != NULL)
1020+
{
1021+
ParseState *pstate;
1022+
ParseNamespaceItem *nsitem;
1023+
1024+
/* Set up a pstate to parse with */
1025+
pstate = make_parsestate(NULL);
1026+
pstate->p_sourcetext = queryString;
1027+
1028+
/*
1029+
* Set up nsitems for OLD and NEW references.
1030+
*
1031+
* 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
1032+
*/
1033+
nsitem = addRangeTableEntryForRelation(pstate, rel,
1034+
AccessShareLock,
1035+
makeAlias("old", NIL),
1036+
false, false);
1037+
addNSItemToQuery(pstate, nsitem, false, true, true);
1038+
1039+
nsitem = addRangeTableEntryForRelation(pstate, rel,
1040+
AccessShareLock,
1041+
makeAlias("new", NIL),
1042+
false, false);
1043+
addNSItemToQuery(pstate, nsitem, false, true, true);
1044+
1045+
/* we'll need the rtable for recordDependencyOnExpr */
1046+
whenRtable = pstate->p_rtable;
11331047
recordDependencyOnExpr(&myself, whenClause, whenRtable,
11341048
DEPENDENCY_NORMAL);
11351049

1050+
free_parsestate(pstate);
1051+
}
1052+
11361053
/* Post creation hook for new trigger */
11371054
InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
11381055
isInternal);
@@ -1175,7 +1092,6 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
11751092
*/
11761093
childStmt = copyObject(stmt);
11771094
childStmt->funcname = NIL;
1178-
childStmt->whenClause = NULL;
11791095

11801096
/* If there is a WHEN clause, create a modified copy of it */
11811097
qual = copyObject(whenClause);
@@ -1185,11 +1101,13 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
11851101
qual = (Node *)
11861102
map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
11871103
childTbl, rel);
1104+
childStmt->whenClause = qual;
1105+
childStmt->transformed = true;
11881106

11891107
CreateTriggerFiringOn(childStmt, queryString,
11901108
partdesc->oids[i], refRelOid,
11911109
InvalidOid, InvalidOid,
1192-
funcoid, trigoid, qual,
1110+
funcoid, trigoid,
11931111
isInternal, true, trigger_fires_when);
11941112

11951113
table_close(childTbl, NoLock);

src/backend/parser/gram.y

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6098,6 +6098,7 @@ CreateTrigStmt:
60986098
n->deferrable = false;
60996099
n->initdeferred = false;
61006100
n->constrrel = NULL;
6101+
n->transformed = false;
61016102
$$ = (Node *) n;
61026103
}
61036104
| CREATE opt_or_replace CONSTRAINT TRIGGER name AFTER TriggerEvents ON
@@ -6148,6 +6149,7 @@ CreateTrigStmt:
61486149
&n->deferrable, &n->initdeferred, &dummy,
61496150
NULL, NULL, yyscanner);
61506151
n->constrrel = $10;
6152+
n->transformed = false;
61516153
$$ = (Node *) n;
61526154
}
61536155
;

0 commit comments

Comments
 (0)