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
159157ObjectAddress
160158CreateTrigger (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
177175CreateTriggerFiringOn (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 );
0 commit comments