1
/*-------------------------------------------------------------------------
4
* PostgreSQL TRIGGERs support code.
6
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
10
* src/backend/commands/trigger.c
12
*-------------------------------------------------------------------------
16
#include "access/genam.h"
17
#include "access/heapam.h"
18
#include "access/sysattr.h"
19
#include "access/xact.h"
20
#include "catalog/catalog.h"
21
#include "catalog/dependency.h"
22
#include "catalog/indexing.h"
23
#include "catalog/objectaccess.h"
24
#include "catalog/pg_constraint.h"
25
#include "catalog/pg_proc.h"
26
#include "catalog/pg_trigger.h"
27
#include "catalog/pg_type.h"
28
#include "commands/dbcommands.h"
29
#include "commands/defrem.h"
30
#include "commands/trigger.h"
31
#include "executor/executor.h"
32
#include "executor/instrument.h"
33
#include "miscadmin.h"
34
#include "nodes/bitmapset.h"
35
#include "nodes/makefuncs.h"
36
#include "optimizer/clauses.h"
37
#include "optimizer/var.h"
38
#include "parser/parse_clause.h"
39
#include "parser/parse_collate.h"
40
#include "parser/parse_func.h"
41
#include "parser/parse_relation.h"
42
#include "parser/parsetree.h"
44
#include "rewrite/rewriteManip.h"
45
#include "storage/bufmgr.h"
46
#include "tcop/utility.h"
47
#include "utils/acl.h"
48
#include "utils/builtins.h"
49
#include "utils/bytea.h"
50
#include "utils/fmgroids.h"
51
#include "utils/inval.h"
52
#include "utils/lsyscache.h"
53
#include "utils/memutils.h"
54
#include "utils/snapmgr.h"
55
#include "utils/syscache.h"
56
#include "utils/tqual.h"
60
int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
63
#define GetModifiedColumns(relinfo, estate) \
64
(rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)
66
/* Local function prototypes */
67
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
68
static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger);
69
static HeapTuple GetTupleForTrigger(EState *estate,
71
ResultRelInfo *relinfo,
73
TupleTableSlot **newSlot);
74
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
75
Trigger *trigger, TriggerEvent event,
76
Bitmapset *modifiedCols,
77
HeapTuple oldtup, HeapTuple newtup);
78
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
81
Instrumentation *instr,
82
MemoryContext per_tuple_context);
83
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
84
int event, bool row_trigger,
85
HeapTuple oldtup, HeapTuple newtup,
86
List *recheckIndexes, Bitmapset *modifiedCols);
90
* Create a trigger. Returns the OID of the created trigger.
92
* queryString is the source text of the CREATE TRIGGER command.
93
* This must be supplied if a whenClause is specified, else it can be NULL.
95
* constraintOid, if nonzero, says that this trigger is being created
96
* internally to implement that constraint. A suitable pg_depend entry will
97
* be made to link the trigger to that constraint. constraintOid is zero when
98
* executing a user-entered CREATE TRIGGER command. (For CREATE CONSTRAINT
99
* TRIGGER, we build a pg_constraint entry internally.)
101
* indexOid, if nonzero, is the OID of an index associated with the constraint.
102
* We do nothing with this except store it into pg_trigger.tgconstrindid.
104
* If isInternal is true then this is an internally-generated trigger.
105
* This argument sets the tgisinternal field of the pg_trigger entry, and
106
* if TRUE causes us to modify the given trigger name to ensure uniqueness.
108
* When isInternal is not true we require ACL_TRIGGER permissions on the
109
* relation. For internal triggers the caller must apply any required
112
* Note: can return InvalidOid if we decided to not create a trigger at all,
113
* but a foreign-key constraint. This is a kluge for backwards compatibility.
116
CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
117
Oid constraintOid, Oid indexOid,
127
Datum values[Natts_pg_trigger];
128
bool nulls[Natts_pg_trigger];
136
Oid fargtypes[1]; /* dummy */
140
char internaltrigname[NAMEDATALEN];
142
Oid constrrelid = InvalidOid;
143
ObjectAddress myself,
147
* ShareRowExclusiveLock is sufficient to prevent concurrent write
148
* activity to the relation, and thus to lock out any operations that
149
* might want to fire triggers on the relation. If we had ON SELECT
150
* triggers we would need to take an AccessExclusiveLock to add one of
151
* those, just as we do with ON SELECT rules.
153
rel = heap_openrv(stmt->relation, ShareRowExclusiveLock);
156
* Triggers must be on tables or views, and there are additional
157
* relation-type-specific restrictions.
159
if (rel->rd_rel->relkind == RELKIND_RELATION)
161
/* Tables can't have INSTEAD OF triggers */
162
if (stmt->timing != TRIGGER_TYPE_BEFORE &&
163
stmt->timing != TRIGGER_TYPE_AFTER)
165
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
166
errmsg("\"%s\" is a table",
167
RelationGetRelationName(rel)),
168
errdetail("Tables cannot have INSTEAD OF triggers.")));
170
else if (rel->rd_rel->relkind == RELKIND_VIEW)
173
* Views can have INSTEAD OF triggers (which we check below are
174
* row-level), or statement-level BEFORE/AFTER triggers.
176
if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
178
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
179
errmsg("\"%s\" is a view",
180
RelationGetRelationName(rel)),
181
errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
182
/* Disallow TRUNCATE triggers on VIEWs */
183
if (TRIGGER_FOR_TRUNCATE(stmt->events))
185
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
186
errmsg("\"%s\" is a view",
187
RelationGetRelationName(rel)),
188
errdetail("Views cannot have TRUNCATE triggers.")));
192
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
193
errmsg("\"%s\" is not a table or view",
194
RelationGetRelationName(rel))));
196
if (!allowSystemTableMods && IsSystemRelation(rel))
198
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
199
errmsg("permission denied: \"%s\" is a system catalog",
200
RelationGetRelationName(rel))));
202
if (stmt->isconstraint && stmt->constrrel != NULL)
203
constrrelid = RangeVarGetRelid(stmt->constrrel, false);
205
/* permission checks */
208
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
210
if (aclresult != ACLCHECK_OK)
211
aclcheck_error(aclresult, ACL_KIND_CLASS,
212
RelationGetRelationName(rel));
214
if (OidIsValid(constrrelid))
216
aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
218
if (aclresult != ACLCHECK_OK)
219
aclcheck_error(aclresult, ACL_KIND_CLASS,
220
get_rel_name(constrrelid));
225
TRIGGER_CLEAR_TYPE(tgtype);
227
TRIGGER_SETT_ROW(tgtype);
228
tgtype |= stmt->timing;
229
tgtype |= stmt->events;
231
/* Disallow ROW-level TRUNCATE triggers */
232
if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
234
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
235
errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
237
/* INSTEAD triggers must be row-level, and can't have WHEN or columns */
238
if (TRIGGER_FOR_INSTEAD(tgtype))
240
if (!TRIGGER_FOR_ROW(tgtype))
242
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
243
errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
244
if (stmt->whenClause)
246
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
247
errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
248
if (stmt->columns != NIL)
250
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
251
errmsg("INSTEAD OF triggers cannot have column lists")));
255
* Parse the WHEN clause, if any
257
if (stmt->whenClause)
264
/* Set up a pstate to parse with */
265
pstate = make_parsestate(NULL);
266
pstate->p_sourcetext = queryString;
269
* Set up RTEs for OLD and NEW references.
271
* 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
273
rte = addRangeTableEntryForRelation(pstate, rel,
274
makeAlias("old", NIL),
276
addRTEtoQuery(pstate, rte, false, true, true);
277
rte = addRangeTableEntryForRelation(pstate, rel,
278
makeAlias("new", NIL),
280
addRTEtoQuery(pstate, rte, false, true, true);
282
/* Transform expression. Copy to be sure we don't modify original */
283
whenClause = transformWhereClause(pstate,
284
copyObject(stmt->whenClause),
286
/* we have to fix its collations too */
287
assign_expr_collations(pstate, whenClause);
290
* No subplans or aggregates, please
292
if (pstate->p_hasSubLinks)
294
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
295
errmsg("cannot use subquery in trigger WHEN condition")));
296
if (pstate->p_hasAggs)
298
(errcode(ERRCODE_GROUPING_ERROR),
299
errmsg("cannot use aggregate function in trigger WHEN condition")));
300
if (pstate->p_hasWindowFuncs)
302
(errcode(ERRCODE_WINDOWING_ERROR),
303
errmsg("cannot use window function in trigger WHEN condition")));
306
* Check for disallowed references to OLD/NEW.
308
* NB: pull_var_clause is okay here only because we don't allow
309
* subselects in WHEN clauses; it would fail to examine the contents
312
varList = pull_var_clause(whenClause, PVC_REJECT_PLACEHOLDERS);
315
Var *var = (Var *) lfirst(lc);
320
if (!TRIGGER_FOR_ROW(tgtype))
322
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
323
errmsg("statement trigger's WHEN condition cannot reference column values"),
324
parser_errposition(pstate, var->location)));
325
if (TRIGGER_FOR_INSERT(tgtype))
327
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
328
errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
329
parser_errposition(pstate, var->location)));
330
/* system columns are okay here */
333
if (!TRIGGER_FOR_ROW(tgtype))
335
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
336
errmsg("statement trigger's WHEN condition cannot reference column values"),
337
parser_errposition(pstate, var->location)));
338
if (TRIGGER_FOR_DELETE(tgtype))
340
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
341
errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
342
parser_errposition(pstate, var->location)));
343
if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
345
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
346
errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
347
parser_errposition(pstate, var->location)));
350
/* can't happen without add_missing_from, so just elog */
351
elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
356
/* we'll need the rtable for recordDependencyOnExpr */
357
whenRtable = pstate->p_rtable;
359
qual = nodeToString(whenClause);
361
free_parsestate(pstate);
371
* Find and validate the trigger function.
373
funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
374
funcrettype = get_func_rettype(funcoid);
375
if (funcrettype != TRIGGEROID)
378
* We allow OPAQUE just so we can load old dump files. When we see a
379
* trigger function declared OPAQUE, change it to TRIGGER.
381
if (funcrettype == OPAQUEOID)
384
(errmsg("changing return type of function %s from \"opaque\" to \"trigger\"",
385
NameListToString(stmt->funcname))));
386
SetFunctionReturnType(funcoid, TRIGGEROID);
390
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
391
errmsg("function %s must return type \"trigger\"",
392
NameListToString(stmt->funcname))));
396
* If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
397
* references one of the built-in RI_FKey trigger functions, assume it is
398
* from a dump of a pre-7.3 foreign key constraint, and take steps to
399
* convert this legacy representation into a regular foreign key
400
* constraint. Ugly, but necessary for loading old dump files.
402
if (stmt->isconstraint && !isInternal &&
403
list_length(stmt->args) >= 6 &&
404
(list_length(stmt->args) % 2) == 0 &&
405
RI_FKey_trigger_type(funcoid) != RI_TRIGGER_NONE)
407
/* Keep lock on target rel until end of xact */
408
heap_close(rel, NoLock);
410
ConvertTriggerToFK(stmt, funcoid);
416
* If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
417
* corresponding pg_constraint entry.
419
if (stmt->isconstraint && !OidIsValid(constraintOid))
421
/* Internal callers should have made their own constraints */
423
constraintOid = CreateConstraintEntry(stmt->trigname,
424
RelationGetNamespace(rel),
429
RelationGetRelid(rel),
430
NULL, /* no conkey */
432
InvalidOid, /* no domain */
433
InvalidOid, /* no index */
434
InvalidOid, /* no foreign key */
443
NULL, /* no exclusion */
444
NULL, /* no check constraint */
452
* Generate the trigger's OID now, so that we can use it in the name if
455
tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
457
trigoid = GetNewOid(tgrel);
460
* If trigger is internally generated, modify the provided trigger name to
461
* ensure uniqueness by appending the trigger OID. (Callers will usually
462
* supply a simple constant trigger name in these cases.)
466
snprintf(internaltrigname, sizeof(internaltrigname),
467
"%s_%u", stmt->trigname, trigoid);
468
trigname = internaltrigname;
472
/* user-defined trigger; use the specified trigger name as-is */
473
trigname = stmt->trigname;
477
* Scan pg_trigger for existing triggers on relation. We do this only to
478
* give a nice error message if there's already a trigger of the same
479
* name. (The unique index on tgrelid/tgname would complain anyway.) We
480
* can skip this for internally generated triggers, since the name
481
* modification above should be sufficient.
483
* NOTE that this is cool only because we have ShareRowExclusiveLock on
484
* the relation, so the trigger set won't be changing underneath us.
489
Anum_pg_trigger_tgrelid,
490
BTEqualStrategyNumber, F_OIDEQ,
491
ObjectIdGetDatum(RelationGetRelid(rel)));
492
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
493
SnapshotNow, 1, &key);
494
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
496
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
498
if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
500
(errcode(ERRCODE_DUPLICATE_OBJECT),
501
errmsg("trigger \"%s\" for relation \"%s\" already exists",
502
trigname, stmt->relation->relname)));
504
systable_endscan(tgscan);
508
* Build the new pg_trigger tuple.
510
memset(nulls, false, sizeof(nulls));
512
values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
513
values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
514
CStringGetDatum(trigname));
515
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
516
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
517
values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
518
values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
519
values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
520
values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
521
values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
522
values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
523
values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
529
int16 nargs = list_length(stmt->args);
532
foreach(le, stmt->args)
534
char *ar = strVal(lfirst(le));
536
len += strlen(ar) + 4;
543
args = (char *) palloc(len + 1);
545
foreach(le, stmt->args)
547
char *s = strVal(lfirst(le));
548
char *d = args + strlen(args);
558
values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
559
values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
560
CStringGetDatum(args));
564
values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
565
values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
566
CStringGetDatum(""));
569
/* build column number array if it's a column-specific trigger */
570
ncolumns = list_length(stmt->columns);
578
columns = (int2 *) palloc(ncolumns * sizeof(int2));
579
foreach(cell, stmt->columns)
581
char *name = strVal(lfirst(cell));
585
/* Lookup column name. System columns are not allowed */
586
attnum = attnameAttNum(rel, name, false);
587
if (attnum == InvalidAttrNumber)
589
(errcode(ERRCODE_UNDEFINED_COLUMN),
590
errmsg("column \"%s\" of relation \"%s\" does not exist",
591
name, RelationGetRelationName(rel))));
593
/* Check for duplicates */
594
for (j = i - 1; j >= 0; j--)
596
if (columns[j] == attnum)
598
(errcode(ERRCODE_DUPLICATE_COLUMN),
599
errmsg("column \"%s\" specified more than once",
603
columns[i++] = attnum;
606
tgattr = buildint2vector(columns, ncolumns);
607
values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
609
/* set tgqual if trigger has WHEN clause */
611
values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
613
nulls[Anum_pg_trigger_tgqual - 1] = true;
615
tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
617
/* force tuple to have the desired OID */
618
HeapTupleSetOid(tuple, trigoid);
621
* Insert tuple into pg_trigger.
623
simple_heap_insert(tgrel, tuple);
625
CatalogUpdateIndexes(tgrel, tuple);
627
heap_freetuple(tuple);
628
heap_close(tgrel, RowExclusiveLock);
630
pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
631
pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
632
pfree(DatumGetPointer(values[Anum_pg_trigger_tgattr - 1]));
635
* Update relation's pg_class entry. Crucial side-effect: other backends
636
* (and this one too!) are sent SI message to make them rebuild relcache
639
pgrel = heap_open(RelationRelationId, RowExclusiveLock);
640
tuple = SearchSysCacheCopy1(RELOID,
641
ObjectIdGetDatum(RelationGetRelid(rel)));
642
if (!HeapTupleIsValid(tuple))
643
elog(ERROR, "cache lookup failed for relation %u",
644
RelationGetRelid(rel));
646
((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
648
simple_heap_update(pgrel, &tuple->t_self, tuple);
650
CatalogUpdateIndexes(pgrel, tuple);
652
heap_freetuple(tuple);
653
heap_close(pgrel, RowExclusiveLock);
656
* We used to try to update the rel's relcache entry here, but that's
657
* fairly pointless since it will happen as a byproduct of the upcoming
658
* CommandCounterIncrement...
662
* Record dependencies for trigger. Always place a normal dependency on
665
myself.classId = TriggerRelationId;
666
myself.objectId = trigoid;
667
myself.objectSubId = 0;
669
referenced.classId = ProcedureRelationId;
670
referenced.objectId = funcoid;
671
referenced.objectSubId = 0;
672
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
674
if (isInternal && OidIsValid(constraintOid))
677
* Internally-generated trigger for a constraint, so make it an
678
* internal dependency of the constraint. We can skip depending on
679
* the relation(s), as there'll be an indirect dependency via the
682
referenced.classId = ConstraintRelationId;
683
referenced.objectId = constraintOid;
684
referenced.objectSubId = 0;
685
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
690
* User CREATE TRIGGER, so place dependencies. We make trigger be
691
* auto-dropped if its relation is dropped or if the FK relation is
692
* dropped. (Auto drop is compatible with our pre-7.3 behavior.)
694
referenced.classId = RelationRelationId;
695
referenced.objectId = RelationGetRelid(rel);
696
referenced.objectSubId = 0;
697
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
698
if (OidIsValid(constrrelid))
700
referenced.classId = RelationRelationId;
701
referenced.objectId = constrrelid;
702
referenced.objectSubId = 0;
703
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
705
/* Not possible to have an index dependency in this case */
706
Assert(!OidIsValid(indexOid));
709
* If it's a user-specified constraint trigger, make the constraint
710
* internally dependent on the trigger instead of vice versa.
712
if (OidIsValid(constraintOid))
714
referenced.classId = ConstraintRelationId;
715
referenced.objectId = constraintOid;
716
referenced.objectSubId = 0;
717
recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
721
/* If column-specific trigger, add normal dependencies on columns */
726
referenced.classId = RelationRelationId;
727
referenced.objectId = RelationGetRelid(rel);
728
for (i = 0; i < ncolumns; i++)
730
referenced.objectSubId = columns[i];
731
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
736
* If it has a WHEN clause, add dependencies on objects mentioned in the
737
* expression (eg, functions, as well as any columns used).
739
if (whenClause != NULL)
740
recordDependencyOnExpr(&myself, whenClause, whenRtable,
743
/* Post creation hook for new trigger */
744
InvokeObjectAccessHook(OAT_POST_CREATE,
745
TriggerRelationId, trigoid, 0);
747
/* Keep lock on target rel until end of xact */
748
heap_close(rel, NoLock);
755
* Convert legacy (pre-7.3) CREATE CONSTRAINT TRIGGER commands into
756
* full-fledged foreign key constraints.
758
* The conversion is complex because a pre-7.3 foreign key involved three
759
* separate triggers, which were reported separately in dumps. While the
760
* single trigger on the referencing table adds no new information, we need
761
* to know the trigger functions of both of the triggers on the referenced
762
* table to build the constraint declaration. Also, due to lack of proper
763
* dependency checking pre-7.3, it is possible that the source database had
764
* an incomplete set of triggers resulting in an only partially enforced
765
* FK constraint. (This would happen if one of the tables had been dropped
766
* and re-created, but only if the DB had been affected by a 7.0 pg_dump bug
767
* that caused loss of tgconstrrelid information.) We choose to translate to
768
* an FK constraint only when we've seen all three triggers of a set. This is
769
* implemented by storing unmatched items in a list in TopMemoryContext.
770
* We match triggers together by comparing the trigger arguments (which
771
* include constraint name, table and column names, so should be good enough).
775
List *args; /* list of (T_String) Values or NIL */
776
Oid funcoids[3]; /* OIDs of trigger functions */
777
/* The three function OIDs are stored in the order update, delete, child */
781
ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
783
static List *info_list = NIL;
785
static const char *const funcdescr[3] = {
786
gettext_noop("Found referenced table's UPDATE trigger."),
787
gettext_noop("Found referenced table's DELETE trigger."),
788
gettext_noop("Found referencing table's trigger.")
794
char fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED;
795
List *fk_attrs = NIL;
796
List *pk_attrs = NIL;
799
OldTriggerInfo *info = NULL;
803
/* Parse out the trigger arguments */
804
constr_name = strVal(linitial(stmt->args));
805
fk_table_name = strVal(lsecond(stmt->args));
806
pk_table_name = strVal(lthird(stmt->args));
808
foreach(l, stmt->args)
810
Value *arg = (Value *) lfirst(l);
813
if (i < 4) /* skip constraint and table names */
815
if (i == 4) /* handle match type */
817
if (strcmp(strVal(arg), "FULL") == 0)
818
fk_matchtype = FKCONSTR_MATCH_FULL;
820
fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED;
824
fk_attrs = lappend(fk_attrs, arg);
826
pk_attrs = lappend(pk_attrs, arg);
829
/* Prepare description of constraint for use in messages */
830
initStringInfo(&buf);
831
appendStringInfo(&buf, "FOREIGN KEY %s(",
832
quote_identifier(fk_table_name));
836
Value *arg = (Value *) lfirst(l);
839
appendStringInfoChar(&buf, ',');
840
appendStringInfoString(&buf, quote_identifier(strVal(arg)));
842
appendStringInfo(&buf, ") REFERENCES %s(",
843
quote_identifier(pk_table_name));
847
Value *arg = (Value *) lfirst(l);
850
appendStringInfoChar(&buf, ',');
851
appendStringInfoString(&buf, quote_identifier(strVal(arg)));
853
appendStringInfoChar(&buf, ')');
855
/* Identify class of trigger --- update, delete, or referencing-table */
858
case F_RI_FKEY_CASCADE_UPD:
859
case F_RI_FKEY_RESTRICT_UPD:
860
case F_RI_FKEY_SETNULL_UPD:
861
case F_RI_FKEY_SETDEFAULT_UPD:
862
case F_RI_FKEY_NOACTION_UPD:
866
case F_RI_FKEY_CASCADE_DEL:
867
case F_RI_FKEY_RESTRICT_DEL:
868
case F_RI_FKEY_SETNULL_DEL:
869
case F_RI_FKEY_SETDEFAULT_DEL:
870
case F_RI_FKEY_NOACTION_DEL:
879
/* See if we have a match to this trigger */
880
foreach(l, info_list)
882
info = (OldTriggerInfo *) lfirst(l);
883
if (info->funcoids[funcnum] == InvalidOid &&
884
equal(info->args, stmt->args))
886
info->funcoids[funcnum] = funcoid;
893
/* First trigger of set, so create a new list entry */
894
MemoryContext oldContext;
897
(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
898
constr_name, buf.data),
899
errdetail("%s", _(funcdescr[funcnum]))));
900
oldContext = MemoryContextSwitchTo(TopMemoryContext);
901
info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
902
info->args = copyObject(stmt->args);
903
info->funcoids[funcnum] = funcoid;
904
info_list = lappend(info_list, info);
905
MemoryContextSwitchTo(oldContext);
907
else if (info->funcoids[0] == InvalidOid ||
908
info->funcoids[1] == InvalidOid ||
909
info->funcoids[2] == InvalidOid)
911
/* Second trigger of set */
913
(errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
914
constr_name, buf.data),
915
errdetail("%s", _(funcdescr[funcnum]))));
919
/* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
920
AlterTableStmt *atstmt = makeNode(AlterTableStmt);
921
AlterTableCmd *atcmd = makeNode(AlterTableCmd);
922
Constraint *fkcon = makeNode(Constraint);
925
(errmsg("converting trigger group into constraint \"%s\" %s",
926
constr_name, buf.data),
927
errdetail("%s", _(funcdescr[funcnum]))));
928
fkcon->contype = CONSTR_FOREIGN;
929
fkcon->location = -1;
932
/* This trigger is on the FK table */
933
atstmt->relation = stmt->relation;
935
fkcon->pktable = stmt->constrrel;
938
/* Work around ancient pg_dump bug that omitted constrrel */
939
fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
944
/* This trigger is on the PK table */
945
fkcon->pktable = stmt->relation;
947
atstmt->relation = stmt->constrrel;
950
/* Work around ancient pg_dump bug that omitted constrrel */
951
atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
954
atstmt->cmds = list_make1(atcmd);
955
atstmt->relkind = OBJECT_TABLE;
956
atcmd->subtype = AT_AddConstraint;
957
atcmd->def = (Node *) fkcon;
958
if (strcmp(constr_name, "<unnamed>") == 0)
959
fkcon->conname = NULL;
961
fkcon->conname = constr_name;
962
fkcon->fk_attrs = fk_attrs;
963
fkcon->pk_attrs = pk_attrs;
964
fkcon->fk_matchtype = fk_matchtype;
965
switch (info->funcoids[0])
967
case F_RI_FKEY_NOACTION_UPD:
968
fkcon->fk_upd_action = FKCONSTR_ACTION_NOACTION;
970
case F_RI_FKEY_CASCADE_UPD:
971
fkcon->fk_upd_action = FKCONSTR_ACTION_CASCADE;
973
case F_RI_FKEY_RESTRICT_UPD:
974
fkcon->fk_upd_action = FKCONSTR_ACTION_RESTRICT;
976
case F_RI_FKEY_SETNULL_UPD:
977
fkcon->fk_upd_action = FKCONSTR_ACTION_SETNULL;
979
case F_RI_FKEY_SETDEFAULT_UPD:
980
fkcon->fk_upd_action = FKCONSTR_ACTION_SETDEFAULT;
983
/* can't get here because of earlier checks */
984
elog(ERROR, "confused about RI update function");
986
switch (info->funcoids[1])
988
case F_RI_FKEY_NOACTION_DEL:
989
fkcon->fk_del_action = FKCONSTR_ACTION_NOACTION;
991
case F_RI_FKEY_CASCADE_DEL:
992
fkcon->fk_del_action = FKCONSTR_ACTION_CASCADE;
994
case F_RI_FKEY_RESTRICT_DEL:
995
fkcon->fk_del_action = FKCONSTR_ACTION_RESTRICT;
997
case F_RI_FKEY_SETNULL_DEL:
998
fkcon->fk_del_action = FKCONSTR_ACTION_SETNULL;
1000
case F_RI_FKEY_SETDEFAULT_DEL:
1001
fkcon->fk_del_action = FKCONSTR_ACTION_SETDEFAULT;
1004
/* can't get here because of earlier checks */
1005
elog(ERROR, "confused about RI delete function");
1007
fkcon->deferrable = stmt->deferrable;
1008
fkcon->initdeferred = stmt->initdeferred;
1010
/* ... and execute it */
1011
ProcessUtility((Node *) atstmt,
1012
"(generated ALTER TABLE ADD FOREIGN KEY command)",
1013
NULL, false, None_Receiver, NULL);
1015
/* Remove the matched item from the list */
1016
info_list = list_delete_ptr(info_list, info);
1018
/* We leak the copied args ... not worth worrying about */
1024
* DropTrigger - drop an individual trigger by name
1027
DropTrigger(Oid relid, const char *trigname, DropBehavior behavior,
1030
ObjectAddress object;
1032
object.classId = TriggerRelationId;
1033
object.objectId = get_trigger_oid(relid, trigname, missing_ok);
1034
object.objectSubId = 0;
1036
if (!OidIsValid(object.objectId))
1039
(errmsg("trigger \"%s\" for table \"%s\" does not exist, skipping",
1040
trigname, get_rel_name(relid))));
1044
if (!pg_class_ownercheck(relid, GetUserId()))
1045
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
1046
get_rel_name(relid));
1051
performDeletion(&object, behavior);
1055
* Guts of trigger deletion.
1058
RemoveTriggerById(Oid trigOid)
1062
ScanKeyData skey[1];
1067
tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
1070
* Find the trigger to delete.
1072
ScanKeyInit(&skey[0],
1073
ObjectIdAttributeNumber,
1074
BTEqualStrategyNumber, F_OIDEQ,
1075
ObjectIdGetDatum(trigOid));
1077
tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
1078
SnapshotNow, 1, skey);
1080
tup = systable_getnext(tgscan);
1081
if (!HeapTupleIsValid(tup))
1082
elog(ERROR, "could not find tuple for trigger %u", trigOid);
1085
* Open and lock the relation the trigger belongs to. As in
1086
* CreateTrigger, this is sufficient to lock out all operations that could
1087
* fire or add triggers; but it would need to be revisited if we had ON
1090
relid = ((Form_pg_trigger) GETSTRUCT(tup))->tgrelid;
1092
rel = heap_open(relid, ShareRowExclusiveLock);
1094
if (rel->rd_rel->relkind != RELKIND_RELATION &&
1095
rel->rd_rel->relkind != RELKIND_VIEW)
1097
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1098
errmsg("\"%s\" is not a table or view",
1099
RelationGetRelationName(rel))));
1101
if (!allowSystemTableMods && IsSystemRelation(rel))
1103
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1104
errmsg("permission denied: \"%s\" is a system catalog",
1105
RelationGetRelationName(rel))));
1108
* Delete the pg_trigger tuple.
1110
simple_heap_delete(tgrel, &tup->t_self);
1112
systable_endscan(tgscan);
1113
heap_close(tgrel, RowExclusiveLock);
1116
* We do not bother to try to determine whether any other triggers remain,
1117
* which would be needed in order to decide whether it's safe to clear the
1118
* relation's relhastriggers. (In any case, there might be a concurrent
1119
* process adding new triggers.) Instead, just force a relcache inval to
1120
* make other backends (and this one too!) rebuild their relcache entries.
1121
* There's no great harm in leaving relhastriggers true even if there are
1124
CacheInvalidateRelcache(rel);
1126
/* Keep lock on trigger's rel until end of xact */
1127
heap_close(rel, NoLock);
1131
* get_trigger_oid - Look up a trigger by name to find its OID.
1133
* If missing_ok is false, throw an error if trigger not found. If
1134
* true, just return InvalidOid.
1137
get_trigger_oid(Oid relid, const char *trigname, bool missing_ok)
1140
ScanKeyData skey[2];
1146
* Find the trigger, verify permissions, set up object address
1148
tgrel = heap_open(TriggerRelationId, AccessShareLock);
1150
ScanKeyInit(&skey[0],
1151
Anum_pg_trigger_tgrelid,
1152
BTEqualStrategyNumber, F_OIDEQ,
1153
ObjectIdGetDatum(relid));
1154
ScanKeyInit(&skey[1],
1155
Anum_pg_trigger_tgname,
1156
BTEqualStrategyNumber, F_NAMEEQ,
1157
CStringGetDatum(trigname));
1159
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1160
SnapshotNow, 2, skey);
1162
tup = systable_getnext(tgscan);
1164
if (!HeapTupleIsValid(tup))
1168
(errcode(ERRCODE_UNDEFINED_OBJECT),
1169
errmsg("trigger \"%s\" for table \"%s\" does not exist",
1170
trigname, get_rel_name(relid))));
1175
oid = HeapTupleGetOid(tup);
1178
systable_endscan(tgscan);
1179
heap_close(tgrel, AccessShareLock);
1184
* renametrig - changes the name of a trigger on a relation
1186
* trigger name is changed in trigger catalog.
1187
* No record of the previous name is kept.
1189
* get proper relrelation from relation catalog (if not arg)
1190
* scan trigger catalog
1191
* for name conflict (within rel)
1192
* for original trigger (if not arg)
1193
* modify tgname in trigger tuple
1194
* update row in catalog
1197
renametrig(Oid relid,
1198
const char *oldname,
1199
const char *newname)
1208
* Grab an exclusive lock on the target table, which we will NOT release
1209
* until end of transaction.
1211
targetrel = heap_open(relid, AccessExclusiveLock);
1214
* Scan pg_trigger twice for existing triggers on relation. We do this in
1215
* order to ensure a trigger does not exist with newname (The unique index
1216
* on tgrelid/tgname would complain anyway) and to ensure a trigger does
1217
* exist with oldname.
1219
* NOTE that this is cool only because we have AccessExclusiveLock on the
1220
* relation, so the trigger set won't be changing underneath us.
1222
tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
1225
* First pass -- look for name conflict
1227
ScanKeyInit(&key[0],
1228
Anum_pg_trigger_tgrelid,
1229
BTEqualStrategyNumber, F_OIDEQ,
1230
ObjectIdGetDatum(relid));
1231
ScanKeyInit(&key[1],
1232
Anum_pg_trigger_tgname,
1233
BTEqualStrategyNumber, F_NAMEEQ,
1234
PointerGetDatum(newname));
1235
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1236
SnapshotNow, 2, key);
1237
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1239
(errcode(ERRCODE_DUPLICATE_OBJECT),
1240
errmsg("trigger \"%s\" for relation \"%s\" already exists",
1241
newname, RelationGetRelationName(targetrel))));
1242
systable_endscan(tgscan);
1245
* Second pass -- look for trigger existing with oldname and update
1247
ScanKeyInit(&key[0],
1248
Anum_pg_trigger_tgrelid,
1249
BTEqualStrategyNumber, F_OIDEQ,
1250
ObjectIdGetDatum(relid));
1251
ScanKeyInit(&key[1],
1252
Anum_pg_trigger_tgname,
1253
BTEqualStrategyNumber, F_NAMEEQ,
1254
PointerGetDatum(oldname));
1255
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1256
SnapshotNow, 2, key);
1257
if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1260
* Update pg_trigger tuple with new tgname.
1262
tuple = heap_copytuple(tuple); /* need a modifiable copy */
1264
namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname, newname);
1266
simple_heap_update(tgrel, &tuple->t_self, tuple);
1268
/* keep system catalog indexes current */
1269
CatalogUpdateIndexes(tgrel, tuple);
1272
* Invalidate relation's relcache entry so that other backends (and
1273
* this one too!) are sent SI message to make them rebuild relcache
1274
* entries. (Ideally this should happen automatically...)
1276
CacheInvalidateRelcache(targetrel);
1281
(errcode(ERRCODE_UNDEFINED_OBJECT),
1282
errmsg("trigger \"%s\" for table \"%s\" does not exist",
1283
oldname, RelationGetRelationName(targetrel))));
1286
systable_endscan(tgscan);
1288
heap_close(tgrel, RowExclusiveLock);
1291
* Close rel, but keep exclusive lock!
1293
heap_close(targetrel, NoLock);
1298
* EnableDisableTrigger()
1300
* Called by ALTER TABLE ENABLE/DISABLE [ REPLICA | ALWAYS ] TRIGGER
1301
* to change 'tgenabled' field for the specified trigger(s)
1303
* rel: relation to process (caller must hold suitable lock on it)
1304
* tgname: trigger to process, or NULL to scan all triggers
1305
* fires_when: new value for tgenabled field. In addition to generic
1306
* enablement/disablement, this also defines when the trigger
1307
* should be fired in session replication roles.
1308
* skip_system: if true, skip "system" triggers (constraint triggers)
1310
* Caller should have checked permissions for the table; here we also
1311
* enforce that superuser privilege is required to alter the state of
1315
EnableDisableTrigger(Relation rel, const char *tgname,
1316
char fires_when, bool skip_system)
1320
ScanKeyData keys[2];
1326
/* Scan the relevant entries in pg_triggers */
1327
tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
1329
ScanKeyInit(&keys[0],
1330
Anum_pg_trigger_tgrelid,
1331
BTEqualStrategyNumber, F_OIDEQ,
1332
ObjectIdGetDatum(RelationGetRelid(rel)));
1335
ScanKeyInit(&keys[1],
1336
Anum_pg_trigger_tgname,
1337
BTEqualStrategyNumber, F_NAMEEQ,
1338
CStringGetDatum(tgname));
1344
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1345
SnapshotNow, nkeys, keys);
1347
found = changed = false;
1349
while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1351
Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1353
if (oldtrig->tgisinternal)
1355
/* system trigger ... ok to process? */
1360
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1361
errmsg("permission denied: \"%s\" is a system trigger",
1362
NameStr(oldtrig->tgname))));
1367
if (oldtrig->tgenabled != fires_when)
1369
/* need to change this one ... make a copy to scribble on */
1370
HeapTuple newtup = heap_copytuple(tuple);
1371
Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1373
newtrig->tgenabled = fires_when;
1375
simple_heap_update(tgrel, &newtup->t_self, newtup);
1377
/* Keep catalog indexes current */
1378
CatalogUpdateIndexes(tgrel, newtup);
1380
heap_freetuple(newtup);
1386
systable_endscan(tgscan);
1388
heap_close(tgrel, RowExclusiveLock);
1390
if (tgname && !found)
1392
(errcode(ERRCODE_UNDEFINED_OBJECT),
1393
errmsg("trigger \"%s\" for table \"%s\" does not exist",
1394
tgname, RelationGetRelationName(rel))));
1397
* If we changed anything, broadcast a SI inval message to force each
1398
* backend (including our own!) to rebuild relation's relcache entry.
1399
* Otherwise they will fail to apply the change promptly.
1402
CacheInvalidateRelcache(rel);
1407
* Build trigger data to attach to the given relcache entry.
1409
* Note that trigger data attached to a relcache entry must be stored in
1410
* CacheMemoryContext to ensure it survives as long as the relcache entry.
1411
* But we should be running in a less long-lived working context. To avoid
1412
* leaking cache memory if this routine fails partway through, we build a
1413
* temporary TriggerDesc in working memory and then copy the completed
1414
* structure into cache memory.
1417
RelationBuildTriggers(Relation relation)
1419
TriggerDesc *trigdesc;
1427
MemoryContext oldContext;
1431
* Allocate a working array to hold the triggers (the array is extended if
1435
triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
1439
* Note: since we scan the triggers using TriggerRelidNameIndexId, we will
1440
* be reading the triggers in name order, except possibly during
1441
* emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
1442
* ensures that triggers will be fired in name order.
1445
Anum_pg_trigger_tgrelid,
1446
BTEqualStrategyNumber, F_OIDEQ,
1447
ObjectIdGetDatum(RelationGetRelid(relation)));
1449
tgrel = heap_open(TriggerRelationId, AccessShareLock);
1450
tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1451
SnapshotNow, 1, &skey);
1453
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
1455
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1460
if (numtrigs >= maxtrigs)
1463
triggers = (Trigger *) repalloc(triggers, maxtrigs * sizeof(Trigger));
1465
build = &(triggers[numtrigs]);
1467
build->tgoid = HeapTupleGetOid(htup);
1468
build->tgname = DatumGetCString(DirectFunctionCall1(nameout,
1469
NameGetDatum(&pg_trigger->tgname)));
1470
build->tgfoid = pg_trigger->tgfoid;
1471
build->tgtype = pg_trigger->tgtype;
1472
build->tgenabled = pg_trigger->tgenabled;
1473
build->tgisinternal = pg_trigger->tgisinternal;
1474
build->tgconstrrelid = pg_trigger->tgconstrrelid;
1475
build->tgconstrindid = pg_trigger->tgconstrindid;
1476
build->tgconstraint = pg_trigger->tgconstraint;
1477
build->tgdeferrable = pg_trigger->tgdeferrable;
1478
build->tginitdeferred = pg_trigger->tginitdeferred;
1479
build->tgnargs = pg_trigger->tgnargs;
1480
/* tgattr is first var-width field, so OK to access directly */
1481
build->tgnattr = pg_trigger->tgattr.dim1;
1482
if (build->tgnattr > 0)
1484
build->tgattr = (int2 *) palloc(build->tgnattr * sizeof(int2));
1485
memcpy(build->tgattr, &(pg_trigger->tgattr.values),
1486
build->tgnattr * sizeof(int2));
1489
build->tgattr = NULL;
1490
if (build->tgnargs > 0)
1495
val = DatumGetByteaP(fastgetattr(htup,
1496
Anum_pg_trigger_tgargs,
1497
tgrel->rd_att, &isnull));
1499
elog(ERROR, "tgargs is null in trigger for relation \"%s\"",
1500
RelationGetRelationName(relation));
1501
p = (char *) VARDATA(val);
1502
build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
1503
for (i = 0; i < build->tgnargs; i++)
1505
build->tgargs[i] = pstrdup(p);
1510
build->tgargs = NULL;
1511
datum = fastgetattr(htup, Anum_pg_trigger_tgqual,
1512
tgrel->rd_att, &isnull);
1514
build->tgqual = TextDatumGetCString(datum);
1516
build->tgqual = NULL;
1521
systable_endscan(tgscan);
1522
heap_close(tgrel, AccessShareLock);
1524
/* There might not be any triggers */
1531
/* Build trigdesc */
1532
trigdesc = (TriggerDesc *) palloc0(sizeof(TriggerDesc));
1533
trigdesc->triggers = triggers;
1534
trigdesc->numtriggers = numtrigs;
1535
for (i = 0; i < numtrigs; i++)
1536
SetTriggerFlags(trigdesc, &(triggers[i]));
1538
/* Copy completed trigdesc into cache storage */
1539
oldContext = MemoryContextSwitchTo(CacheMemoryContext);
1540
relation->trigdesc = CopyTriggerDesc(trigdesc);
1541
MemoryContextSwitchTo(oldContext);
1543
/* Release working memory */
1544
FreeTriggerDesc(trigdesc);
1548
* Update the TriggerDesc's hint flags to include the specified trigger
1551
SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger)
1553
int16 tgtype = trigger->tgtype;
1555
trigdesc->trig_insert_before_row |=
1556
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1557
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
1558
trigdesc->trig_insert_after_row |=
1559
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1560
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
1561
trigdesc->trig_insert_instead_row |=
1562
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1563
TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_INSERT);
1564
trigdesc->trig_insert_before_statement |=
1565
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1566
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
1567
trigdesc->trig_insert_after_statement |=
1568
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1569
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
1570
trigdesc->trig_update_before_row |=
1571
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1572
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
1573
trigdesc->trig_update_after_row |=
1574
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1575
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
1576
trigdesc->trig_update_instead_row |=
1577
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1578
TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_UPDATE);
1579
trigdesc->trig_update_before_statement |=
1580
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1581
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
1582
trigdesc->trig_update_after_statement |=
1583
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1584
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
1585
trigdesc->trig_delete_before_row |=
1586
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1587
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
1588
trigdesc->trig_delete_after_row |=
1589
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1590
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
1591
trigdesc->trig_delete_instead_row |=
1592
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
1593
TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_DELETE);
1594
trigdesc->trig_delete_before_statement |=
1595
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1596
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
1597
trigdesc->trig_delete_after_statement |=
1598
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1599
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
1600
/* there are no row-level truncate triggers */
1601
trigdesc->trig_truncate_before_statement |=
1602
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1603
TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_TRUNCATE);
1604
trigdesc->trig_truncate_after_statement |=
1605
TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
1606
TRIGGER_TYPE_AFTER, TRIGGER_TYPE_TRUNCATE);
1610
* Copy a TriggerDesc data structure.
1612
* The copy is allocated in the current memory context.
1615
CopyTriggerDesc(TriggerDesc *trigdesc)
1617
TriggerDesc *newdesc;
1621
if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1624
newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1625
memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1627
trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1628
memcpy(trigger, trigdesc->triggers,
1629
trigdesc->numtriggers * sizeof(Trigger));
1630
newdesc->triggers = trigger;
1632
for (i = 0; i < trigdesc->numtriggers; i++)
1634
trigger->tgname = pstrdup(trigger->tgname);
1635
if (trigger->tgnattr > 0)
1639
newattr = (int2 *) palloc(trigger->tgnattr * sizeof(int2));
1640
memcpy(newattr, trigger->tgattr,
1641
trigger->tgnattr * sizeof(int2));
1642
trigger->tgattr = newattr;
1644
if (trigger->tgnargs > 0)
1649
newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1650
for (j = 0; j < trigger->tgnargs; j++)
1651
newargs[j] = pstrdup(trigger->tgargs[j]);
1652
trigger->tgargs = newargs;
1654
if (trigger->tgqual)
1655
trigger->tgqual = pstrdup(trigger->tgqual);
1663
* Free a TriggerDesc data structure.
1666
FreeTriggerDesc(TriggerDesc *trigdesc)
1671
if (trigdesc == NULL)
1674
trigger = trigdesc->triggers;
1675
for (i = 0; i < trigdesc->numtriggers; i++)
1677
pfree(trigger->tgname);
1678
if (trigger->tgnattr > 0)
1679
pfree(trigger->tgattr);
1680
if (trigger->tgnargs > 0)
1682
while (--(trigger->tgnargs) >= 0)
1683
pfree(trigger->tgargs[trigger->tgnargs]);
1684
pfree(trigger->tgargs);
1686
if (trigger->tgqual)
1687
pfree(trigger->tgqual);
1690
pfree(trigdesc->triggers);
1695
* Compare two TriggerDesc structures for logical equality.
1699
equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
1705
* We need not examine the hint flags, just the trigger array itself; if
1706
* we have the same triggers with the same types, the flags should match.
1708
* As of 7.3 we assume trigger set ordering is significant in the
1709
* comparison; so we just compare corresponding slots of the two sets.
1711
* Note: comparing the stringToNode forms of the WHEN clauses means that
1712
* parse column locations will affect the result. This is okay as long as
1713
* this function is only used for detecting exact equality, as for example
1714
* in checking for staleness of a cache entry.
1716
if (trigdesc1 != NULL)
1718
if (trigdesc2 == NULL)
1720
if (trigdesc1->numtriggers != trigdesc2->numtriggers)
1722
for (i = 0; i < trigdesc1->numtriggers; i++)
1724
Trigger *trig1 = trigdesc1->triggers + i;
1725
Trigger *trig2 = trigdesc2->triggers + i;
1727
if (trig1->tgoid != trig2->tgoid)
1729
if (strcmp(trig1->tgname, trig2->tgname) != 0)
1731
if (trig1->tgfoid != trig2->tgfoid)
1733
if (trig1->tgtype != trig2->tgtype)
1735
if (trig1->tgenabled != trig2->tgenabled)
1737
if (trig1->tgisinternal != trig2->tgisinternal)
1739
if (trig1->tgconstrrelid != trig2->tgconstrrelid)
1741
if (trig1->tgconstrindid != trig2->tgconstrindid)
1743
if (trig1->tgconstraint != trig2->tgconstraint)
1745
if (trig1->tgdeferrable != trig2->tgdeferrable)
1747
if (trig1->tginitdeferred != trig2->tginitdeferred)
1749
if (trig1->tgnargs != trig2->tgnargs)
1751
if (trig1->tgnattr != trig2->tgnattr)
1753
if (trig1->tgnattr > 0 &&
1754
memcmp(trig1->tgattr, trig2->tgattr,
1755
trig1->tgnattr * sizeof(int2)) != 0)
1757
for (j = 0; j < trig1->tgnargs; j++)
1758
if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
1760
if (trig1->tgqual == NULL && trig2->tgqual == NULL)
1762
else if (trig1->tgqual == NULL || trig2->tgqual == NULL)
1764
else if (strcmp(trig1->tgqual, trig2->tgqual) != 0)
1768
else if (trigdesc2 != NULL)
1772
#endif /* NOT_USED */
1775
* Call a trigger function.
1777
* trigdata: trigger descriptor.
1778
* tgindx: trigger's index in finfo and instr arrays.
1779
* finfo: array of cached trigger function call information.
1780
* instr: optional array of EXPLAIN ANALYZE instrumentation state.
1781
* per_tuple_context: memory context to execute the function in.
1783
* Returns the tuple (or NULL) as returned by the function.
1786
ExecCallTriggerFunc(TriggerData *trigdata,
1789
Instrumentation *instr,
1790
MemoryContext per_tuple_context)
1792
FunctionCallInfoData fcinfo;
1793
PgStat_FunctionCallUsage fcusage;
1795
MemoryContext oldContext;
1800
* We cache fmgr lookup info, to avoid making the lookup again on each
1803
if (finfo->fn_oid == InvalidOid)
1804
fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
1806
Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
1809
* If doing EXPLAIN ANALYZE, start charging time to this trigger.
1812
InstrStartNode(instr + tgindx);
1815
* Do the function evaluation in the per-tuple memory context, so that
1816
* leaked memory will be reclaimed once per tuple. Note in particular that
1817
* any new tuple created by the trigger function will live till the end of
1820
oldContext = MemoryContextSwitchTo(per_tuple_context);
1823
* Call the function, passing no arguments but setting a context.
1825
InitFunctionCallInfoData(fcinfo, finfo, 0,
1826
InvalidOid, (Node *) trigdata, NULL);
1828
pgstat_init_function_usage(&fcinfo, &fcusage);
1830
result = FunctionCallInvoke(&fcinfo);
1832
pgstat_end_function_usage(&fcusage, true);
1834
MemoryContextSwitchTo(oldContext);
1837
* Trigger protocol allows function to return a null pointer, but NOT to
1838
* set the isnull result flag.
1842
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1843
errmsg("trigger function %u returned null value",
1844
fcinfo.flinfo->fn_oid)));
1847
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
1848
* one "tuple returned" (really the number of firings).
1851
InstrStopNode(instr + tgindx, 1);
1853
return (HeapTuple) DatumGetPointer(result);
1857
ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
1859
TriggerDesc *trigdesc;
1861
TriggerData LocTriggerData;
1863
trigdesc = relinfo->ri_TrigDesc;
1865
if (trigdesc == NULL)
1867
if (!trigdesc->trig_insert_before_statement)
1870
LocTriggerData.type = T_TriggerData;
1871
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
1872
TRIGGER_EVENT_BEFORE;
1873
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
1874
LocTriggerData.tg_trigtuple = NULL;
1875
LocTriggerData.tg_newtuple = NULL;
1876
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
1877
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
1878
for (i = 0; i < trigdesc->numtriggers; i++)
1880
Trigger *trigger = &trigdesc->triggers[i];
1883
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
1884
TRIGGER_TYPE_STATEMENT,
1885
TRIGGER_TYPE_BEFORE,
1886
TRIGGER_TYPE_INSERT))
1888
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
1892
LocTriggerData.tg_trigger = trigger;
1893
newtuple = ExecCallTriggerFunc(&LocTriggerData,
1895
relinfo->ri_TrigFunctions,
1896
relinfo->ri_TrigInstrument,
1897
GetPerTupleMemoryContext(estate));
1901
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1902
errmsg("BEFORE STATEMENT trigger cannot return a value")));
1907
ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
1909
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1911
if (trigdesc && trigdesc->trig_insert_after_statement)
1912
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
1913
false, NULL, NULL, NIL, NULL);
1917
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
1918
TupleTableSlot *slot)
1920
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1921
HeapTuple slottuple = ExecMaterializeSlot(slot);
1922
HeapTuple newtuple = slottuple;
1924
TriggerData LocTriggerData;
1927
LocTriggerData.type = T_TriggerData;
1928
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
1930
TRIGGER_EVENT_BEFORE;
1931
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
1932
LocTriggerData.tg_newtuple = NULL;
1933
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
1934
for (i = 0; i < trigdesc->numtriggers; i++)
1936
Trigger *trigger = &trigdesc->triggers[i];
1938
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
1940
TRIGGER_TYPE_BEFORE,
1941
TRIGGER_TYPE_INSERT))
1943
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
1944
NULL, NULL, newtuple))
1947
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
1948
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
1949
LocTriggerData.tg_trigger = trigger;
1950
newtuple = ExecCallTriggerFunc(&LocTriggerData,
1952
relinfo->ri_TrigFunctions,
1953
relinfo->ri_TrigInstrument,
1954
GetPerTupleMemoryContext(estate));
1955
if (oldtuple != newtuple && oldtuple != slottuple)
1956
heap_freetuple(oldtuple);
1957
if (newtuple == NULL)
1958
return NULL; /* "do nothing" */
1961
if (newtuple != slottuple)
1964
* Return the modified tuple using the es_trig_tuple_slot. We assume
1965
* the tuple was allocated in per-tuple memory context, and therefore
1966
* will go away by itself. The tuple table slot should not try to
1969
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
1970
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
1972
if (newslot->tts_tupleDescriptor != tupdesc)
1973
ExecSetSlotDescriptor(newslot, tupdesc);
1974
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
1981
ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
1982
HeapTuple trigtuple, List *recheckIndexes)
1984
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1986
if (trigdesc && trigdesc->trig_insert_after_row)
1987
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
1988
true, NULL, trigtuple, recheckIndexes, NULL);
1992
ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
1993
TupleTableSlot *slot)
1995
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1996
HeapTuple slottuple = ExecMaterializeSlot(slot);
1997
HeapTuple newtuple = slottuple;
1999
TriggerData LocTriggerData;
2002
LocTriggerData.type = T_TriggerData;
2003
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2005
TRIGGER_EVENT_INSTEAD;
2006
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2007
LocTriggerData.tg_newtuple = NULL;
2008
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2009
for (i = 0; i < trigdesc->numtriggers; i++)
2011
Trigger *trigger = &trigdesc->triggers[i];
2013
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2015
TRIGGER_TYPE_INSTEAD,
2016
TRIGGER_TYPE_INSERT))
2018
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2019
NULL, NULL, newtuple))
2022
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2023
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2024
LocTriggerData.tg_trigger = trigger;
2025
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2027
relinfo->ri_TrigFunctions,
2028
relinfo->ri_TrigInstrument,
2029
GetPerTupleMemoryContext(estate));
2030
if (oldtuple != newtuple && oldtuple != slottuple)
2031
heap_freetuple(oldtuple);
2032
if (newtuple == NULL)
2033
return NULL; /* "do nothing" */
2036
if (newtuple != slottuple)
2039
* Return the modified tuple using the es_trig_tuple_slot. We assume
2040
* the tuple was allocated in per-tuple memory context, and therefore
2041
* will go away by itself. The tuple table slot should not try to
2044
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2045
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2047
if (newslot->tts_tupleDescriptor != tupdesc)
2048
ExecSetSlotDescriptor(newslot, tupdesc);
2049
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2056
ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
2058
TriggerDesc *trigdesc;
2060
TriggerData LocTriggerData;
2062
trigdesc = relinfo->ri_TrigDesc;
2064
if (trigdesc == NULL)
2066
if (!trigdesc->trig_delete_before_statement)
2069
LocTriggerData.type = T_TriggerData;
2070
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2071
TRIGGER_EVENT_BEFORE;
2072
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2073
LocTriggerData.tg_trigtuple = NULL;
2074
LocTriggerData.tg_newtuple = NULL;
2075
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2076
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2077
for (i = 0; i < trigdesc->numtriggers; i++)
2079
Trigger *trigger = &trigdesc->triggers[i];
2082
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2083
TRIGGER_TYPE_STATEMENT,
2084
TRIGGER_TYPE_BEFORE,
2085
TRIGGER_TYPE_DELETE))
2087
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2091
LocTriggerData.tg_trigger = trigger;
2092
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2094
relinfo->ri_TrigFunctions,
2095
relinfo->ri_TrigInstrument,
2096
GetPerTupleMemoryContext(estate));
2100
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2101
errmsg("BEFORE STATEMENT trigger cannot return a value")));
2106
ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
2108
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2110
if (trigdesc && trigdesc->trig_delete_after_statement)
2111
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
2112
false, NULL, NULL, NIL, NULL);
2116
ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
2117
ResultRelInfo *relinfo,
2118
ItemPointer tupleid)
2120
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2122
TriggerData LocTriggerData;
2123
HeapTuple trigtuple;
2125
TupleTableSlot *newSlot;
2128
trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2130
if (trigtuple == NULL)
2133
LocTriggerData.type = T_TriggerData;
2134
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2136
TRIGGER_EVENT_BEFORE;
2137
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2138
LocTriggerData.tg_newtuple = NULL;
2139
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2140
for (i = 0; i < trigdesc->numtriggers; i++)
2142
Trigger *trigger = &trigdesc->triggers[i];
2144
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2146
TRIGGER_TYPE_BEFORE,
2147
TRIGGER_TYPE_DELETE))
2149
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2150
NULL, trigtuple, NULL))
2153
LocTriggerData.tg_trigtuple = trigtuple;
2154
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2155
LocTriggerData.tg_trigger = trigger;
2156
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2158
relinfo->ri_TrigFunctions,
2159
relinfo->ri_TrigInstrument,
2160
GetPerTupleMemoryContext(estate));
2161
if (newtuple == NULL)
2163
result = false; /* tell caller to suppress delete */
2166
if (newtuple != trigtuple)
2167
heap_freetuple(newtuple);
2169
heap_freetuple(trigtuple);
2175
ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
2176
ItemPointer tupleid)
2178
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2180
if (trigdesc && trigdesc->trig_delete_after_row)
2182
HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
2185
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
2186
true, trigtuple, NULL, NIL, NULL);
2187
heap_freetuple(trigtuple);
2192
ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
2193
HeapTuple trigtuple)
2195
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2196
TriggerData LocTriggerData;
2200
LocTriggerData.type = T_TriggerData;
2201
LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2203
TRIGGER_EVENT_INSTEAD;
2204
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2205
LocTriggerData.tg_newtuple = NULL;
2206
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2207
for (i = 0; i < trigdesc->numtriggers; i++)
2209
Trigger *trigger = &trigdesc->triggers[i];
2211
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2213
TRIGGER_TYPE_INSTEAD,
2214
TRIGGER_TYPE_DELETE))
2216
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2217
NULL, trigtuple, NULL))
2220
LocTriggerData.tg_trigtuple = trigtuple;
2221
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2222
LocTriggerData.tg_trigger = trigger;
2223
rettuple = ExecCallTriggerFunc(&LocTriggerData,
2225
relinfo->ri_TrigFunctions,
2226
relinfo->ri_TrigInstrument,
2227
GetPerTupleMemoryContext(estate));
2228
if (rettuple == NULL)
2229
return false; /* Delete was suppressed */
2230
if (rettuple != trigtuple)
2231
heap_freetuple(rettuple);
2237
ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
2239
TriggerDesc *trigdesc;
2241
TriggerData LocTriggerData;
2242
Bitmapset *modifiedCols;
2244
trigdesc = relinfo->ri_TrigDesc;
2246
if (trigdesc == NULL)
2248
if (!trigdesc->trig_update_before_statement)
2251
modifiedCols = GetModifiedColumns(relinfo, estate);
2253
LocTriggerData.type = T_TriggerData;
2254
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2255
TRIGGER_EVENT_BEFORE;
2256
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2257
LocTriggerData.tg_trigtuple = NULL;
2258
LocTriggerData.tg_newtuple = NULL;
2259
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2260
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2261
for (i = 0; i < trigdesc->numtriggers; i++)
2263
Trigger *trigger = &trigdesc->triggers[i];
2266
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2267
TRIGGER_TYPE_STATEMENT,
2268
TRIGGER_TYPE_BEFORE,
2269
TRIGGER_TYPE_UPDATE))
2271
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2272
modifiedCols, NULL, NULL))
2275
LocTriggerData.tg_trigger = trigger;
2276
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2278
relinfo->ri_TrigFunctions,
2279
relinfo->ri_TrigInstrument,
2280
GetPerTupleMemoryContext(estate));
2284
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2285
errmsg("BEFORE STATEMENT trigger cannot return a value")));
2290
ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
2292
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2294
if (trigdesc && trigdesc->trig_update_after_statement)
2295
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
2296
false, NULL, NULL, NIL,
2297
GetModifiedColumns(relinfo, estate));
2301
ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
2302
ResultRelInfo *relinfo,
2303
ItemPointer tupleid, TupleTableSlot *slot)
2305
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2306
HeapTuple slottuple = ExecMaterializeSlot(slot);
2307
HeapTuple newtuple = slottuple;
2308
TriggerData LocTriggerData;
2309
HeapTuple trigtuple;
2311
TupleTableSlot *newSlot;
2313
Bitmapset *modifiedCols;
2315
/* get a copy of the on-disk tuple we are planning to update */
2316
trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2318
if (trigtuple == NULL)
2319
return NULL; /* cancel the update action */
2322
* In READ COMMITTED isolation level it's possible that target tuple was
2323
* changed due to concurrent update. In that case we have a raw subplan
2324
* output tuple in newSlot, and need to run it through the junk filter to
2325
* produce an insertable tuple.
2327
* Caution: more than likely, the passed-in slot is the same as the
2328
* junkfilter's output slot, so we are clobbering the original value of
2329
* slottuple by doing the filtering. This is OK since neither we nor our
2330
* caller have any more interest in the prior contents of that slot.
2332
if (newSlot != NULL)
2334
slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
2335
slottuple = ExecMaterializeSlot(slot);
2336
newtuple = slottuple;
2339
modifiedCols = GetModifiedColumns(relinfo, estate);
2341
LocTriggerData.type = T_TriggerData;
2342
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2344
TRIGGER_EVENT_BEFORE;
2345
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2346
for (i = 0; i < trigdesc->numtriggers; i++)
2348
Trigger *trigger = &trigdesc->triggers[i];
2350
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2352
TRIGGER_TYPE_BEFORE,
2353
TRIGGER_TYPE_UPDATE))
2355
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2356
modifiedCols, trigtuple, newtuple))
2359
LocTriggerData.tg_trigtuple = trigtuple;
2360
LocTriggerData.tg_newtuple = oldtuple = newtuple;
2361
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2362
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2363
LocTriggerData.tg_trigger = trigger;
2364
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2366
relinfo->ri_TrigFunctions,
2367
relinfo->ri_TrigInstrument,
2368
GetPerTupleMemoryContext(estate));
2369
if (oldtuple != newtuple && oldtuple != slottuple)
2370
heap_freetuple(oldtuple);
2371
if (newtuple == NULL)
2373
heap_freetuple(trigtuple);
2374
return NULL; /* "do nothing" */
2377
heap_freetuple(trigtuple);
2379
if (newtuple != slottuple)
2382
* Return the modified tuple using the es_trig_tuple_slot. We assume
2383
* the tuple was allocated in per-tuple memory context, and therefore
2384
* will go away by itself. The tuple table slot should not try to
2387
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2388
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2390
if (newslot->tts_tupleDescriptor != tupdesc)
2391
ExecSetSlotDescriptor(newslot, tupdesc);
2392
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2399
ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
2400
ItemPointer tupleid, HeapTuple newtuple,
2401
List *recheckIndexes)
2403
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2405
if (trigdesc && trigdesc->trig_update_after_row)
2407
HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
2410
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
2411
true, trigtuple, newtuple, recheckIndexes,
2412
GetModifiedColumns(relinfo, estate));
2413
heap_freetuple(trigtuple);
2418
ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
2419
HeapTuple trigtuple, TupleTableSlot *slot)
2421
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2422
HeapTuple slottuple = ExecMaterializeSlot(slot);
2423
HeapTuple newtuple = slottuple;
2424
TriggerData LocTriggerData;
2428
LocTriggerData.type = T_TriggerData;
2429
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2431
TRIGGER_EVENT_INSTEAD;
2432
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2433
for (i = 0; i < trigdesc->numtriggers; i++)
2435
Trigger *trigger = &trigdesc->triggers[i];
2437
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2439
TRIGGER_TYPE_INSTEAD,
2440
TRIGGER_TYPE_UPDATE))
2442
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2443
NULL, trigtuple, newtuple))
2446
LocTriggerData.tg_trigtuple = trigtuple;
2447
LocTriggerData.tg_newtuple = oldtuple = newtuple;
2448
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2449
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2450
LocTriggerData.tg_trigger = trigger;
2451
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2453
relinfo->ri_TrigFunctions,
2454
relinfo->ri_TrigInstrument,
2455
GetPerTupleMemoryContext(estate));
2456
if (oldtuple != newtuple && oldtuple != slottuple)
2457
heap_freetuple(oldtuple);
2458
if (newtuple == NULL)
2459
return NULL; /* "do nothing" */
2462
if (newtuple != slottuple)
2465
* Return the modified tuple using the es_trig_tuple_slot. We assume
2466
* the tuple was allocated in per-tuple memory context, and therefore
2467
* will go away by itself. The tuple table slot should not try to
2470
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2471
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2473
if (newslot->tts_tupleDescriptor != tupdesc)
2474
ExecSetSlotDescriptor(newslot, tupdesc);
2475
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2482
ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
2484
TriggerDesc *trigdesc;
2486
TriggerData LocTriggerData;
2488
trigdesc = relinfo->ri_TrigDesc;
2490
if (trigdesc == NULL)
2492
if (!trigdesc->trig_truncate_before_statement)
2495
LocTriggerData.type = T_TriggerData;
2496
LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
2497
TRIGGER_EVENT_BEFORE;
2498
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2499
LocTriggerData.tg_trigtuple = NULL;
2500
LocTriggerData.tg_newtuple = NULL;
2501
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2502
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2503
for (i = 0; i < trigdesc->numtriggers; i++)
2505
Trigger *trigger = &trigdesc->triggers[i];
2508
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2509
TRIGGER_TYPE_STATEMENT,
2510
TRIGGER_TYPE_BEFORE,
2511
TRIGGER_TYPE_TRUNCATE))
2513
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2517
LocTriggerData.tg_trigger = trigger;
2518
newtuple = ExecCallTriggerFunc(&LocTriggerData,
2520
relinfo->ri_TrigFunctions,
2521
relinfo->ri_TrigInstrument,
2522
GetPerTupleMemoryContext(estate));
2526
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2527
errmsg("BEFORE STATEMENT trigger cannot return a value")));
2532
ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
2534
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2536
if (trigdesc && trigdesc->trig_truncate_after_statement)
2537
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_TRUNCATE,
2538
false, NULL, NULL, NIL, NULL);
2543
GetTupleForTrigger(EState *estate,
2545
ResultRelInfo *relinfo,
2547
TupleTableSlot **newSlot)
2549
Relation relation = relinfo->ri_RelationDesc;
2550
HeapTupleData tuple;
2554
if (newSlot != NULL)
2557
ItemPointerData update_ctid;
2558
TransactionId update_xmax;
2562
/* caller must pass an epqstate if EvalPlanQual is possible */
2563
Assert(epqstate != NULL);
2566
* lock tuple for update
2569
tuple.t_self = *tid;
2570
test = heap_lock_tuple(relation, &tuple, &buffer,
2571
&update_ctid, &update_xmax,
2572
estate->es_output_cid,
2573
LockTupleExclusive, false);
2576
case HeapTupleSelfUpdated:
2577
/* treat it as deleted; do not process */
2578
ReleaseBuffer(buffer);
2581
case HeapTupleMayBeUpdated:
2584
case HeapTupleUpdated:
2585
ReleaseBuffer(buffer);
2586
if (IsolationUsesXactSnapshot())
2588
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
2589
errmsg("could not serialize access due to concurrent update")));
2590
if (!ItemPointerEquals(&update_ctid, &tuple.t_self))
2592
/* it was updated, so look at the updated version */
2593
TupleTableSlot *epqslot;
2595
epqslot = EvalPlanQual(estate,
2598
relinfo->ri_RangeTableIndex,
2601
if (!TupIsNull(epqslot))
2607
* EvalPlanQual already locked the tuple, but we
2608
* re-call heap_lock_tuple anyway as an easy way of
2609
* re-fetching the correct tuple. Speed is hardly a
2610
* criterion in this path anyhow.
2617
* if tuple was deleted or PlanQual failed for updated tuple -
2618
* we must not process this tuple!
2623
ReleaseBuffer(buffer);
2624
elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
2625
return NULL; /* keep compiler quiet */
2633
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
2635
page = BufferGetPage(buffer);
2636
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2638
Assert(ItemIdIsNormal(lp));
2640
tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2641
tuple.t_len = ItemIdGetLength(lp);
2642
tuple.t_self = *tid;
2643
tuple.t_tableOid = RelationGetRelid(relation);
2646
result = heap_copytuple(&tuple);
2647
ReleaseBuffer(buffer);
2653
* Is trigger enabled to fire?
2656
TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
2657
Trigger *trigger, TriggerEvent event,
2658
Bitmapset *modifiedCols,
2659
HeapTuple oldtup, HeapTuple newtup)
2661
/* Check replication-role-dependent enable state */
2662
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
2664
if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
2665
trigger->tgenabled == TRIGGER_DISABLED)
2668
else /* ORIGIN or LOCAL role */
2670
if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
2671
trigger->tgenabled == TRIGGER_DISABLED)
2676
* Check for column-specific trigger (only possible for UPDATE, and in
2677
* fact we *must* ignore tgattr for other event types)
2679
if (trigger->tgnattr > 0 && TRIGGER_FIRED_BY_UPDATE(event))
2685
for (i = 0; i < trigger->tgnattr; i++)
2687
if (bms_is_member(trigger->tgattr[i] - FirstLowInvalidHeapAttributeNumber,
2698
/* Check for WHEN clause */
2699
if (trigger->tgqual)
2701
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2703
ExprContext *econtext;
2704
TupleTableSlot *oldslot = NULL;
2705
TupleTableSlot *newslot = NULL;
2706
MemoryContext oldContext;
2709
Assert(estate != NULL);
2712
* trigger is an element of relinfo->ri_TrigDesc->triggers[]; find the
2713
* matching element of relinfo->ri_TrigWhenExprs[]
2715
i = trigger - relinfo->ri_TrigDesc->triggers;
2716
predicate = &relinfo->ri_TrigWhenExprs[i];
2719
* If first time through for this WHEN expression, build expression
2720
* nodetrees for it. Keep them in the per-query memory context so
2721
* they'll survive throughout the query.
2723
if (*predicate == NIL)
2727
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
2728
tgqual = stringToNode(trigger->tgqual);
2729
/* Change references to OLD and NEW to INNER and OUTER */
2730
ChangeVarNodes(tgqual, PRS2_OLD_VARNO, INNER, 0);
2731
ChangeVarNodes(tgqual, PRS2_NEW_VARNO, OUTER, 0);
2732
/* ExecQual wants implicit-AND form */
2733
tgqual = (Node *) make_ands_implicit((Expr *) tgqual);
2734
*predicate = (List *) ExecPrepareExpr((Expr *) tgqual, estate);
2735
MemoryContextSwitchTo(oldContext);
2739
* We will use the EState's per-tuple context for evaluating WHEN
2740
* expressions (creating it if it's not already there).
2742
econtext = GetPerTupleExprContext(estate);
2745
* Put OLD and NEW tuples into tupleslots for expression evaluation.
2746
* These slots can be shared across the whole estate, but be careful
2747
* that they have the current resultrel's tupdesc.
2749
if (HeapTupleIsValid(oldtup))
2751
if (estate->es_trig_oldtup_slot == NULL)
2753
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
2754
estate->es_trig_oldtup_slot = ExecInitExtraTupleSlot(estate);
2755
MemoryContextSwitchTo(oldContext);
2757
oldslot = estate->es_trig_oldtup_slot;
2758
if (oldslot->tts_tupleDescriptor != tupdesc)
2759
ExecSetSlotDescriptor(oldslot, tupdesc);
2760
ExecStoreTuple(oldtup, oldslot, InvalidBuffer, false);
2762
if (HeapTupleIsValid(newtup))
2764
if (estate->es_trig_tuple_slot == NULL)
2766
oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
2767
estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
2768
MemoryContextSwitchTo(oldContext);
2770
newslot = estate->es_trig_tuple_slot;
2771
if (newslot->tts_tupleDescriptor != tupdesc)
2772
ExecSetSlotDescriptor(newslot, tupdesc);
2773
ExecStoreTuple(newtup, newslot, InvalidBuffer, false);
2777
* Finally evaluate the expression, making the old and/or new tuples
2778
* available as INNER/OUTER respectively.
2780
econtext->ecxt_innertuple = oldslot;
2781
econtext->ecxt_outertuple = newslot;
2782
if (!ExecQual(*predicate, econtext, false))
2791
* After-trigger stuff
2793
* The AfterTriggersData struct holds data about pending AFTER trigger events
2794
* during the current transaction tree. (BEFORE triggers are fired
2795
* immediately so we don't need any persistent state about them.) The struct
2796
* and most of its subsidiary data are kept in TopTransactionContext; however
2797
* the individual event records are kept in a separate sub-context. This is
2798
* done mainly so that it's easy to tell from a memory context dump how much
2799
* space is being eaten by trigger events.
2801
* Because the list of pending events can grow large, we go to some
2802
* considerable effort to minimize per-event memory consumption. The event
2803
* records are grouped into chunks and common data for similar events in the
2804
* same chunk is only stored once.
2806
* XXX We need to be able to save the per-event data in a file if it grows too
2811
/* Per-trigger SET CONSTRAINT status */
2812
typedef struct SetConstraintTriggerData
2815
bool sct_tgisdeferred;
2816
} SetConstraintTriggerData;
2818
typedef struct SetConstraintTriggerData *SetConstraintTrigger;
2821
* SET CONSTRAINT intra-transaction status.
2823
* We make this a single palloc'd object so it can be copied and freed easily.
2825
* all_isset and all_isdeferred are used to keep track
2826
* of SET CONSTRAINTS ALL {DEFERRED, IMMEDIATE}.
2828
* trigstates[] stores per-trigger tgisdeferred settings.
2830
typedef struct SetConstraintStateData
2833
bool all_isdeferred;
2834
int numstates; /* number of trigstates[] entries in use */
2835
int numalloc; /* allocated size of trigstates[] */
2836
SetConstraintTriggerData trigstates[1]; /* VARIABLE LENGTH ARRAY */
2837
} SetConstraintStateData;
2839
typedef SetConstraintStateData *SetConstraintState;
2843
* Per-trigger-event data
2845
* The actual per-event data, AfterTriggerEventData, includes DONE/IN_PROGRESS
2846
* status bits and one or two tuple CTIDs. Each event record also has an
2847
* associated AfterTriggerSharedData that is shared across all instances
2848
* of similar events within a "chunk".
2850
* We arrange not to waste storage on ate_ctid2 for non-update events.
2851
* We could go further and not store either ctid for statement-level triggers,
2852
* but that seems unlikely to be worth the trouble.
2854
* Note: ats_firing_id is initially zero and is set to something else when
2855
* AFTER_TRIGGER_IN_PROGRESS is set. It indicates which trigger firing
2856
* cycle the trigger will be fired in (or was fired in, if DONE is set).
2857
* Although this is mutable state, we can keep it in AfterTriggerSharedData
2858
* because all instances of the same type of event in a given event list will
2859
* be fired at the same time, if they were queued between the same firing
2860
* cycles. So we need only ensure that ats_firing_id is zero when attaching
2861
* a new event to an existing AfterTriggerSharedData record.
2863
typedef uint32 TriggerFlags;
2865
#define AFTER_TRIGGER_OFFSET 0x0FFFFFFF /* must be low-order
2867
#define AFTER_TRIGGER_2CTIDS 0x10000000
2868
#define AFTER_TRIGGER_DONE 0x20000000
2869
#define AFTER_TRIGGER_IN_PROGRESS 0x40000000
2871
typedef struct AfterTriggerSharedData *AfterTriggerShared;
2873
typedef struct AfterTriggerSharedData
2875
TriggerEvent ats_event; /* event type indicator, see trigger.h */
2876
Oid ats_tgoid; /* the trigger's ID */
2877
Oid ats_relid; /* the relation it's on */
2878
CommandId ats_firing_id; /* ID for firing cycle */
2879
} AfterTriggerSharedData;
2881
typedef struct AfterTriggerEventData *AfterTriggerEvent;
2883
typedef struct AfterTriggerEventData
2885
TriggerFlags ate_flags; /* status bits and offset to shared data */
2886
ItemPointerData ate_ctid1; /* inserted, deleted, or old updated tuple */
2887
ItemPointerData ate_ctid2; /* new updated tuple */
2888
} AfterTriggerEventData;
2890
/* This struct must exactly match the one above except for not having ctid2 */
2891
typedef struct AfterTriggerEventDataOneCtid
2893
TriggerFlags ate_flags; /* status bits and offset to shared data */
2894
ItemPointerData ate_ctid1; /* inserted, deleted, or old updated tuple */
2895
} AfterTriggerEventDataOneCtid;
2897
#define SizeofTriggerEvent(evt) \
2898
(((evt)->ate_flags & AFTER_TRIGGER_2CTIDS) ? \
2899
sizeof(AfterTriggerEventData) : sizeof(AfterTriggerEventDataOneCtid))
2901
#define GetTriggerSharedData(evt) \
2902
((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
2905
* To avoid palloc overhead, we keep trigger events in arrays in successively-
2906
* larger chunks (a slightly more sophisticated version of an expansible
2907
* array). The space between CHUNK_DATA_START and freeptr is occupied by
2908
* AfterTriggerEventData records; the space between endfree and endptr is
2909
* occupied by AfterTriggerSharedData records.
2911
typedef struct AfterTriggerEventChunk
2913
struct AfterTriggerEventChunk *next; /* list link */
2914
char *freeptr; /* start of free space in chunk */
2915
char *endfree; /* end of free space in chunk */
2916
char *endptr; /* end of chunk */
2917
/* event data follows here */
2918
} AfterTriggerEventChunk;
2920
#define CHUNK_DATA_START(cptr) ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
2922
/* A list of events */
2923
typedef struct AfterTriggerEventList
2925
AfterTriggerEventChunk *head;
2926
AfterTriggerEventChunk *tail;
2927
char *tailfree; /* freeptr of tail chunk */
2928
} AfterTriggerEventList;
2930
/* Macros to help in iterating over a list of events */
2931
#define for_each_chunk(cptr, evtlist) \
2932
for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)
2933
#define for_each_event(eptr, cptr) \
2934
for (eptr = (AfterTriggerEvent) CHUNK_DATA_START(cptr); \
2935
(char *) eptr < (cptr)->freeptr; \
2936
eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
2937
/* Use this if no special per-chunk processing is needed */
2938
#define for_each_event_chunk(eptr, cptr, evtlist) \
2939
for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
2943
* All per-transaction data for the AFTER TRIGGERS module.
2945
* AfterTriggersData has the following fields:
2947
* firing_counter is incremented for each call of afterTriggerInvokeEvents.
2948
* We mark firable events with the current firing cycle's ID so that we can
2949
* tell which ones to work on. This ensures sane behavior if a trigger
2950
* function chooses to do SET CONSTRAINTS: the inner SET CONSTRAINTS will
2951
* only fire those events that weren't already scheduled for firing.
2953
* state keeps track of the transaction-local effects of SET CONSTRAINTS.
2954
* This is saved and restored across failed subtransactions.
2956
* events is the current list of deferred events. This is global across
2957
* all subtransactions of the current transaction. In a subtransaction
2958
* abort, we know that the events added by the subtransaction are at the
2959
* end of the list, so it is relatively easy to discard them. The event
2960
* list chunks themselves are stored in event_cxt.
2962
* query_depth is the current depth of nested AfterTriggerBeginQuery calls
2963
* (-1 when the stack is empty).
2965
* query_stack[query_depth] is a list of AFTER trigger events queued by the
2966
* current query (and the query_stack entries below it are lists of trigger
2967
* events queued by calling queries). None of these are valid until the
2968
* matching AfterTriggerEndQuery call occurs. At that point we fire
2969
* immediate-mode triggers, and append any deferred events to the main events
2972
* maxquerydepth is just the allocated length of query_stack.
2974
* state_stack is a stack of pointers to saved copies of the SET CONSTRAINTS
2975
* state data; each subtransaction level that modifies that state first
2976
* saves a copy, which we use to restore the state if we abort.
2978
* events_stack is a stack of copies of the events head/tail pointers,
2979
* which we use to restore those values during subtransaction abort.
2981
* depth_stack is a stack of copies of subtransaction-start-time query_depth,
2982
* which we similarly use to clean up at subtransaction abort.
2984
* firing_stack is a stack of copies of subtransaction-start-time
2985
* firing_counter. We use this to recognize which deferred triggers were
2986
* fired (or marked for firing) within an aborted subtransaction.
2988
* We use GetCurrentTransactionNestLevel() to determine the correct array
2989
* index in these stacks. maxtransdepth is the number of allocated entries in
2990
* each stack. (By not keeping our own stack pointer, we can avoid trouble
2991
* in cases where errors during subxact abort cause multiple invocations
2992
* of AfterTriggerEndSubXact() at the same nesting depth.)
2994
typedef struct AfterTriggersData
2996
CommandId firing_counter; /* next firing ID to assign */
2997
SetConstraintState state; /* the active S C state */
2998
AfterTriggerEventList events; /* deferred-event list */
2999
int query_depth; /* current query list index */
3000
AfterTriggerEventList *query_stack; /* events pending from each query */
3001
int maxquerydepth; /* allocated len of above array */
3002
MemoryContext event_cxt; /* memory context for events, if any */
3004
/* these fields are just for resetting at subtrans abort: */
3006
SetConstraintState *state_stack; /* stacked S C states */
3007
AfterTriggerEventList *events_stack; /* stacked list pointers */
3008
int *depth_stack; /* stacked query_depths */
3009
CommandId *firing_stack; /* stacked firing_counters */
3010
int maxtransdepth; /* allocated len of above arrays */
3011
} AfterTriggersData;
3013
typedef AfterTriggersData *AfterTriggers;
3015
static AfterTriggers afterTriggers;
3018
static void AfterTriggerExecute(AfterTriggerEvent event,
3019
Relation rel, TriggerDesc *trigdesc,
3021
Instrumentation *instr,
3022
MemoryContext per_tuple_context);
3023
static SetConstraintState SetConstraintStateCreate(int numalloc);
3024
static SetConstraintState SetConstraintStateCopy(SetConstraintState state);
3025
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state,
3026
Oid tgoid, bool tgisdeferred);
3030
* afterTriggerCheckState()
3032
* Returns true if the trigger event is actually in state DEFERRED.
3036
afterTriggerCheckState(AfterTriggerShared evtshared)
3038
Oid tgoid = evtshared->ats_tgoid;
3039
SetConstraintState state = afterTriggers->state;
3043
* For not-deferrable triggers (i.e. normal AFTER ROW triggers and
3044
* constraints declared NOT DEFERRABLE), the state is always false.
3046
if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
3050
* Check if SET CONSTRAINTS has been executed for this specific trigger.
3052
for (i = 0; i < state->numstates; i++)
3054
if (state->trigstates[i].sct_tgoid == tgoid)
3055
return state->trigstates[i].sct_tgisdeferred;
3059
* Check if SET CONSTRAINTS ALL has been executed; if so use that.
3061
if (state->all_isset)
3062
return state->all_isdeferred;
3065
* Otherwise return the default state for the trigger.
3067
return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
3072
* afterTriggerAddEvent()
3074
* Add a new trigger event to the specified queue.
3075
* The passed-in event data is copied.
3079
afterTriggerAddEvent(AfterTriggerEventList *events,
3080
AfterTriggerEvent event, AfterTriggerShared evtshared)
3082
Size eventsize = SizeofTriggerEvent(event);
3083
Size needed = eventsize + sizeof(AfterTriggerSharedData);
3084
AfterTriggerEventChunk *chunk;
3085
AfterTriggerShared newshared;
3086
AfterTriggerEvent newevent;
3089
* If empty list or not enough room in the tail chunk, make a new chunk.
3090
* We assume here that a new shared record will always be needed.
3092
chunk = events->tail;
3093
if (chunk == NULL ||
3094
chunk->endfree - chunk->freeptr < needed)
3098
/* Create event context if we didn't already */
3099
if (afterTriggers->event_cxt == NULL)
3100
afterTriggers->event_cxt =
3101
AllocSetContextCreate(TopTransactionContext,
3102
"AfterTriggerEvents",
3103
ALLOCSET_DEFAULT_MINSIZE,
3104
ALLOCSET_DEFAULT_INITSIZE,
3105
ALLOCSET_DEFAULT_MAXSIZE);
3108
* Chunk size starts at 1KB and is allowed to increase up to 1MB.
3109
* These numbers are fairly arbitrary, though there is a hard limit at
3110
* AFTER_TRIGGER_OFFSET; else we couldn't link event records to their
3111
* shared records using the available space in ate_flags. Another
3112
* constraint is that if the chunk size gets too huge, the search loop
3113
* below would get slow given a (not too common) usage pattern with
3114
* many distinct event types in a chunk. Therefore, we double the
3115
* preceding chunk size only if there weren't too many shared records
3116
* in the preceding chunk; otherwise we halve it. This gives us some
3117
* ability to adapt to the actual usage pattern of the current query
3118
* while still having large chunk sizes in typical usage. All chunk
3119
* sizes used should be MAXALIGN multiples, to ensure that the shared
3120
* records will be aligned safely.
3122
#define MIN_CHUNK_SIZE 1024
3123
#define MAX_CHUNK_SIZE (1024*1024)
3125
#if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
3126
#error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
3130
chunksize = MIN_CHUNK_SIZE;
3133
/* preceding chunk size... */
3134
chunksize = chunk->endptr - (char *) chunk;
3135
/* check number of shared records in preceding chunk */
3136
if ((chunk->endptr - chunk->endfree) <=
3137
(100 * sizeof(AfterTriggerSharedData)))
3138
chunksize *= 2; /* okay, double it */
3140
chunksize /= 2; /* too many shared records */
3141
chunksize = Min(chunksize, MAX_CHUNK_SIZE);
3143
chunk = MemoryContextAlloc(afterTriggers->event_cxt, chunksize);
3145
chunk->freeptr = CHUNK_DATA_START(chunk);
3146
chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
3147
Assert(chunk->endfree - chunk->freeptr >= needed);
3149
if (events->head == NULL)
3150
events->head = chunk;
3152
events->tail->next = chunk;
3153
events->tail = chunk;
3154
/* events->tailfree is now out of sync, but we'll fix it below */
3158
* Try to locate a matching shared-data record already in the chunk. If
3159
* none, make a new one.
3161
for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
3162
(char *) newshared >= chunk->endfree;
3165
if (newshared->ats_tgoid == evtshared->ats_tgoid &&
3166
newshared->ats_relid == evtshared->ats_relid &&
3167
newshared->ats_event == evtshared->ats_event &&
3168
newshared->ats_firing_id == 0)
3171
if ((char *) newshared < chunk->endfree)
3173
*newshared = *evtshared;
3174
newshared->ats_firing_id = 0; /* just to be sure */
3175
chunk->endfree = (char *) newshared;
3178
/* Insert the data */
3179
newevent = (AfterTriggerEvent) chunk->freeptr;
3180
memcpy(newevent, event, eventsize);
3181
/* ... and link the new event to its shared record */
3182
newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
3183
newevent->ate_flags |= (char *) newshared - (char *) newevent;
3185
chunk->freeptr += eventsize;
3186
events->tailfree = chunk->freeptr;
3190
* afterTriggerFreeEventList()
3192
* Free all the event storage in the given list.
3196
afterTriggerFreeEventList(AfterTriggerEventList *events)
3198
AfterTriggerEventChunk *chunk;
3199
AfterTriggerEventChunk *next_chunk;
3201
for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3203
next_chunk = chunk->next;
3206
events->head = NULL;
3207
events->tail = NULL;
3208
events->tailfree = NULL;
3212
* afterTriggerRestoreEventList()
3214
* Restore an event list to its prior length, removing all the events
3215
* added since it had the value old_events.
3219
afterTriggerRestoreEventList(AfterTriggerEventList *events,
3220
const AfterTriggerEventList *old_events)
3222
AfterTriggerEventChunk *chunk;
3223
AfterTriggerEventChunk *next_chunk;
3225
if (old_events->tail == NULL)
3227
/* restoring to a completely empty state, so free everything */
3228
afterTriggerFreeEventList(events);
3232
*events = *old_events;
3233
/* free any chunks after the last one we want to keep */
3234
for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3236
next_chunk = chunk->next;
3239
/* and clean up the tail chunk to be the right length */
3240
events->tail->next = NULL;
3241
events->tail->freeptr = events->tailfree;
3244
* We don't make any effort to remove now-unused shared data records.
3245
* They might still be useful, anyway.
3252
* AfterTriggerExecute()
3254
* Fetch the required tuples back from the heap and fire one
3255
* single trigger function.
3257
* Frequently, this will be fired many times in a row for triggers of
3258
* a single relation. Therefore, we cache the open relation and provide
3259
* fmgr lookup cache space at the caller level. (For triggers fired at
3260
* the end of a query, we can even piggyback on the executor's state.)
3262
* event: event currently being fired.
3263
* rel: open relation for event.
3264
* trigdesc: working copy of rel's trigger info.
3265
* finfo: array of fmgr lookup cache entries (one per trigger in trigdesc).
3266
* instr: array of EXPLAIN ANALYZE instrumentation nodes (one per trigger),
3267
* or NULL if no instrumentation is wanted.
3268
* per_tuple_context: memory context to call trigger function in.
3272
AfterTriggerExecute(AfterTriggerEvent event,
3273
Relation rel, TriggerDesc *trigdesc,
3274
FmgrInfo *finfo, Instrumentation *instr,
3275
MemoryContext per_tuple_context)
3277
AfterTriggerShared evtshared = GetTriggerSharedData(event);
3278
Oid tgoid = evtshared->ats_tgoid;
3279
TriggerData LocTriggerData;
3280
HeapTupleData tuple1;
3281
HeapTupleData tuple2;
3283
Buffer buffer1 = InvalidBuffer;
3284
Buffer buffer2 = InvalidBuffer;
3288
* Locate trigger in trigdesc.
3290
LocTriggerData.tg_trigger = NULL;
3291
for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3293
if (trigdesc->triggers[tgindx].tgoid == tgoid)
3295
LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3299
if (LocTriggerData.tg_trigger == NULL)
3300
elog(ERROR, "could not find trigger %u", tgoid);
3303
* If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3304
* to include time spent re-fetching tuples in the trigger cost.
3307
InstrStartNode(instr + tgindx);
3310
* Fetch the required tuple(s).
3312
if (ItemPointerIsValid(&(event->ate_ctid1)))
3314
ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3315
if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3316
elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3317
LocTriggerData.tg_trigtuple = &tuple1;
3318
LocTriggerData.tg_trigtuplebuf = buffer1;
3322
LocTriggerData.tg_trigtuple = NULL;
3323
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3326
/* don't touch ctid2 if not there */
3327
if ((event->ate_flags & AFTER_TRIGGER_2CTIDS) &&
3328
ItemPointerIsValid(&(event->ate_ctid2)))
3330
ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3331
if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3332
elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3333
LocTriggerData.tg_newtuple = &tuple2;
3334
LocTriggerData.tg_newtuplebuf = buffer2;
3338
LocTriggerData.tg_newtuple = NULL;
3339
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3343
* Setup the remaining trigger information
3345
LocTriggerData.type = T_TriggerData;
3346
LocTriggerData.tg_event =
3347
evtshared->ats_event & (TRIGGER_EVENT_OPMASK | TRIGGER_EVENT_ROW);
3348
LocTriggerData.tg_relation = rel;
3350
MemoryContextReset(per_tuple_context);
3353
* Call the trigger and throw away any possibly returned updated tuple.
3354
* (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3356
rettuple = ExecCallTriggerFunc(&LocTriggerData,
3361
if (rettuple != NULL && rettuple != &tuple1 && rettuple != &tuple2)
3362
heap_freetuple(rettuple);
3367
if (buffer1 != InvalidBuffer)
3368
ReleaseBuffer(buffer1);
3369
if (buffer2 != InvalidBuffer)
3370
ReleaseBuffer(buffer2);
3373
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3374
* one "tuple returned" (really the number of firings).
3377
InstrStopNode(instr + tgindx, 1);
3382
* afterTriggerMarkEvents()
3384
* Scan the given event list for not yet invoked events. Mark the ones
3385
* that can be invoked now with the current firing ID.
3387
* If move_list isn't NULL, events that are not to be invoked now are
3388
* transferred to move_list.
3390
* When immediate_only is TRUE, do not invoke currently-deferred triggers.
3391
* (This will be FALSE only at main transaction exit.)
3393
* Returns TRUE if any invokable events were found.
3396
afterTriggerMarkEvents(AfterTriggerEventList *events,
3397
AfterTriggerEventList *move_list,
3398
bool immediate_only)
3401
AfterTriggerEvent event;
3402
AfterTriggerEventChunk *chunk;
3404
for_each_event_chunk(event, chunk, *events)
3406
AfterTriggerShared evtshared = GetTriggerSharedData(event);
3407
bool defer_it = false;
3409
if (!(event->ate_flags &
3410
(AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS)))
3413
* This trigger hasn't been called or scheduled yet. Check if we
3414
* should call it now.
3416
if (immediate_only && afterTriggerCheckState(evtshared))
3423
* Mark it as to be fired in this firing cycle.
3425
evtshared->ats_firing_id = afterTriggers->firing_counter;
3426
event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3432
* If it's deferred, move it to move_list, if requested.
3434
if (defer_it && move_list != NULL)
3436
/* add it to move_list */
3437
afterTriggerAddEvent(move_list, event, evtshared);
3438
/* mark original copy "done" so we don't do it again */
3439
event->ate_flags |= AFTER_TRIGGER_DONE;
3447
* afterTriggerInvokeEvents()
3449
* Scan the given event list for events that are marked as to be fired
3450
* in the current firing cycle, and fire them.
3452
* If estate isn't NULL, we use its result relation info to avoid repeated
3453
* openings and closing of trigger target relations. If it is NULL, we
3454
* make one locally to cache the info in case there are multiple trigger
3457
* When delete_ok is TRUE, it's safe to delete fully-processed events.
3458
* (We are not very tense about that: we simply reset a chunk to be empty
3459
* if all its events got fired. The objective here is just to avoid useless
3460
* rescanning of events when a trigger queues new events during transaction
3461
* end, so it's not necessary to worry much about the case where only
3462
* some events are fired.)
3464
* Returns TRUE if no unfired events remain in the list (this allows us
3465
* to avoid repeating afterTriggerMarkEvents).
3468
afterTriggerInvokeEvents(AfterTriggerEventList *events,
3469
CommandId firing_id,
3473
bool all_fired = true;
3474
AfterTriggerEventChunk *chunk;
3475
MemoryContext per_tuple_context;
3476
bool local_estate = false;
3477
Relation rel = NULL;
3478
TriggerDesc *trigdesc = NULL;
3479
FmgrInfo *finfo = NULL;
3480
Instrumentation *instr = NULL;
3482
/* Make a local EState if need be */
3485
estate = CreateExecutorState();
3486
local_estate = true;
3489
/* Make a per-tuple memory context for trigger function calls */
3491
AllocSetContextCreate(CurrentMemoryContext,
3492
"AfterTriggerTupleContext",
3493
ALLOCSET_DEFAULT_MINSIZE,
3494
ALLOCSET_DEFAULT_INITSIZE,
3495
ALLOCSET_DEFAULT_MAXSIZE);
3497
for_each_chunk(chunk, *events)
3499
AfterTriggerEvent event;
3500
bool all_fired_in_chunk = true;
3502
for_each_event(event, chunk)
3504
AfterTriggerShared evtshared = GetTriggerSharedData(event);
3507
* Is it one for me to fire?
3509
if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
3510
evtshared->ats_firing_id == firing_id)
3513
* So let's fire it... but first, find the correct relation if
3514
* this is not the same relation as before.
3516
if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
3518
ResultRelInfo *rInfo;
3520
rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
3521
rel = rInfo->ri_RelationDesc;
3522
trigdesc = rInfo->ri_TrigDesc;
3523
finfo = rInfo->ri_TrigFunctions;
3524
instr = rInfo->ri_TrigInstrument;
3525
if (trigdesc == NULL) /* should not happen */
3526
elog(ERROR, "relation %u has no triggers",
3527
evtshared->ats_relid);
3531
* Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
3532
* still set, so recursive examinations of the event list
3533
* won't try to re-fire it.
3535
AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
3539
* Mark the event as done.
3541
event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
3542
event->ate_flags |= AFTER_TRIGGER_DONE;
3544
else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
3546
/* something remains to be done */
3547
all_fired = all_fired_in_chunk = false;
3551
/* Clear the chunk if delete_ok and nothing left of interest */
3552
if (delete_ok && all_fired_in_chunk)
3554
chunk->freeptr = CHUNK_DATA_START(chunk);
3555
chunk->endfree = chunk->endptr;
3558
* If it's last chunk, must sync event list's tailfree too. Note
3559
* that delete_ok must NOT be passed as true if there could be
3560
* stacked AfterTriggerEventList values pointing at this event
3561
* list, since we'd fail to fix their copies of tailfree.
3563
if (chunk == events->tail)
3564
events->tailfree = chunk->freeptr;
3568
/* Release working resources */
3569
MemoryContextDelete(per_tuple_context);
3575
foreach(l, estate->es_trig_target_relations)
3577
ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
3579
/* Close indices and then the relation itself */
3580
ExecCloseIndices(resultRelInfo);
3581
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
3583
FreeExecutorState(estate);
3591
* AfterTriggerBeginXact()
3593
* Called at transaction start (either BEGIN or implicit for single
3594
* statement outside of transaction block).
3598
AfterTriggerBeginXact(void)
3600
Assert(afterTriggers == NULL);
3603
* Build empty after-trigger state structure
3605
afterTriggers = (AfterTriggers)
3606
MemoryContextAlloc(TopTransactionContext,
3607
sizeof(AfterTriggersData));
3609
afterTriggers->firing_counter = (CommandId) 1; /* mustn't be 0 */
3610
afterTriggers->state = SetConstraintStateCreate(8);
3611
afterTriggers->events.head = NULL;
3612
afterTriggers->events.tail = NULL;
3613
afterTriggers->events.tailfree = NULL;
3614
afterTriggers->query_depth = -1;
3616
/* We initialize the query stack to a reasonable size */
3617
afterTriggers->query_stack = (AfterTriggerEventList *)
3618
MemoryContextAlloc(TopTransactionContext,
3619
8 * sizeof(AfterTriggerEventList));
3620
afterTriggers->maxquerydepth = 8;
3622
/* Context for events is created only when needed */
3623
afterTriggers->event_cxt = NULL;
3625
/* Subtransaction stack is empty until/unless needed */
3626
afterTriggers->state_stack = NULL;
3627
afterTriggers->events_stack = NULL;
3628
afterTriggers->depth_stack = NULL;
3629
afterTriggers->firing_stack = NULL;
3630
afterTriggers->maxtransdepth = 0;
3635
* AfterTriggerBeginQuery()
3637
* Called just before we start processing a single query within a
3638
* transaction (or subtransaction). Set up to record AFTER trigger
3639
* events queued by the query. Note that it is allowed to have
3640
* nested queries within a (sub)transaction.
3644
AfterTriggerBeginQuery(void)
3646
AfterTriggerEventList *events;
3648
/* Must be inside a transaction */
3649
Assert(afterTriggers != NULL);
3651
/* Increase the query stack depth */
3652
afterTriggers->query_depth++;
3655
* Allocate more space in the query stack if needed.
3657
if (afterTriggers->query_depth >= afterTriggers->maxquerydepth)
3659
/* repalloc will keep the stack in the same context */
3660
int new_alloc = afterTriggers->maxquerydepth * 2;
3662
afterTriggers->query_stack = (AfterTriggerEventList *)
3663
repalloc(afterTriggers->query_stack,
3664
new_alloc * sizeof(AfterTriggerEventList));
3665
afterTriggers->maxquerydepth = new_alloc;
3668
/* Initialize this query's list to empty */
3669
events = &afterTriggers->query_stack[afterTriggers->query_depth];
3670
events->head = NULL;
3671
events->tail = NULL;
3672
events->tailfree = NULL;
3677
* AfterTriggerEndQuery()
3679
* Called after one query has been completely processed. At this time
3680
* we invoke all AFTER IMMEDIATE trigger events queued by the query, and
3681
* transfer deferred trigger events to the global deferred-trigger list.
3683
* Note that this must be called BEFORE closing down the executor
3684
* with ExecutorEnd, because we make use of the EState's info about
3685
* target relations. Normally it is called from ExecutorFinish.
3689
AfterTriggerEndQuery(EState *estate)
3691
AfterTriggerEventList *events;
3693
/* Must be inside a transaction */
3694
Assert(afterTriggers != NULL);
3696
/* Must be inside a query, too */
3697
Assert(afterTriggers->query_depth >= 0);
3700
* Process all immediate-mode triggers queued by the query, and move the
3701
* deferred ones to the main list of deferred events.
3703
* Notice that we decide which ones will be fired, and put the deferred
3704
* ones on the main list, before anything is actually fired. This ensures
3705
* reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
3706
* IMMEDIATE: all events we have decided to defer will be available for it
3709
* We loop in case a trigger queues more events at the same query level
3710
* (is that even possible?). Be careful here: firing a trigger could
3711
* result in query_stack being repalloc'd, so we can't save its address
3712
* across afterTriggerInvokeEvents calls.
3714
* If we find no firable events, we don't have to increment
3719
events = &afterTriggers->query_stack[afterTriggers->query_depth];
3720
if (afterTriggerMarkEvents(events, &afterTriggers->events, true))
3722
CommandId firing_id = afterTriggers->firing_counter++;
3724
/* OK to delete the immediate events after processing them */
3725
if (afterTriggerInvokeEvents(events, firing_id, estate, true))
3726
break; /* all fired */
3732
/* Release query-local storage for events */
3733
afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
3735
afterTriggers->query_depth--;
3740
* AfterTriggerFireDeferred()
3742
* Called just before the current transaction is committed. At this
3743
* time we invoke all pending DEFERRED triggers.
3745
* It is possible for other modules to queue additional deferred triggers
3746
* during pre-commit processing; therefore xact.c may have to call this
3751
AfterTriggerFireDeferred(void)
3753
AfterTriggerEventList *events;
3754
bool snap_pushed = false;
3756
/* Must be inside a transaction */
3757
Assert(afterTriggers != NULL);
3759
/* ... but not inside a query */
3760
Assert(afterTriggers->query_depth == -1);
3763
* If there are any triggers to fire, make sure we have set a snapshot for
3764
* them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
3765
* can't assume ActiveSnapshot is valid on entry.)
3767
events = &afterTriggers->events;
3768
if (events->head != NULL)
3770
PushActiveSnapshot(GetTransactionSnapshot());
3775
* Run all the remaining triggers. Loop until they are all gone, in case
3776
* some trigger queues more for us to do.
3778
while (afterTriggerMarkEvents(events, NULL, false))
3780
CommandId firing_id = afterTriggers->firing_counter++;
3782
if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
3783
break; /* all fired */
3787
* We don't bother freeing the event list, since it will go away anyway
3788
* (and more efficiently than via pfree) in AfterTriggerEndXact.
3792
PopActiveSnapshot();
3797
* AfterTriggerEndXact()
3799
* The current transaction is finishing.
3801
* Any unfired triggers are canceled so we simply throw
3802
* away anything we know.
3804
* Note: it is possible for this to be called repeatedly in case of
3805
* error during transaction abort; therefore, do not complain if
3806
* already closed down.
3810
AfterTriggerEndXact(bool isCommit)
3813
* Forget everything we know about AFTER triggers.
3815
* Since all the info is in TopTransactionContext or children thereof, we
3816
* don't really need to do anything to reclaim memory. However, the
3817
* pending-events list could be large, and so it's useful to discard it as
3818
* soon as possible --- especially if we are aborting because we ran out
3819
* of memory for the list!
3821
if (afterTriggers && afterTriggers->event_cxt)
3822
MemoryContextDelete(afterTriggers->event_cxt);
3824
afterTriggers = NULL;
3828
* AfterTriggerBeginSubXact()
3830
* Start a subtransaction.
3833
AfterTriggerBeginSubXact(void)
3835
int my_level = GetCurrentTransactionNestLevel();
3838
* Ignore call if the transaction is in aborted state. (Probably
3839
* shouldn't happen?)
3841
if (afterTriggers == NULL)
3845
* Allocate more space in the stacks if needed. (Note: because the
3846
* minimum nest level of a subtransaction is 2, we waste the first couple
3847
* entries of each array; not worth the notational effort to avoid it.)
3849
while (my_level >= afterTriggers->maxtransdepth)
3851
if (afterTriggers->maxtransdepth == 0)
3853
MemoryContext old_cxt;
3855
old_cxt = MemoryContextSwitchTo(TopTransactionContext);
3857
#define DEFTRIG_INITALLOC 8
3858
afterTriggers->state_stack = (SetConstraintState *)
3859
palloc(DEFTRIG_INITALLOC * sizeof(SetConstraintState));
3860
afterTriggers->events_stack = (AfterTriggerEventList *)
3861
palloc(DEFTRIG_INITALLOC * sizeof(AfterTriggerEventList));
3862
afterTriggers->depth_stack = (int *)
3863
palloc(DEFTRIG_INITALLOC * sizeof(int));
3864
afterTriggers->firing_stack = (CommandId *)
3865
palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
3866
afterTriggers->maxtransdepth = DEFTRIG_INITALLOC;
3868
MemoryContextSwitchTo(old_cxt);
3872
/* repalloc will keep the stacks in the same context */
3873
int new_alloc = afterTriggers->maxtransdepth * 2;
3875
afterTriggers->state_stack = (SetConstraintState *)
3876
repalloc(afterTriggers->state_stack,
3877
new_alloc * sizeof(SetConstraintState));
3878
afterTriggers->events_stack = (AfterTriggerEventList *)
3879
repalloc(afterTriggers->events_stack,
3880
new_alloc * sizeof(AfterTriggerEventList));
3881
afterTriggers->depth_stack = (int *)
3882
repalloc(afterTriggers->depth_stack,
3883
new_alloc * sizeof(int));
3884
afterTriggers->firing_stack = (CommandId *)
3885
repalloc(afterTriggers->firing_stack,
3886
new_alloc * sizeof(CommandId));
3887
afterTriggers->maxtransdepth = new_alloc;
3892
* Push the current information into the stack. The SET CONSTRAINTS state
3893
* is not saved until/unless changed. Likewise, we don't make a
3894
* per-subtransaction event context until needed.
3896
afterTriggers->state_stack[my_level] = NULL;
3897
afterTriggers->events_stack[my_level] = afterTriggers->events;
3898
afterTriggers->depth_stack[my_level] = afterTriggers->query_depth;
3899
afterTriggers->firing_stack[my_level] = afterTriggers->firing_counter;
3903
* AfterTriggerEndSubXact()
3905
* The current subtransaction is ending.
3908
AfterTriggerEndSubXact(bool isCommit)
3910
int my_level = GetCurrentTransactionNestLevel();
3911
SetConstraintState state;
3912
AfterTriggerEvent event;
3913
AfterTriggerEventChunk *chunk;
3914
CommandId subxact_firing_id;
3917
* Ignore call if the transaction is in aborted state. (Probably
3920
if (afterTriggers == NULL)
3924
* Pop the prior state if needed.
3928
Assert(my_level < afterTriggers->maxtransdepth);
3929
/* If we saved a prior state, we don't need it anymore */
3930
state = afterTriggers->state_stack[my_level];
3933
/* this avoids double pfree if error later: */
3934
afterTriggers->state_stack[my_level] = NULL;
3935
Assert(afterTriggers->query_depth ==
3936
afterTriggers->depth_stack[my_level]);
3941
* Aborting. It is possible subxact start failed before calling
3942
* AfterTriggerBeginSubXact, in which case we mustn't risk touching
3943
* stack levels that aren't there.
3945
if (my_level >= afterTriggers->maxtransdepth)
3949
* Release any event lists from queries being aborted, and restore
3950
* query_depth to its pre-subxact value.
3952
while (afterTriggers->query_depth > afterTriggers->depth_stack[my_level])
3954
afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
3955
afterTriggers->query_depth--;
3957
Assert(afterTriggers->query_depth ==
3958
afterTriggers->depth_stack[my_level]);
3961
* Restore the global deferred-event list to its former length,
3962
* discarding any events queued by the subxact.
3964
afterTriggerRestoreEventList(&afterTriggers->events,
3965
&afterTriggers->events_stack[my_level]);
3968
* Restore the trigger state. If the saved state is NULL, then this
3969
* subxact didn't save it, so it doesn't need restoring.
3971
state = afterTriggers->state_stack[my_level];
3974
pfree(afterTriggers->state);
3975
afterTriggers->state = state;
3977
/* this avoids double pfree if error later: */
3978
afterTriggers->state_stack[my_level] = NULL;
3981
* Scan for any remaining deferred events that were marked DONE or IN
3982
* PROGRESS by this subxact or a child, and un-mark them. We can
3983
* recognize such events because they have a firing ID greater than or
3984
* equal to the firing_counter value we saved at subtransaction start.
3985
* (This essentially assumes that the current subxact includes all
3986
* subxacts started after it.)
3988
subxact_firing_id = afterTriggers->firing_stack[my_level];
3989
for_each_event_chunk(event, chunk, afterTriggers->events)
3991
AfterTriggerShared evtshared = GetTriggerSharedData(event);
3993
if (event->ate_flags &
3994
(AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS))
3996
if (evtshared->ats_firing_id >= subxact_firing_id)
3998
~(AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS);
4005
* Create an empty SetConstraintState with room for numalloc trigstates
4007
static SetConstraintState
4008
SetConstraintStateCreate(int numalloc)
4010
SetConstraintState state;
4012
/* Behave sanely with numalloc == 0 */
4017
* We assume that zeroing will correctly initialize the state values.
4019
state = (SetConstraintState)
4020
MemoryContextAllocZero(TopTransactionContext,
4021
sizeof(SetConstraintStateData) +
4022
(numalloc - 1) *sizeof(SetConstraintTriggerData));
4024
state->numalloc = numalloc;
4030
* Copy a SetConstraintState
4032
static SetConstraintState
4033
SetConstraintStateCopy(SetConstraintState origstate)
4035
SetConstraintState state;
4037
state = SetConstraintStateCreate(origstate->numstates);
4039
state->all_isset = origstate->all_isset;
4040
state->all_isdeferred = origstate->all_isdeferred;
4041
state->numstates = origstate->numstates;
4042
memcpy(state->trigstates, origstate->trigstates,
4043
origstate->numstates * sizeof(SetConstraintTriggerData));
4049
* Add a per-trigger item to a SetConstraintState. Returns possibly-changed
4050
* pointer to the state object (it will change if we have to repalloc).
4052
static SetConstraintState
4053
SetConstraintStateAddItem(SetConstraintState state,
4054
Oid tgoid, bool tgisdeferred)
4056
if (state->numstates >= state->numalloc)
4058
int newalloc = state->numalloc * 2;
4060
newalloc = Max(newalloc, 8); /* in case original has size 0 */
4061
state = (SetConstraintState)
4063
sizeof(SetConstraintStateData) +
4064
(newalloc - 1) *sizeof(SetConstraintTriggerData));
4065
state->numalloc = newalloc;
4066
Assert(state->numstates < state->numalloc);
4069
state->trigstates[state->numstates].sct_tgoid = tgoid;
4070
state->trigstates[state->numstates].sct_tgisdeferred = tgisdeferred;
4077
* AfterTriggerSetState()
4079
* Execute the SET CONSTRAINTS ... utility command.
4083
AfterTriggerSetState(ConstraintsSetStmt *stmt)
4085
int my_level = GetCurrentTransactionNestLevel();
4088
* Ignore call if we aren't in a transaction. (Shouldn't happen?)
4090
if (afterTriggers == NULL)
4094
* If in a subtransaction, and we didn't save the current state already,
4095
* save it so it can be restored if the subtransaction aborts.
4098
afterTriggers->state_stack[my_level] == NULL)
4100
afterTriggers->state_stack[my_level] =
4101
SetConstraintStateCopy(afterTriggers->state);
4105
* Handle SET CONSTRAINTS ALL ...
4107
if (stmt->constraints == NIL)
4110
* Forget any previous SET CONSTRAINTS commands in this transaction.
4112
afterTriggers->state->numstates = 0;
4115
* Set the per-transaction ALL state to known.
4117
afterTriggers->state->all_isset = true;
4118
afterTriggers->state->all_isdeferred = stmt->deferred;
4124
List *conoidlist = NIL;
4125
List *tgoidlist = NIL;
4129
* Handle SET CONSTRAINTS constraint-name [, ...]
4131
* First, identify all the named constraints and make a list of their
4132
* OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4133
* the same name within a schema, the specifications are not
4134
* necessarily unique. Our strategy is to target all matching
4135
* constraints within the first search-path schema that has any
4136
* matches, but disregard matches in schemas beyond the first match.
4137
* (This is a bit odd but it's the historical behavior.)
4139
conrel = heap_open(ConstraintRelationId, AccessShareLock);
4141
foreach(lc, stmt->constraints)
4143
RangeVar *constraint = lfirst(lc);
4145
List *namespacelist;
4148
if (constraint->catalogname)
4150
if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4152
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4153
errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4154
constraint->catalogname, constraint->schemaname,
4155
constraint->relname)));
4159
* If we're given the schema name with the constraint, look only
4160
* in that schema. If given a bare constraint name, use the
4161
* search path to find the first matching constraint.
4163
if (constraint->schemaname)
4165
Oid namespaceId = LookupExplicitNamespace(constraint->schemaname);
4167
namespacelist = list_make1_oid(namespaceId);
4171
namespacelist = fetch_search_path(true);
4175
foreach(nslc, namespacelist)
4177
Oid namespaceId = lfirst_oid(nslc);
4178
SysScanDesc conscan;
4179
ScanKeyData skey[2];
4182
ScanKeyInit(&skey[0],
4183
Anum_pg_constraint_conname,
4184
BTEqualStrategyNumber, F_NAMEEQ,
4185
CStringGetDatum(constraint->relname));
4186
ScanKeyInit(&skey[1],
4187
Anum_pg_constraint_connamespace,
4188
BTEqualStrategyNumber, F_OIDEQ,
4189
ObjectIdGetDatum(namespaceId));
4191
conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4192
true, SnapshotNow, 2, skey);
4194
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4196
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
4198
if (con->condeferrable)
4199
conoidlist = lappend_oid(conoidlist,
4200
HeapTupleGetOid(tup));
4201
else if (stmt->deferred)
4203
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
4204
errmsg("constraint \"%s\" is not deferrable",
4205
constraint->relname)));
4209
systable_endscan(conscan);
4212
* Once we've found a matching constraint we do not search
4213
* later parts of the search path.
4219
list_free(namespacelist);
4226
(errcode(ERRCODE_UNDEFINED_OBJECT),
4227
errmsg("constraint \"%s\" does not exist",
4228
constraint->relname)));
4231
heap_close(conrel, AccessShareLock);
4234
* Now, locate the trigger(s) implementing each of these constraints,
4235
* and make a list of their OIDs.
4237
tgrel = heap_open(TriggerRelationId, AccessShareLock);
4239
foreach(lc, conoidlist)
4241
Oid conoid = lfirst_oid(lc);
4250
Anum_pg_trigger_tgconstraint,
4251
BTEqualStrategyNumber, F_OIDEQ,
4252
ObjectIdGetDatum(conoid));
4254
tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
4255
SnapshotNow, 1, &skey);
4257
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
4259
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
4262
* Silently skip triggers that are marked as non-deferrable in
4263
* pg_trigger. This is not an error condition, since a
4264
* deferrable RI constraint may have some non-deferrable
4267
if (pg_trigger->tgdeferrable)
4268
tgoidlist = lappend_oid(tgoidlist,
4269
HeapTupleGetOid(htup));
4274
systable_endscan(tgscan);
4276
/* Safety check: a deferrable constraint should have triggers */
4278
elog(ERROR, "no triggers found for constraint with OID %u",
4282
heap_close(tgrel, AccessShareLock);
4285
* Now we can set the trigger states of individual triggers for this
4288
foreach(lc, tgoidlist)
4290
Oid tgoid = lfirst_oid(lc);
4291
SetConstraintState state = afterTriggers->state;
4295
for (i = 0; i < state->numstates; i++)
4297
if (state->trigstates[i].sct_tgoid == tgoid)
4299
state->trigstates[i].sct_tgisdeferred = stmt->deferred;
4306
afterTriggers->state =
4307
SetConstraintStateAddItem(state, tgoid, stmt->deferred);
4313
* SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
4314
* checks against that constraint must be made when the SET CONSTRAINTS
4315
* command is executed -- i.e. the effects of the SET CONSTRAINTS command
4316
* apply retroactively. We've updated the constraints state, so scan the
4317
* list of previously deferred events to fire any that have now become
4320
* Obviously, if this was SET ... DEFERRED then it can't have converted
4321
* any unfired events to immediate, so we need do nothing in that case.
4323
if (!stmt->deferred)
4325
AfterTriggerEventList *events = &afterTriggers->events;
4326
bool snapshot_set = false;
4328
while (afterTriggerMarkEvents(events, NULL, true))
4330
CommandId firing_id = afterTriggers->firing_counter++;
4333
* Make sure a snapshot has been established in case trigger
4334
* functions need one. Note that we avoid setting a snapshot if
4335
* we don't find at least one trigger that has to be fired now.
4336
* This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
4337
* ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
4338
* at the start of a transaction it's not possible for any trigger
4339
* events to be queued yet.)
4343
PushActiveSnapshot(GetTransactionSnapshot());
4344
snapshot_set = true;
4348
* We can delete fired events if we are at top transaction level,
4349
* but we'd better not if inside a subtransaction, since the
4350
* subtransaction could later get rolled back.
4352
if (afterTriggerInvokeEvents(events, firing_id, NULL,
4353
!IsSubTransaction()))
4354
break; /* all fired */
4358
PopActiveSnapshot();
4363
* AfterTriggerPendingOnRel()
4364
* Test to see if there are any pending after-trigger events for rel.
4366
* This is used by TRUNCATE, CLUSTER, ALTER TABLE, etc to detect whether
4367
* it is unsafe to perform major surgery on a relation. Note that only
4368
* local pending events are examined. We assume that having exclusive lock
4369
* on a rel guarantees there are no unserviced events in other backends ---
4370
* but having a lock does not prevent there being such events in our own.
4372
* In some scenarios it'd be reasonable to remove pending events (more
4373
* specifically, mark them DONE by the current subxact) but without a lot
4374
* of knowledge of the trigger semantics we can't do this in general.
4378
AfterTriggerPendingOnRel(Oid relid)
4380
AfterTriggerEvent event;
4381
AfterTriggerEventChunk *chunk;
4384
/* No-op if we aren't in a transaction. (Shouldn't happen?) */
4385
if (afterTriggers == NULL)
4388
/* Scan queued events */
4389
for_each_event_chunk(event, chunk, afterTriggers->events)
4391
AfterTriggerShared evtshared = GetTriggerSharedData(event);
4394
* We can ignore completed events. (Even if a DONE flag is rolled
4395
* back by subxact abort, it's OK because the effects of the TRUNCATE
4396
* or whatever must get rolled back too.)
4398
if (event->ate_flags & AFTER_TRIGGER_DONE)
4401
if (evtshared->ats_relid == relid)
4406
* Also scan events queued by incomplete queries. This could only matter
4407
* if TRUNCATE/etc is executed by a function or trigger within an updating
4408
* query on the same relation, which is pretty perverse, but let's check.
4410
for (depth = 0; depth <= afterTriggers->query_depth; depth++)
4412
for_each_event_chunk(event, chunk, afterTriggers->query_stack[depth])
4414
AfterTriggerShared evtshared = GetTriggerSharedData(event);
4416
if (event->ate_flags & AFTER_TRIGGER_DONE)
4419
if (evtshared->ats_relid == relid)
4429
* AfterTriggerSaveEvent()
4431
* Called by ExecA[RS]...Triggers() to queue up the triggers that should
4432
* be fired for an event.
4434
* NOTE: this is called whenever there are any triggers associated with
4435
* the event (even if they are disabled). This function decides which
4436
* triggers actually need to be queued.
4440
AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
4441
int event, bool row_trigger,
4442
HeapTuple oldtup, HeapTuple newtup,
4443
List *recheckIndexes, Bitmapset *modifiedCols)
4445
Relation rel = relinfo->ri_RelationDesc;
4446
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
4447
AfterTriggerEventData new_event;
4448
AfterTriggerSharedData new_shared;
4454
* Check state. We use normal tests not Asserts because it is possible to
4455
* reach here in the wrong state given misconfigured RI triggers, in
4456
* particular deferring a cascade action trigger.
4458
if (afterTriggers == NULL)
4459
elog(ERROR, "AfterTriggerSaveEvent() called outside of transaction");
4460
if (afterTriggers->query_depth < 0)
4461
elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
4464
* Validate the event code and collect the associated tuple CTIDs.
4466
* The event code will be used both as a bitmask and an array offset, so
4467
* validation is important to make sure we don't walk off the edge of our
4470
new_event.ate_flags = 0;
4473
case TRIGGER_EVENT_INSERT:
4474
tgtype_event = TRIGGER_TYPE_INSERT;
4477
Assert(oldtup == NULL);
4478
Assert(newtup != NULL);
4479
ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
4480
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4484
Assert(oldtup == NULL);
4485
Assert(newtup == NULL);
4486
ItemPointerSetInvalid(&(new_event.ate_ctid1));
4487
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4490
case TRIGGER_EVENT_DELETE:
4491
tgtype_event = TRIGGER_TYPE_DELETE;
4494
Assert(oldtup != NULL);
4495
Assert(newtup == NULL);
4496
ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4497
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4501
Assert(oldtup == NULL);
4502
Assert(newtup == NULL);
4503
ItemPointerSetInvalid(&(new_event.ate_ctid1));
4504
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4507
case TRIGGER_EVENT_UPDATE:
4508
tgtype_event = TRIGGER_TYPE_UPDATE;
4511
Assert(oldtup != NULL);
4512
Assert(newtup != NULL);
4513
ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4514
ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
4515
new_event.ate_flags |= AFTER_TRIGGER_2CTIDS;
4519
Assert(oldtup == NULL);
4520
Assert(newtup == NULL);
4521
ItemPointerSetInvalid(&(new_event.ate_ctid1));
4522
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4525
case TRIGGER_EVENT_TRUNCATE:
4526
tgtype_event = TRIGGER_TYPE_TRUNCATE;
4527
Assert(oldtup == NULL);
4528
Assert(newtup == NULL);
4529
ItemPointerSetInvalid(&(new_event.ate_ctid1));
4530
ItemPointerSetInvalid(&(new_event.ate_ctid2));
4533
elog(ERROR, "invalid after-trigger event code: %d", event);
4534
tgtype_event = 0; /* keep compiler quiet */
4538
tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
4540
for (i = 0; i < trigdesc->numtriggers; i++)
4542
Trigger *trigger = &trigdesc->triggers[i];
4544
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
4549
if (!TriggerEnabled(estate, relinfo, trigger, event,
4550
modifiedCols, oldtup, newtup))
4554
* If this is an UPDATE of a PK table or FK table that does not change
4555
* the PK or FK respectively, we can skip queuing the event: there is
4556
* no need to fire the trigger.
4558
if (TRIGGER_FIRED_BY_UPDATE(event))
4560
switch (RI_FKey_trigger_type(trigger->tgfoid))
4563
/* Update on PK table */
4564
if (RI_FKey_keyequal_upd_pk(trigger, rel, oldtup, newtup))
4566
/* key unchanged, so skip queuing this event */
4574
* Update on FK table
4576
* There is one exception when updating FK tables: if the
4577
* updated row was inserted by our own transaction and the
4578
* FK is deferred, we still need to fire the trigger. This
4579
* is because our UPDATE will invalidate the INSERT so the
4580
* end-of-transaction INSERT RI trigger will not do
4581
* anything, so we have to do the check for the UPDATE
4584
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(oldtup->t_data)) &&
4585
RI_FKey_keyequal_upd_fk(trigger, rel, oldtup, newtup))
4591
case RI_TRIGGER_NONE:
4592
/* Not an FK trigger */
4598
* If the trigger is a deferred unique constraint check trigger, only
4599
* queue it if the unique constraint was potentially violated, which
4600
* we know from index insertion time.
4602
if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
4604
if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
4605
continue; /* Uniqueness definitely not violated */
4609
* Fill in event structure and add it to the current query's queue.
4611
new_shared.ats_event =
4612
(event & TRIGGER_EVENT_OPMASK) |
4613
(row_trigger ? TRIGGER_EVENT_ROW : 0) |
4614
(trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
4615
(trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
4616
new_shared.ats_tgoid = trigger->tgoid;
4617
new_shared.ats_relid = RelationGetRelid(rel);
4618
new_shared.ats_firing_id = 0;
4620
afterTriggerAddEvent(&afterTriggers->query_stack[afterTriggers->query_depth],
4621
&new_event, &new_shared);