~ubuntu-branches/ubuntu/precise/postgresql-9.1/precise-security

« back to all changes in this revision

Viewing changes to src/backend/commands/trigger.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * trigger.c
 
4
 *        PostgreSQL TRIGGERs support code.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        src/backend/commands/trigger.c
 
11
 *
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
#include "postgres.h"
 
15
 
 
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"
 
43
#include "pgstat.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"
 
57
 
 
58
 
 
59
/* GUC variables */
 
60
int                     SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
 
61
 
 
62
 
 
63
#define GetModifiedColumns(relinfo, estate) \
 
64
        (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)
 
65
 
 
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,
 
70
                                   EPQState *epqstate,
 
71
                                   ResultRelInfo *relinfo,
 
72
                                   ItemPointer tid,
 
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,
 
79
                                        int tgindx,
 
80
                                        FmgrInfo *finfo,
 
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);
 
87
 
 
88
 
 
89
/*
 
90
 * Create a trigger.  Returns the OID of the created trigger.
 
91
 *
 
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.
 
94
 *
 
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.)
 
100
 *
 
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.
 
103
 *
 
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.
 
107
 *
 
108
 * When isInternal is not true we require ACL_TRIGGER permissions on the
 
109
 * relation.  For internal triggers the caller must apply any required
 
110
 * permission checks.
 
111
 *
 
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.
 
114
 */
 
115
Oid
 
116
CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 
117
                          Oid constraintOid, Oid indexOid,
 
118
                          bool isInternal)
 
119
{
 
120
        int16           tgtype;
 
121
        int                     ncolumns;
 
122
        int2       *columns;
 
123
        int2vector *tgattr;
 
124
        Node       *whenClause;
 
125
        List       *whenRtable;
 
126
        char       *qual;
 
127
        Datum           values[Natts_pg_trigger];
 
128
        bool            nulls[Natts_pg_trigger];
 
129
        Relation        rel;
 
130
        AclResult       aclresult;
 
131
        Relation        tgrel;
 
132
        SysScanDesc tgscan;
 
133
        ScanKeyData key;
 
134
        Relation        pgrel;
 
135
        HeapTuple       tuple;
 
136
        Oid                     fargtypes[1];   /* dummy */
 
137
        Oid                     funcoid;
 
138
        Oid                     funcrettype;
 
139
        Oid                     trigoid;
 
140
        char            internaltrigname[NAMEDATALEN];
 
141
        char       *trigname;
 
142
        Oid                     constrrelid = InvalidOid;
 
143
        ObjectAddress myself,
 
144
                                referenced;
 
145
 
 
146
        /*
 
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.
 
152
         */
 
153
        rel = heap_openrv(stmt->relation, ShareRowExclusiveLock);
 
154
 
 
155
        /*
 
156
         * Triggers must be on tables or views, and there are additional
 
157
         * relation-type-specific restrictions.
 
158
         */
 
159
        if (rel->rd_rel->relkind == RELKIND_RELATION)
 
160
        {
 
161
                /* Tables can't have INSTEAD OF triggers */
 
162
                if (stmt->timing != TRIGGER_TYPE_BEFORE &&
 
163
                        stmt->timing != TRIGGER_TYPE_AFTER)
 
164
                        ereport(ERROR,
 
165
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
166
                                         errmsg("\"%s\" is a table",
 
167
                                                        RelationGetRelationName(rel)),
 
168
                                         errdetail("Tables cannot have INSTEAD OF triggers.")));
 
169
        }
 
170
        else if (rel->rd_rel->relkind == RELKIND_VIEW)
 
171
        {
 
172
                /*
 
173
                 * Views can have INSTEAD OF triggers (which we check below are
 
174
                 * row-level), or statement-level BEFORE/AFTER triggers.
 
175
                 */
 
176
                if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
 
177
                        ereport(ERROR,
 
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))
 
184
                        ereport(ERROR,
 
185
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
186
                                         errmsg("\"%s\" is a view",
 
187
                                                        RelationGetRelationName(rel)),
 
188
                                         errdetail("Views cannot have TRUNCATE triggers.")));
 
189
        }
 
190
        else
 
191
                ereport(ERROR,
 
192
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
193
                                 errmsg("\"%s\" is not a table or view",
 
194
                                                RelationGetRelationName(rel))));
 
195
 
 
196
        if (!allowSystemTableMods && IsSystemRelation(rel))
 
197
                ereport(ERROR,
 
198
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
199
                                 errmsg("permission denied: \"%s\" is a system catalog",
 
200
                                                RelationGetRelationName(rel))));
 
201
 
 
202
        if (stmt->isconstraint && stmt->constrrel != NULL)
 
203
                constrrelid = RangeVarGetRelid(stmt->constrrel, false);
 
204
 
 
205
        /* permission checks */
 
206
        if (!isInternal)
 
207
        {
 
208
                aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
 
209
                                                                          ACL_TRIGGER);
 
210
                if (aclresult != ACLCHECK_OK)
 
211
                        aclcheck_error(aclresult, ACL_KIND_CLASS,
 
212
                                                   RelationGetRelationName(rel));
 
213
 
 
214
                if (OidIsValid(constrrelid))
 
215
                {
 
216
                        aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
 
217
                                                                                  ACL_TRIGGER);
 
218
                        if (aclresult != ACLCHECK_OK)
 
219
                                aclcheck_error(aclresult, ACL_KIND_CLASS,
 
220
                                                           get_rel_name(constrrelid));
 
221
                }
 
222
        }
 
223
 
 
224
        /* Compute tgtype */
 
225
        TRIGGER_CLEAR_TYPE(tgtype);
 
226
        if (stmt->row)
 
227
                TRIGGER_SETT_ROW(tgtype);
 
228
        tgtype |= stmt->timing;
 
229
        tgtype |= stmt->events;
 
230
 
 
231
        /* Disallow ROW-level TRUNCATE triggers */
 
232
        if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
 
233
                ereport(ERROR,
 
234
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
235
                                 errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
 
236
 
 
237
        /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
 
238
        if (TRIGGER_FOR_INSTEAD(tgtype))
 
239
        {
 
240
                if (!TRIGGER_FOR_ROW(tgtype))
 
241
                        ereport(ERROR,
 
242
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
243
                                         errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
 
244
                if (stmt->whenClause)
 
245
                        ereport(ERROR,
 
246
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
247
                                 errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
 
248
                if (stmt->columns != NIL)
 
249
                        ereport(ERROR,
 
250
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
251
                                         errmsg("INSTEAD OF triggers cannot have column lists")));
 
252
        }
 
253
 
 
254
        /*
 
255
         * Parse the WHEN clause, if any
 
256
         */
 
257
        if (stmt->whenClause)
 
258
        {
 
259
                ParseState *pstate;
 
260
                RangeTblEntry *rte;
 
261
                List       *varList;
 
262
                ListCell   *lc;
 
263
 
 
264
                /* Set up a pstate to parse with */
 
265
                pstate = make_parsestate(NULL);
 
266
                pstate->p_sourcetext = queryString;
 
267
 
 
268
                /*
 
269
                 * Set up RTEs for OLD and NEW references.
 
270
                 *
 
271
                 * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
 
272
                 */
 
273
                rte = addRangeTableEntryForRelation(pstate, rel,
 
274
                                                                                        makeAlias("old", NIL),
 
275
                                                                                        false, false);
 
276
                addRTEtoQuery(pstate, rte, false, true, true);
 
277
                rte = addRangeTableEntryForRelation(pstate, rel,
 
278
                                                                                        makeAlias("new", NIL),
 
279
                                                                                        false, false);
 
280
                addRTEtoQuery(pstate, rte, false, true, true);
 
281
 
 
282
                /* Transform expression.  Copy to be sure we don't modify original */
 
283
                whenClause = transformWhereClause(pstate,
 
284
                                                                                  copyObject(stmt->whenClause),
 
285
                                                                                  "WHEN");
 
286
                /* we have to fix its collations too */
 
287
                assign_expr_collations(pstate, whenClause);
 
288
 
 
289
                /*
 
290
                 * No subplans or aggregates, please
 
291
                 */
 
292
                if (pstate->p_hasSubLinks)
 
293
                        ereport(ERROR,
 
294
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
295
                                   errmsg("cannot use subquery in trigger WHEN condition")));
 
296
                if (pstate->p_hasAggs)
 
297
                        ereport(ERROR,
 
298
                                        (errcode(ERRCODE_GROUPING_ERROR),
 
299
                                         errmsg("cannot use aggregate function in trigger WHEN condition")));
 
300
                if (pstate->p_hasWindowFuncs)
 
301
                        ereport(ERROR,
 
302
                                        (errcode(ERRCODE_WINDOWING_ERROR),
 
303
                        errmsg("cannot use window function in trigger WHEN condition")));
 
304
 
 
305
                /*
 
306
                 * Check for disallowed references to OLD/NEW.
 
307
                 *
 
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
 
310
                 * of subselects.
 
311
                 */
 
312
                varList = pull_var_clause(whenClause, PVC_REJECT_PLACEHOLDERS);
 
313
                foreach(lc, varList)
 
314
                {
 
315
                        Var                *var = (Var *) lfirst(lc);
 
316
 
 
317
                        switch (var->varno)
 
318
                        {
 
319
                                case PRS2_OLD_VARNO:
 
320
                                        if (!TRIGGER_FOR_ROW(tgtype))
 
321
                                                ereport(ERROR,
 
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))
 
326
                                                ereport(ERROR,
 
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 */
 
331
                                        break;
 
332
                                case PRS2_NEW_VARNO:
 
333
                                        if (!TRIGGER_FOR_ROW(tgtype))
 
334
                                                ereport(ERROR,
 
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))
 
339
                                                ereport(ERROR,
 
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))
 
344
                                                ereport(ERROR,
 
345
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
346
                                                                 errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
 
347
                                                                 parser_errposition(pstate, var->location)));
 
348
                                        break;
 
349
                                default:
 
350
                                        /* can't happen without add_missing_from, so just elog */
 
351
                                        elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
 
352
                                        break;
 
353
                        }
 
354
                }
 
355
 
 
356
                /* we'll need the rtable for recordDependencyOnExpr */
 
357
                whenRtable = pstate->p_rtable;
 
358
 
 
359
                qual = nodeToString(whenClause);
 
360
 
 
361
                free_parsestate(pstate);
 
362
        }
 
363
        else
 
364
        {
 
365
                whenClause = NULL;
 
366
                whenRtable = NIL;
 
367
                qual = NULL;
 
368
        }
 
369
 
 
370
        /*
 
371
         * Find and validate the trigger function.
 
372
         */
 
373
        funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
 
374
        funcrettype = get_func_rettype(funcoid);
 
375
        if (funcrettype != TRIGGEROID)
 
376
        {
 
377
                /*
 
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.
 
380
                 */
 
381
                if (funcrettype == OPAQUEOID)
 
382
                {
 
383
                        ereport(WARNING,
 
384
                                        (errmsg("changing return type of function %s from \"opaque\" to \"trigger\"",
 
385
                                                        NameListToString(stmt->funcname))));
 
386
                        SetFunctionReturnType(funcoid, TRIGGEROID);
 
387
                }
 
388
                else
 
389
                        ereport(ERROR,
 
390
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 
391
                                         errmsg("function %s must return type \"trigger\"",
 
392
                                                        NameListToString(stmt->funcname))));
 
393
        }
 
394
 
 
395
        /*
 
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.
 
401
         */
 
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)
 
406
        {
 
407
                /* Keep lock on target rel until end of xact */
 
408
                heap_close(rel, NoLock);
 
409
 
 
410
                ConvertTriggerToFK(stmt, funcoid);
 
411
 
 
412
                return InvalidOid;
 
413
        }
 
414
 
 
415
        /*
 
416
         * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
 
417
         * corresponding pg_constraint entry.
 
418
         */
 
419
        if (stmt->isconstraint && !OidIsValid(constraintOid))
 
420
        {
 
421
                /* Internal callers should have made their own constraints */
 
422
                Assert(!isInternal);
 
423
                constraintOid = CreateConstraintEntry(stmt->trigname,
 
424
                                                                                          RelationGetNamespace(rel),
 
425
                                                                                          CONSTRAINT_TRIGGER,
 
426
                                                                                          stmt->deferrable,
 
427
                                                                                          stmt->initdeferred,
 
428
                                                                                          true,
 
429
                                                                                          RelationGetRelid(rel),
 
430
                                                                                          NULL,         /* no conkey */
 
431
                                                                                          0,
 
432
                                                                                          InvalidOid,           /* no domain */
 
433
                                                                                          InvalidOid,           /* no index */
 
434
                                                                                          InvalidOid,           /* no foreign key */
 
435
                                                                                          NULL,
 
436
                                                                                          NULL,
 
437
                                                                                          NULL,
 
438
                                                                                          NULL,
 
439
                                                                                          0,
 
440
                                                                                          ' ',
 
441
                                                                                          ' ',
 
442
                                                                                          ' ',
 
443
                                                                                          NULL,         /* no exclusion */
 
444
                                                                                          NULL,         /* no check constraint */
 
445
                                                                                          NULL,
 
446
                                                                                          NULL,
 
447
                                                                                          true,         /* islocal */
 
448
                                                                                          0);           /* inhcount */
 
449
        }
 
450
 
 
451
        /*
 
452
         * Generate the trigger's OID now, so that we can use it in the name if
 
453
         * needed.
 
454
         */
 
455
        tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
 
456
 
 
457
        trigoid = GetNewOid(tgrel);
 
458
 
 
459
        /*
 
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.)
 
463
         */
 
464
        if (isInternal)
 
465
        {
 
466
                snprintf(internaltrigname, sizeof(internaltrigname),
 
467
                                 "%s_%u", stmt->trigname, trigoid);
 
468
                trigname = internaltrigname;
 
469
        }
 
470
        else
 
471
        {
 
472
                /* user-defined trigger; use the specified trigger name as-is */
 
473
                trigname = stmt->trigname;
 
474
        }
 
475
 
 
476
        /*
 
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.
 
482
         *
 
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.
 
485
         */
 
486
        if (!isInternal)
 
487
        {
 
488
                ScanKeyInit(&key,
 
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)))
 
495
                {
 
496
                        Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
 
497
 
 
498
                        if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
 
499
                                ereport(ERROR,
 
500
                                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
501
                                  errmsg("trigger \"%s\" for relation \"%s\" already exists",
 
502
                                                 trigname, stmt->relation->relname)));
 
503
                }
 
504
                systable_endscan(tgscan);
 
505
        }
 
506
 
 
507
        /*
 
508
         * Build the new pg_trigger tuple.
 
509
         */
 
510
        memset(nulls, false, sizeof(nulls));
 
511
 
 
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);
 
524
 
 
525
        if (stmt->args)
 
526
        {
 
527
                ListCell   *le;
 
528
                char       *args;
 
529
                int16           nargs = list_length(stmt->args);
 
530
                int                     len = 0;
 
531
 
 
532
                foreach(le, stmt->args)
 
533
                {
 
534
                        char       *ar = strVal(lfirst(le));
 
535
 
 
536
                        len += strlen(ar) + 4;
 
537
                        for (; *ar; ar++)
 
538
                        {
 
539
                                if (*ar == '\\')
 
540
                                        len++;
 
541
                        }
 
542
                }
 
543
                args = (char *) palloc(len + 1);
 
544
                args[0] = '\0';
 
545
                foreach(le, stmt->args)
 
546
                {
 
547
                        char       *s = strVal(lfirst(le));
 
548
                        char       *d = args + strlen(args);
 
549
 
 
550
                        while (*s)
 
551
                        {
 
552
                                if (*s == '\\')
 
553
                                        *d++ = '\\';
 
554
                                *d++ = *s++;
 
555
                        }
 
556
                        strcpy(d, "\\000");
 
557
                }
 
558
                values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
 
559
                values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
 
560
                                                                                                          CStringGetDatum(args));
 
561
        }
 
562
        else
 
563
        {
 
564
                values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
 
565
                values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
 
566
                                                                                                                CStringGetDatum(""));
 
567
        }
 
568
 
 
569
        /* build column number array if it's a column-specific trigger */
 
570
        ncolumns = list_length(stmt->columns);
 
571
        if (ncolumns == 0)
 
572
                columns = NULL;
 
573
        else
 
574
        {
 
575
                ListCell   *cell;
 
576
                int                     i = 0;
 
577
 
 
578
                columns = (int2 *) palloc(ncolumns * sizeof(int2));
 
579
                foreach(cell, stmt->columns)
 
580
                {
 
581
                        char       *name = strVal(lfirst(cell));
 
582
                        int2            attnum;
 
583
                        int                     j;
 
584
 
 
585
                        /* Lookup column name.  System columns are not allowed */
 
586
                        attnum = attnameAttNum(rel, name, false);
 
587
                        if (attnum == InvalidAttrNumber)
 
588
                                ereport(ERROR,
 
589
                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
590
                                        errmsg("column \"%s\" of relation \"%s\" does not exist",
 
591
                                                   name, RelationGetRelationName(rel))));
 
592
 
 
593
                        /* Check for duplicates */
 
594
                        for (j = i - 1; j >= 0; j--)
 
595
                        {
 
596
                                if (columns[j] == attnum)
 
597
                                        ereport(ERROR,
 
598
                                                        (errcode(ERRCODE_DUPLICATE_COLUMN),
 
599
                                                         errmsg("column \"%s\" specified more than once",
 
600
                                                                        name)));
 
601
                        }
 
602
 
 
603
                        columns[i++] = attnum;
 
604
                }
 
605
        }
 
606
        tgattr = buildint2vector(columns, ncolumns);
 
607
        values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
 
608
 
 
609
        /* set tgqual if trigger has WHEN clause */
 
610
        if (qual)
 
611
                values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
 
612
        else
 
613
                nulls[Anum_pg_trigger_tgqual - 1] = true;
 
614
 
 
615
        tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
 
616
 
 
617
        /* force tuple to have the desired OID */
 
618
        HeapTupleSetOid(tuple, trigoid);
 
619
 
 
620
        /*
 
621
         * Insert tuple into pg_trigger.
 
622
         */
 
623
        simple_heap_insert(tgrel, tuple);
 
624
 
 
625
        CatalogUpdateIndexes(tgrel, tuple);
 
626
 
 
627
        heap_freetuple(tuple);
 
628
        heap_close(tgrel, RowExclusiveLock);
 
629
 
 
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]));
 
633
 
 
634
        /*
 
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
 
637
         * entries.
 
638
         */
 
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));
 
645
 
 
646
        ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
 
647
 
 
648
        simple_heap_update(pgrel, &tuple->t_self, tuple);
 
649
 
 
650
        CatalogUpdateIndexes(pgrel, tuple);
 
651
 
 
652
        heap_freetuple(tuple);
 
653
        heap_close(pgrel, RowExclusiveLock);
 
654
 
 
655
        /*
 
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...
 
659
         */
 
660
 
 
661
        /*
 
662
         * Record dependencies for trigger.  Always place a normal dependency on
 
663
         * the function.
 
664
         */
 
665
        myself.classId = TriggerRelationId;
 
666
        myself.objectId = trigoid;
 
667
        myself.objectSubId = 0;
 
668
 
 
669
        referenced.classId = ProcedureRelationId;
 
670
        referenced.objectId = funcoid;
 
671
        referenced.objectSubId = 0;
 
672
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
673
 
 
674
        if (isInternal && OidIsValid(constraintOid))
 
675
        {
 
676
                /*
 
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
 
680
                 * constraint.
 
681
                 */
 
682
                referenced.classId = ConstraintRelationId;
 
683
                referenced.objectId = constraintOid;
 
684
                referenced.objectSubId = 0;
 
685
                recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
 
686
        }
 
687
        else
 
688
        {
 
689
                /*
 
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.)
 
693
                 */
 
694
                referenced.classId = RelationRelationId;
 
695
                referenced.objectId = RelationGetRelid(rel);
 
696
                referenced.objectSubId = 0;
 
697
                recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
698
                if (OidIsValid(constrrelid))
 
699
                {
 
700
                        referenced.classId = RelationRelationId;
 
701
                        referenced.objectId = constrrelid;
 
702
                        referenced.objectSubId = 0;
 
703
                        recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
704
                }
 
705
                /* Not possible to have an index dependency in this case */
 
706
                Assert(!OidIsValid(indexOid));
 
707
 
 
708
                /*
 
709
                 * If it's a user-specified constraint trigger, make the constraint
 
710
                 * internally dependent on the trigger instead of vice versa.
 
711
                 */
 
712
                if (OidIsValid(constraintOid))
 
713
                {
 
714
                        referenced.classId = ConstraintRelationId;
 
715
                        referenced.objectId = constraintOid;
 
716
                        referenced.objectSubId = 0;
 
717
                        recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 
718
                }
 
719
        }
 
720
 
 
721
        /* If column-specific trigger, add normal dependencies on columns */
 
722
        if (columns != NULL)
 
723
        {
 
724
                int                     i;
 
725
 
 
726
                referenced.classId = RelationRelationId;
 
727
                referenced.objectId = RelationGetRelid(rel);
 
728
                for (i = 0; i < ncolumns; i++)
 
729
                {
 
730
                        referenced.objectSubId = columns[i];
 
731
                        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
732
                }
 
733
        }
 
734
 
 
735
        /*
 
736
         * If it has a WHEN clause, add dependencies on objects mentioned in the
 
737
         * expression (eg, functions, as well as any columns used).
 
738
         */
 
739
        if (whenClause != NULL)
 
740
                recordDependencyOnExpr(&myself, whenClause, whenRtable,
 
741
                                                           DEPENDENCY_NORMAL);
 
742
 
 
743
        /* Post creation hook for new trigger */
 
744
        InvokeObjectAccessHook(OAT_POST_CREATE,
 
745
                                                   TriggerRelationId, trigoid, 0);
 
746
 
 
747
        /* Keep lock on target rel until end of xact */
 
748
        heap_close(rel, NoLock);
 
749
 
 
750
        return trigoid;
 
751
}
 
752
 
 
753
 
 
754
/*
 
755
 * Convert legacy (pre-7.3) CREATE CONSTRAINT TRIGGER commands into
 
756
 * full-fledged foreign key constraints.
 
757
 *
 
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).
 
772
 */
 
773
typedef struct
 
774
{
 
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 */
 
778
} OldTriggerInfo;
 
779
 
 
780
static void
 
781
ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
 
782
{
 
783
        static List *info_list = NIL;
 
784
 
 
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.")
 
789
        };
 
790
 
 
791
        char       *constr_name;
 
792
        char       *fk_table_name;
 
793
        char       *pk_table_name;
 
794
        char            fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED;
 
795
        List       *fk_attrs = NIL;
 
796
        List       *pk_attrs = NIL;
 
797
        StringInfoData buf;
 
798
        int                     funcnum;
 
799
        OldTriggerInfo *info = NULL;
 
800
        ListCell   *l;
 
801
        int                     i;
 
802
 
 
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));
 
807
        i = 0;
 
808
        foreach(l, stmt->args)
 
809
        {
 
810
                Value      *arg = (Value *) lfirst(l);
 
811
 
 
812
                i++;
 
813
                if (i < 4)                              /* skip constraint and table names */
 
814
                        continue;
 
815
                if (i == 4)                             /* handle match type */
 
816
                {
 
817
                        if (strcmp(strVal(arg), "FULL") == 0)
 
818
                                fk_matchtype = FKCONSTR_MATCH_FULL;
 
819
                        else
 
820
                                fk_matchtype = FKCONSTR_MATCH_UNSPECIFIED;
 
821
                        continue;
 
822
                }
 
823
                if (i % 2)
 
824
                        fk_attrs = lappend(fk_attrs, arg);
 
825
                else
 
826
                        pk_attrs = lappend(pk_attrs, arg);
 
827
        }
 
828
 
 
829
        /* Prepare description of constraint for use in messages */
 
830
        initStringInfo(&buf);
 
831
        appendStringInfo(&buf, "FOREIGN KEY %s(",
 
832
                                         quote_identifier(fk_table_name));
 
833
        i = 0;
 
834
        foreach(l, fk_attrs)
 
835
        {
 
836
                Value      *arg = (Value *) lfirst(l);
 
837
 
 
838
                if (i++ > 0)
 
839
                        appendStringInfoChar(&buf, ',');
 
840
                appendStringInfoString(&buf, quote_identifier(strVal(arg)));
 
841
        }
 
842
        appendStringInfo(&buf, ") REFERENCES %s(",
 
843
                                         quote_identifier(pk_table_name));
 
844
        i = 0;
 
845
        foreach(l, pk_attrs)
 
846
        {
 
847
                Value      *arg = (Value *) lfirst(l);
 
848
 
 
849
                if (i++ > 0)
 
850
                        appendStringInfoChar(&buf, ',');
 
851
                appendStringInfoString(&buf, quote_identifier(strVal(arg)));
 
852
        }
 
853
        appendStringInfoChar(&buf, ')');
 
854
 
 
855
        /* Identify class of trigger --- update, delete, or referencing-table */
 
856
        switch (funcoid)
 
857
        {
 
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:
 
863
                        funcnum = 0;
 
864
                        break;
 
865
 
 
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:
 
871
                        funcnum = 1;
 
872
                        break;
 
873
 
 
874
                default:
 
875
                        funcnum = 2;
 
876
                        break;
 
877
        }
 
878
 
 
879
        /* See if we have a match to this trigger */
 
880
        foreach(l, info_list)
 
881
        {
 
882
                info = (OldTriggerInfo *) lfirst(l);
 
883
                if (info->funcoids[funcnum] == InvalidOid &&
 
884
                        equal(info->args, stmt->args))
 
885
                {
 
886
                        info->funcoids[funcnum] = funcoid;
 
887
                        break;
 
888
                }
 
889
        }
 
890
 
 
891
        if (l == NULL)
 
892
        {
 
893
                /* First trigger of set, so create a new list entry */
 
894
                MemoryContext oldContext;
 
895
 
 
896
                ereport(NOTICE,
 
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);
 
906
        }
 
907
        else if (info->funcoids[0] == InvalidOid ||
 
908
                         info->funcoids[1] == InvalidOid ||
 
909
                         info->funcoids[2] == InvalidOid)
 
910
        {
 
911
                /* Second trigger of set */
 
912
                ereport(NOTICE,
 
913
                (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
 
914
                                constr_name, buf.data),
 
915
                 errdetail("%s", _(funcdescr[funcnum]))));
 
916
        }
 
917
        else
 
918
        {
 
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);
 
923
 
 
924
                ereport(NOTICE,
 
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;
 
930
                if (funcnum == 2)
 
931
                {
 
932
                        /* This trigger is on the FK table */
 
933
                        atstmt->relation = stmt->relation;
 
934
                        if (stmt->constrrel)
 
935
                                fkcon->pktable = stmt->constrrel;
 
936
                        else
 
937
                        {
 
938
                                /* Work around ancient pg_dump bug that omitted constrrel */
 
939
                                fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
 
940
                        }
 
941
                }
 
942
                else
 
943
                {
 
944
                        /* This trigger is on the PK table */
 
945
                        fkcon->pktable = stmt->relation;
 
946
                        if (stmt->constrrel)
 
947
                                atstmt->relation = stmt->constrrel;
 
948
                        else
 
949
                        {
 
950
                                /* Work around ancient pg_dump bug that omitted constrrel */
 
951
                                atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
 
952
                        }
 
953
                }
 
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;
 
960
                else
 
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])
 
966
                {
 
967
                        case F_RI_FKEY_NOACTION_UPD:
 
968
                                fkcon->fk_upd_action = FKCONSTR_ACTION_NOACTION;
 
969
                                break;
 
970
                        case F_RI_FKEY_CASCADE_UPD:
 
971
                                fkcon->fk_upd_action = FKCONSTR_ACTION_CASCADE;
 
972
                                break;
 
973
                        case F_RI_FKEY_RESTRICT_UPD:
 
974
                                fkcon->fk_upd_action = FKCONSTR_ACTION_RESTRICT;
 
975
                                break;
 
976
                        case F_RI_FKEY_SETNULL_UPD:
 
977
                                fkcon->fk_upd_action = FKCONSTR_ACTION_SETNULL;
 
978
                                break;
 
979
                        case F_RI_FKEY_SETDEFAULT_UPD:
 
980
                                fkcon->fk_upd_action = FKCONSTR_ACTION_SETDEFAULT;
 
981
                                break;
 
982
                        default:
 
983
                                /* can't get here because of earlier checks */
 
984
                                elog(ERROR, "confused about RI update function");
 
985
                }
 
986
                switch (info->funcoids[1])
 
987
                {
 
988
                        case F_RI_FKEY_NOACTION_DEL:
 
989
                                fkcon->fk_del_action = FKCONSTR_ACTION_NOACTION;
 
990
                                break;
 
991
                        case F_RI_FKEY_CASCADE_DEL:
 
992
                                fkcon->fk_del_action = FKCONSTR_ACTION_CASCADE;
 
993
                                break;
 
994
                        case F_RI_FKEY_RESTRICT_DEL:
 
995
                                fkcon->fk_del_action = FKCONSTR_ACTION_RESTRICT;
 
996
                                break;
 
997
                        case F_RI_FKEY_SETNULL_DEL:
 
998
                                fkcon->fk_del_action = FKCONSTR_ACTION_SETNULL;
 
999
                                break;
 
1000
                        case F_RI_FKEY_SETDEFAULT_DEL:
 
1001
                                fkcon->fk_del_action = FKCONSTR_ACTION_SETDEFAULT;
 
1002
                                break;
 
1003
                        default:
 
1004
                                /* can't get here because of earlier checks */
 
1005
                                elog(ERROR, "confused about RI delete function");
 
1006
                }
 
1007
                fkcon->deferrable = stmt->deferrable;
 
1008
                fkcon->initdeferred = stmt->initdeferred;
 
1009
 
 
1010
                /* ... and execute it */
 
1011
                ProcessUtility((Node *) atstmt,
 
1012
                                           "(generated ALTER TABLE ADD FOREIGN KEY command)",
 
1013
                                           NULL, false, None_Receiver, NULL);
 
1014
 
 
1015
                /* Remove the matched item from the list */
 
1016
                info_list = list_delete_ptr(info_list, info);
 
1017
                pfree(info);
 
1018
                /* We leak the copied args ... not worth worrying about */
 
1019
        }
 
1020
}
 
1021
 
 
1022
 
 
1023
/*
 
1024
 * DropTrigger - drop an individual trigger by name
 
1025
 */
 
1026
void
 
1027
DropTrigger(Oid relid, const char *trigname, DropBehavior behavior,
 
1028
                        bool missing_ok)
 
1029
{
 
1030
        ObjectAddress object;
 
1031
 
 
1032
        object.classId = TriggerRelationId;
 
1033
        object.objectId = get_trigger_oid(relid, trigname, missing_ok);
 
1034
        object.objectSubId = 0;
 
1035
 
 
1036
        if (!OidIsValid(object.objectId))
 
1037
        {
 
1038
                ereport(NOTICE,
 
1039
                  (errmsg("trigger \"%s\" for table \"%s\" does not exist, skipping",
 
1040
                                  trigname, get_rel_name(relid))));
 
1041
                return;
 
1042
        }
 
1043
 
 
1044
        if (!pg_class_ownercheck(relid, GetUserId()))
 
1045
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 
1046
                                           get_rel_name(relid));
 
1047
 
 
1048
        /*
 
1049
         * Do the deletion
 
1050
         */
 
1051
        performDeletion(&object, behavior);
 
1052
}
 
1053
 
 
1054
/*
 
1055
 * Guts of trigger deletion.
 
1056
 */
 
1057
void
 
1058
RemoveTriggerById(Oid trigOid)
 
1059
{
 
1060
        Relation        tgrel;
 
1061
        SysScanDesc tgscan;
 
1062
        ScanKeyData skey[1];
 
1063
        HeapTuple       tup;
 
1064
        Oid                     relid;
 
1065
        Relation        rel;
 
1066
 
 
1067
        tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
 
1068
 
 
1069
        /*
 
1070
         * Find the trigger to delete.
 
1071
         */
 
1072
        ScanKeyInit(&skey[0],
 
1073
                                ObjectIdAttributeNumber,
 
1074
                                BTEqualStrategyNumber, F_OIDEQ,
 
1075
                                ObjectIdGetDatum(trigOid));
 
1076
 
 
1077
        tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
 
1078
                                                                SnapshotNow, 1, skey);
 
1079
 
 
1080
        tup = systable_getnext(tgscan);
 
1081
        if (!HeapTupleIsValid(tup))
 
1082
                elog(ERROR, "could not find tuple for trigger %u", trigOid);
 
1083
 
 
1084
        /*
 
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
 
1088
         * SELECT triggers.
 
1089
         */
 
1090
        relid = ((Form_pg_trigger) GETSTRUCT(tup))->tgrelid;
 
1091
 
 
1092
        rel = heap_open(relid, ShareRowExclusiveLock);
 
1093
 
 
1094
        if (rel->rd_rel->relkind != RELKIND_RELATION &&
 
1095
                rel->rd_rel->relkind != RELKIND_VIEW)
 
1096
                ereport(ERROR,
 
1097
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
1098
                                 errmsg("\"%s\" is not a table or view",
 
1099
                                                RelationGetRelationName(rel))));
 
1100
 
 
1101
        if (!allowSystemTableMods && IsSystemRelation(rel))
 
1102
                ereport(ERROR,
 
1103
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
1104
                                 errmsg("permission denied: \"%s\" is a system catalog",
 
1105
                                                RelationGetRelationName(rel))));
 
1106
 
 
1107
        /*
 
1108
         * Delete the pg_trigger tuple.
 
1109
         */
 
1110
        simple_heap_delete(tgrel, &tup->t_self);
 
1111
 
 
1112
        systable_endscan(tgscan);
 
1113
        heap_close(tgrel, RowExclusiveLock);
 
1114
 
 
1115
        /*
 
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
 
1122
         * no triggers left.
 
1123
         */
 
1124
        CacheInvalidateRelcache(rel);
 
1125
 
 
1126
        /* Keep lock on trigger's rel until end of xact */
 
1127
        heap_close(rel, NoLock);
 
1128
}
 
1129
 
 
1130
/*
 
1131
 * get_trigger_oid - Look up a trigger by name to find its OID.
 
1132
 *
 
1133
 * If missing_ok is false, throw an error if trigger not found.  If
 
1134
 * true, just return InvalidOid.
 
1135
 */
 
1136
Oid
 
1137
get_trigger_oid(Oid relid, const char *trigname, bool missing_ok)
 
1138
{
 
1139
        Relation        tgrel;
 
1140
        ScanKeyData skey[2];
 
1141
        SysScanDesc tgscan;
 
1142
        HeapTuple       tup;
 
1143
        Oid                     oid;
 
1144
 
 
1145
        /*
 
1146
         * Find the trigger, verify permissions, set up object address
 
1147
         */
 
1148
        tgrel = heap_open(TriggerRelationId, AccessShareLock);
 
1149
 
 
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));
 
1158
 
 
1159
        tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
 
1160
                                                                SnapshotNow, 2, skey);
 
1161
 
 
1162
        tup = systable_getnext(tgscan);
 
1163
 
 
1164
        if (!HeapTupleIsValid(tup))
 
1165
        {
 
1166
                if (!missing_ok)
 
1167
                        ereport(ERROR,
 
1168
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
 
1169
                                         errmsg("trigger \"%s\" for table \"%s\" does not exist",
 
1170
                                                        trigname, get_rel_name(relid))));
 
1171
                oid = InvalidOid;
 
1172
        }
 
1173
        else
 
1174
        {
 
1175
                oid = HeapTupleGetOid(tup);
 
1176
        }
 
1177
 
 
1178
        systable_endscan(tgscan);
 
1179
        heap_close(tgrel, AccessShareLock);
 
1180
        return oid;
 
1181
}
 
1182
 
 
1183
/*
 
1184
 *              renametrig              - changes the name of a trigger on a relation
 
1185
 *
 
1186
 *              trigger name is changed in trigger catalog.
 
1187
 *              No record of the previous name is kept.
 
1188
 *
 
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
 
1195
 */
 
1196
void
 
1197
renametrig(Oid relid,
 
1198
                   const char *oldname,
 
1199
                   const char *newname)
 
1200
{
 
1201
        Relation        targetrel;
 
1202
        Relation        tgrel;
 
1203
        HeapTuple       tuple;
 
1204
        SysScanDesc tgscan;
 
1205
        ScanKeyData key[2];
 
1206
 
 
1207
        /*
 
1208
         * Grab an exclusive lock on the target table, which we will NOT release
 
1209
         * until end of transaction.
 
1210
         */
 
1211
        targetrel = heap_open(relid, AccessExclusiveLock);
 
1212
 
 
1213
        /*
 
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.
 
1218
         *
 
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.
 
1221
         */
 
1222
        tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
 
1223
 
 
1224
        /*
 
1225
         * First pass -- look for name conflict
 
1226
         */
 
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)))
 
1238
                ereport(ERROR,
 
1239
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
1240
                                 errmsg("trigger \"%s\" for relation \"%s\" already exists",
 
1241
                                                newname, RelationGetRelationName(targetrel))));
 
1242
        systable_endscan(tgscan);
 
1243
 
 
1244
        /*
 
1245
         * Second pass -- look for trigger existing with oldname and update
 
1246
         */
 
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)))
 
1258
        {
 
1259
                /*
 
1260
                 * Update pg_trigger tuple with new tgname.
 
1261
                 */
 
1262
                tuple = heap_copytuple(tuple);  /* need a modifiable copy */
 
1263
 
 
1264
                namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname, newname);
 
1265
 
 
1266
                simple_heap_update(tgrel, &tuple->t_self, tuple);
 
1267
 
 
1268
                /* keep system catalog indexes current */
 
1269
                CatalogUpdateIndexes(tgrel, tuple);
 
1270
 
 
1271
                /*
 
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...)
 
1275
                 */
 
1276
                CacheInvalidateRelcache(targetrel);
 
1277
        }
 
1278
        else
 
1279
        {
 
1280
                ereport(ERROR,
 
1281
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
1282
                                 errmsg("trigger \"%s\" for table \"%s\" does not exist",
 
1283
                                                oldname, RelationGetRelationName(targetrel))));
 
1284
        }
 
1285
 
 
1286
        systable_endscan(tgscan);
 
1287
 
 
1288
        heap_close(tgrel, RowExclusiveLock);
 
1289
 
 
1290
        /*
 
1291
         * Close rel, but keep exclusive lock!
 
1292
         */
 
1293
        heap_close(targetrel, NoLock);
 
1294
}
 
1295
 
 
1296
 
 
1297
/*
 
1298
 * EnableDisableTrigger()
 
1299
 *
 
1300
 *      Called by ALTER TABLE ENABLE/DISABLE [ REPLICA | ALWAYS ] TRIGGER
 
1301
 *      to change 'tgenabled' field for the specified trigger(s)
 
1302
 *
 
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)
 
1309
 *
 
1310
 * Caller should have checked permissions for the table; here we also
 
1311
 * enforce that superuser privilege is required to alter the state of
 
1312
 * system triggers
 
1313
 */
 
1314
void
 
1315
EnableDisableTrigger(Relation rel, const char *tgname,
 
1316
                                         char fires_when, bool skip_system)
 
1317
{
 
1318
        Relation        tgrel;
 
1319
        int                     nkeys;
 
1320
        ScanKeyData keys[2];
 
1321
        SysScanDesc tgscan;
 
1322
        HeapTuple       tuple;
 
1323
        bool            found;
 
1324
        bool            changed;
 
1325
 
 
1326
        /* Scan the relevant entries in pg_triggers */
 
1327
        tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
 
1328
 
 
1329
        ScanKeyInit(&keys[0],
 
1330
                                Anum_pg_trigger_tgrelid,
 
1331
                                BTEqualStrategyNumber, F_OIDEQ,
 
1332
                                ObjectIdGetDatum(RelationGetRelid(rel)));
 
1333
        if (tgname)
 
1334
        {
 
1335
                ScanKeyInit(&keys[1],
 
1336
                                        Anum_pg_trigger_tgname,
 
1337
                                        BTEqualStrategyNumber, F_NAMEEQ,
 
1338
                                        CStringGetDatum(tgname));
 
1339
                nkeys = 2;
 
1340
        }
 
1341
        else
 
1342
                nkeys = 1;
 
1343
 
 
1344
        tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
 
1345
                                                                SnapshotNow, nkeys, keys);
 
1346
 
 
1347
        found = changed = false;
 
1348
 
 
1349
        while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
 
1350
        {
 
1351
                Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
 
1352
 
 
1353
                if (oldtrig->tgisinternal)
 
1354
                {
 
1355
                        /* system trigger ... ok to process? */
 
1356
                        if (skip_system)
 
1357
                                continue;
 
1358
                        if (!superuser())
 
1359
                                ereport(ERROR,
 
1360
                                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
1361
                                          errmsg("permission denied: \"%s\" is a system trigger",
 
1362
                                                         NameStr(oldtrig->tgname))));
 
1363
                }
 
1364
 
 
1365
                found = true;
 
1366
 
 
1367
                if (oldtrig->tgenabled != fires_when)
 
1368
                {
 
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);
 
1372
 
 
1373
                        newtrig->tgenabled = fires_when;
 
1374
 
 
1375
                        simple_heap_update(tgrel, &newtup->t_self, newtup);
 
1376
 
 
1377
                        /* Keep catalog indexes current */
 
1378
                        CatalogUpdateIndexes(tgrel, newtup);
 
1379
 
 
1380
                        heap_freetuple(newtup);
 
1381
 
 
1382
                        changed = true;
 
1383
                }
 
1384
        }
 
1385
 
 
1386
        systable_endscan(tgscan);
 
1387
 
 
1388
        heap_close(tgrel, RowExclusiveLock);
 
1389
 
 
1390
        if (tgname && !found)
 
1391
                ereport(ERROR,
 
1392
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
1393
                                 errmsg("trigger \"%s\" for table \"%s\" does not exist",
 
1394
                                                tgname, RelationGetRelationName(rel))));
 
1395
 
 
1396
        /*
 
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.
 
1400
         */
 
1401
        if (changed)
 
1402
                CacheInvalidateRelcache(rel);
 
1403
}
 
1404
 
 
1405
 
 
1406
/*
 
1407
 * Build trigger data to attach to the given relcache entry.
 
1408
 *
 
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.
 
1415
 */
 
1416
void
 
1417
RelationBuildTriggers(Relation relation)
 
1418
{
 
1419
        TriggerDesc *trigdesc;
 
1420
        int                     numtrigs;
 
1421
        int                     maxtrigs;
 
1422
        Trigger    *triggers;
 
1423
        Relation        tgrel;
 
1424
        ScanKeyData skey;
 
1425
        SysScanDesc tgscan;
 
1426
        HeapTuple       htup;
 
1427
        MemoryContext oldContext;
 
1428
        int                     i;
 
1429
 
 
1430
        /*
 
1431
         * Allocate a working array to hold the triggers (the array is extended if
 
1432
         * necessary)
 
1433
         */
 
1434
        maxtrigs = 16;
 
1435
        triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
 
1436
        numtrigs = 0;
 
1437
 
 
1438
        /*
 
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.
 
1443
         */
 
1444
        ScanKeyInit(&skey,
 
1445
                                Anum_pg_trigger_tgrelid,
 
1446
                                BTEqualStrategyNumber, F_OIDEQ,
 
1447
                                ObjectIdGetDatum(RelationGetRelid(relation)));
 
1448
 
 
1449
        tgrel = heap_open(TriggerRelationId, AccessShareLock);
 
1450
        tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
 
1451
                                                                SnapshotNow, 1, &skey);
 
1452
 
 
1453
        while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
 
1454
        {
 
1455
                Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
 
1456
                Trigger    *build;
 
1457
                Datum           datum;
 
1458
                bool            isnull;
 
1459
 
 
1460
                if (numtrigs >= maxtrigs)
 
1461
                {
 
1462
                        maxtrigs *= 2;
 
1463
                        triggers = (Trigger *) repalloc(triggers, maxtrigs * sizeof(Trigger));
 
1464
                }
 
1465
                build = &(triggers[numtrigs]);
 
1466
 
 
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)
 
1483
                {
 
1484
                        build->tgattr = (int2 *) palloc(build->tgnattr * sizeof(int2));
 
1485
                        memcpy(build->tgattr, &(pg_trigger->tgattr.values),
 
1486
                                   build->tgnattr * sizeof(int2));
 
1487
                }
 
1488
                else
 
1489
                        build->tgattr = NULL;
 
1490
                if (build->tgnargs > 0)
 
1491
                {
 
1492
                        bytea      *val;
 
1493
                        char       *p;
 
1494
 
 
1495
                        val = DatumGetByteaP(fastgetattr(htup,
 
1496
                                                                                         Anum_pg_trigger_tgargs,
 
1497
                                                                                         tgrel->rd_att, &isnull));
 
1498
                        if (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++)
 
1504
                        {
 
1505
                                build->tgargs[i] = pstrdup(p);
 
1506
                                p += strlen(p) + 1;
 
1507
                        }
 
1508
                }
 
1509
                else
 
1510
                        build->tgargs = NULL;
 
1511
                datum = fastgetattr(htup, Anum_pg_trigger_tgqual,
 
1512
                                                        tgrel->rd_att, &isnull);
 
1513
                if (!isnull)
 
1514
                        build->tgqual = TextDatumGetCString(datum);
 
1515
                else
 
1516
                        build->tgqual = NULL;
 
1517
 
 
1518
                numtrigs++;
 
1519
        }
 
1520
 
 
1521
        systable_endscan(tgscan);
 
1522
        heap_close(tgrel, AccessShareLock);
 
1523
 
 
1524
        /* There might not be any triggers */
 
1525
        if (numtrigs == 0)
 
1526
        {
 
1527
                pfree(triggers);
 
1528
                return;
 
1529
        }
 
1530
 
 
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]));
 
1537
 
 
1538
        /* Copy completed trigdesc into cache storage */
 
1539
        oldContext = MemoryContextSwitchTo(CacheMemoryContext);
 
1540
        relation->trigdesc = CopyTriggerDesc(trigdesc);
 
1541
        MemoryContextSwitchTo(oldContext);
 
1542
 
 
1543
        /* Release working memory */
 
1544
        FreeTriggerDesc(trigdesc);
 
1545
}
 
1546
 
 
1547
/*
 
1548
 * Update the TriggerDesc's hint flags to include the specified trigger
 
1549
 */
 
1550
static void
 
1551
SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger)
 
1552
{
 
1553
        int16           tgtype = trigger->tgtype;
 
1554
 
 
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);
 
1607
}
 
1608
 
 
1609
/*
 
1610
 * Copy a TriggerDesc data structure.
 
1611
 *
 
1612
 * The copy is allocated in the current memory context.
 
1613
 */
 
1614
TriggerDesc *
 
1615
CopyTriggerDesc(TriggerDesc *trigdesc)
 
1616
{
 
1617
        TriggerDesc *newdesc;
 
1618
        Trigger    *trigger;
 
1619
        int                     i;
 
1620
 
 
1621
        if (trigdesc == NULL || trigdesc->numtriggers <= 0)
 
1622
                return NULL;
 
1623
 
 
1624
        newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
 
1625
        memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
 
1626
 
 
1627
        trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
 
1628
        memcpy(trigger, trigdesc->triggers,
 
1629
                   trigdesc->numtriggers * sizeof(Trigger));
 
1630
        newdesc->triggers = trigger;
 
1631
 
 
1632
        for (i = 0; i < trigdesc->numtriggers; i++)
 
1633
        {
 
1634
                trigger->tgname = pstrdup(trigger->tgname);
 
1635
                if (trigger->tgnattr > 0)
 
1636
                {
 
1637
                        int2       *newattr;
 
1638
 
 
1639
                        newattr = (int2 *) palloc(trigger->tgnattr * sizeof(int2));
 
1640
                        memcpy(newattr, trigger->tgattr,
 
1641
                                   trigger->tgnattr * sizeof(int2));
 
1642
                        trigger->tgattr = newattr;
 
1643
                }
 
1644
                if (trigger->tgnargs > 0)
 
1645
                {
 
1646
                        char      **newargs;
 
1647
                        int16           j;
 
1648
 
 
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;
 
1653
                }
 
1654
                if (trigger->tgqual)
 
1655
                        trigger->tgqual = pstrdup(trigger->tgqual);
 
1656
                trigger++;
 
1657
        }
 
1658
 
 
1659
        return newdesc;
 
1660
}
 
1661
 
 
1662
/*
 
1663
 * Free a TriggerDesc data structure.
 
1664
 */
 
1665
void
 
1666
FreeTriggerDesc(TriggerDesc *trigdesc)
 
1667
{
 
1668
        Trigger    *trigger;
 
1669
        int                     i;
 
1670
 
 
1671
        if (trigdesc == NULL)
 
1672
                return;
 
1673
 
 
1674
        trigger = trigdesc->triggers;
 
1675
        for (i = 0; i < trigdesc->numtriggers; i++)
 
1676
        {
 
1677
                pfree(trigger->tgname);
 
1678
                if (trigger->tgnattr > 0)
 
1679
                        pfree(trigger->tgattr);
 
1680
                if (trigger->tgnargs > 0)
 
1681
                {
 
1682
                        while (--(trigger->tgnargs) >= 0)
 
1683
                                pfree(trigger->tgargs[trigger->tgnargs]);
 
1684
                        pfree(trigger->tgargs);
 
1685
                }
 
1686
                if (trigger->tgqual)
 
1687
                        pfree(trigger->tgqual);
 
1688
                trigger++;
 
1689
        }
 
1690
        pfree(trigdesc->triggers);
 
1691
        pfree(trigdesc);
 
1692
}
 
1693
 
 
1694
/*
 
1695
 * Compare two TriggerDesc structures for logical equality.
 
1696
 */
 
1697
#ifdef NOT_USED
 
1698
bool
 
1699
equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
 
1700
{
 
1701
        int                     i,
 
1702
                                j;
 
1703
 
 
1704
        /*
 
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.
 
1707
         *
 
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.
 
1710
         *
 
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.
 
1715
         */
 
1716
        if (trigdesc1 != NULL)
 
1717
        {
 
1718
                if (trigdesc2 == NULL)
 
1719
                        return false;
 
1720
                if (trigdesc1->numtriggers != trigdesc2->numtriggers)
 
1721
                        return false;
 
1722
                for (i = 0; i < trigdesc1->numtriggers; i++)
 
1723
                {
 
1724
                        Trigger    *trig1 = trigdesc1->triggers + i;
 
1725
                        Trigger    *trig2 = trigdesc2->triggers + i;
 
1726
 
 
1727
                        if (trig1->tgoid != trig2->tgoid)
 
1728
                                return false;
 
1729
                        if (strcmp(trig1->tgname, trig2->tgname) != 0)
 
1730
                                return false;
 
1731
                        if (trig1->tgfoid != trig2->tgfoid)
 
1732
                                return false;
 
1733
                        if (trig1->tgtype != trig2->tgtype)
 
1734
                                return false;
 
1735
                        if (trig1->tgenabled != trig2->tgenabled)
 
1736
                                return false;
 
1737
                        if (trig1->tgisinternal != trig2->tgisinternal)
 
1738
                                return false;
 
1739
                        if (trig1->tgconstrrelid != trig2->tgconstrrelid)
 
1740
                                return false;
 
1741
                        if (trig1->tgconstrindid != trig2->tgconstrindid)
 
1742
                                return false;
 
1743
                        if (trig1->tgconstraint != trig2->tgconstraint)
 
1744
                                return false;
 
1745
                        if (trig1->tgdeferrable != trig2->tgdeferrable)
 
1746
                                return false;
 
1747
                        if (trig1->tginitdeferred != trig2->tginitdeferred)
 
1748
                                return false;
 
1749
                        if (trig1->tgnargs != trig2->tgnargs)
 
1750
                                return false;
 
1751
                        if (trig1->tgnattr != trig2->tgnattr)
 
1752
                                return false;
 
1753
                        if (trig1->tgnattr > 0 &&
 
1754
                                memcmp(trig1->tgattr, trig2->tgattr,
 
1755
                                           trig1->tgnattr * sizeof(int2)) != 0)
 
1756
                                return false;
 
1757
                        for (j = 0; j < trig1->tgnargs; j++)
 
1758
                                if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
 
1759
                                        return false;
 
1760
                        if (trig1->tgqual == NULL && trig2->tgqual == NULL)
 
1761
                                 /* ok */ ;
 
1762
                        else if (trig1->tgqual == NULL || trig2->tgqual == NULL)
 
1763
                                return false;
 
1764
                        else if (strcmp(trig1->tgqual, trig2->tgqual) != 0)
 
1765
                                return false;
 
1766
                }
 
1767
        }
 
1768
        else if (trigdesc2 != NULL)
 
1769
                return false;
 
1770
        return true;
 
1771
}
 
1772
#endif   /* NOT_USED */
 
1773
 
 
1774
/*
 
1775
 * Call a trigger function.
 
1776
 *
 
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.
 
1782
 *
 
1783
 * Returns the tuple (or NULL) as returned by the function.
 
1784
 */
 
1785
static HeapTuple
 
1786
ExecCallTriggerFunc(TriggerData *trigdata,
 
1787
                                        int tgindx,
 
1788
                                        FmgrInfo *finfo,
 
1789
                                        Instrumentation *instr,
 
1790
                                        MemoryContext per_tuple_context)
 
1791
{
 
1792
        FunctionCallInfoData fcinfo;
 
1793
        PgStat_FunctionCallUsage fcusage;
 
1794
        Datum           result;
 
1795
        MemoryContext oldContext;
 
1796
 
 
1797
        finfo += tgindx;
 
1798
 
 
1799
        /*
 
1800
         * We cache fmgr lookup info, to avoid making the lookup again on each
 
1801
         * call.
 
1802
         */
 
1803
        if (finfo->fn_oid == InvalidOid)
 
1804
                fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
 
1805
 
 
1806
        Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
 
1807
 
 
1808
        /*
 
1809
         * If doing EXPLAIN ANALYZE, start charging time to this trigger.
 
1810
         */
 
1811
        if (instr)
 
1812
                InstrStartNode(instr + tgindx);
 
1813
 
 
1814
        /*
 
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
 
1818
         * the tuple cycle.
 
1819
         */
 
1820
        oldContext = MemoryContextSwitchTo(per_tuple_context);
 
1821
 
 
1822
        /*
 
1823
         * Call the function, passing no arguments but setting a context.
 
1824
         */
 
1825
        InitFunctionCallInfoData(fcinfo, finfo, 0,
 
1826
                                                         InvalidOid, (Node *) trigdata, NULL);
 
1827
 
 
1828
        pgstat_init_function_usage(&fcinfo, &fcusage);
 
1829
 
 
1830
        result = FunctionCallInvoke(&fcinfo);
 
1831
 
 
1832
        pgstat_end_function_usage(&fcusage, true);
 
1833
 
 
1834
        MemoryContextSwitchTo(oldContext);
 
1835
 
 
1836
        /*
 
1837
         * Trigger protocol allows function to return a null pointer, but NOT to
 
1838
         * set the isnull result flag.
 
1839
         */
 
1840
        if (fcinfo.isnull)
 
1841
                ereport(ERROR,
 
1842
                                (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
 
1843
                                 errmsg("trigger function %u returned null value",
 
1844
                                                fcinfo.flinfo->fn_oid)));
 
1845
 
 
1846
        /*
 
1847
         * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
 
1848
         * one "tuple returned" (really the number of firings).
 
1849
         */
 
1850
        if (instr)
 
1851
                InstrStopNode(instr + tgindx, 1);
 
1852
 
 
1853
        return (HeapTuple) DatumGetPointer(result);
 
1854
}
 
1855
 
 
1856
void
 
1857
ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
 
1858
{
 
1859
        TriggerDesc *trigdesc;
 
1860
        int                     i;
 
1861
        TriggerData LocTriggerData;
 
1862
 
 
1863
        trigdesc = relinfo->ri_TrigDesc;
 
1864
 
 
1865
        if (trigdesc == NULL)
 
1866
                return;
 
1867
        if (!trigdesc->trig_insert_before_statement)
 
1868
                return;
 
1869
 
 
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++)
 
1879
        {
 
1880
                Trigger    *trigger = &trigdesc->triggers[i];
 
1881
                HeapTuple       newtuple;
 
1882
 
 
1883
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
1884
                                                                  TRIGGER_TYPE_STATEMENT,
 
1885
                                                                  TRIGGER_TYPE_BEFORE,
 
1886
                                                                  TRIGGER_TYPE_INSERT))
 
1887
                        continue;
 
1888
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
1889
                                                        NULL, NULL, NULL))
 
1890
                        continue;
 
1891
 
 
1892
                LocTriggerData.tg_trigger = trigger;
 
1893
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
1894
                                                                           i,
 
1895
                                                                           relinfo->ri_TrigFunctions,
 
1896
                                                                           relinfo->ri_TrigInstrument,
 
1897
                                                                           GetPerTupleMemoryContext(estate));
 
1898
 
 
1899
                if (newtuple)
 
1900
                        ereport(ERROR,
 
1901
                                        (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
 
1902
                                  errmsg("BEFORE STATEMENT trigger cannot return a value")));
 
1903
        }
 
1904
}
 
1905
 
 
1906
void
 
1907
ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
 
1908
{
 
1909
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
1910
 
 
1911
        if (trigdesc && trigdesc->trig_insert_after_statement)
 
1912
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
 
1913
                                                          false, NULL, NULL, NIL, NULL);
 
1914
}
 
1915
 
 
1916
TupleTableSlot *
 
1917
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
 
1918
                                         TupleTableSlot *slot)
 
1919
{
 
1920
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
1921
        HeapTuple       slottuple = ExecMaterializeSlot(slot);
 
1922
        HeapTuple       newtuple = slottuple;
 
1923
        HeapTuple       oldtuple;
 
1924
        TriggerData LocTriggerData;
 
1925
        int                     i;
 
1926
 
 
1927
        LocTriggerData.type = T_TriggerData;
 
1928
        LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
 
1929
                TRIGGER_EVENT_ROW |
 
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++)
 
1935
        {
 
1936
                Trigger    *trigger = &trigdesc->triggers[i];
 
1937
 
 
1938
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
1939
                                                                  TRIGGER_TYPE_ROW,
 
1940
                                                                  TRIGGER_TYPE_BEFORE,
 
1941
                                                                  TRIGGER_TYPE_INSERT))
 
1942
                        continue;
 
1943
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
1944
                                                        NULL, NULL, newtuple))
 
1945
                        continue;
 
1946
 
 
1947
                LocTriggerData.tg_trigtuple = oldtuple = newtuple;
 
1948
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
 
1949
                LocTriggerData.tg_trigger = trigger;
 
1950
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
1951
                                                                           i,
 
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" */
 
1959
        }
 
1960
 
 
1961
        if (newtuple != slottuple)
 
1962
        {
 
1963
                /*
 
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
 
1967
                 * clear it.
 
1968
                 */
 
1969
                TupleTableSlot *newslot = estate->es_trig_tuple_slot;
 
1970
                TupleDesc       tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
 
1971
 
 
1972
                if (newslot->tts_tupleDescriptor != tupdesc)
 
1973
                        ExecSetSlotDescriptor(newslot, tupdesc);
 
1974
                ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
 
1975
                slot = newslot;
 
1976
        }
 
1977
        return slot;
 
1978
}
 
1979
 
 
1980
void
 
1981
ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
 
1982
                                         HeapTuple trigtuple, List *recheckIndexes)
 
1983
{
 
1984
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
1985
 
 
1986
        if (trigdesc && trigdesc->trig_insert_after_row)
 
1987
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
 
1988
                                                          true, NULL, trigtuple, recheckIndexes, NULL);
 
1989
}
 
1990
 
 
1991
TupleTableSlot *
 
1992
ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
 
1993
                                         TupleTableSlot *slot)
 
1994
{
 
1995
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
1996
        HeapTuple       slottuple = ExecMaterializeSlot(slot);
 
1997
        HeapTuple       newtuple = slottuple;
 
1998
        HeapTuple       oldtuple;
 
1999
        TriggerData LocTriggerData;
 
2000
        int                     i;
 
2001
 
 
2002
        LocTriggerData.type = T_TriggerData;
 
2003
        LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
 
2004
                TRIGGER_EVENT_ROW |
 
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++)
 
2010
        {
 
2011
                Trigger    *trigger = &trigdesc->triggers[i];
 
2012
 
 
2013
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2014
                                                                  TRIGGER_TYPE_ROW,
 
2015
                                                                  TRIGGER_TYPE_INSTEAD,
 
2016
                                                                  TRIGGER_TYPE_INSERT))
 
2017
                        continue;
 
2018
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2019
                                                        NULL, NULL, newtuple))
 
2020
                        continue;
 
2021
 
 
2022
                LocTriggerData.tg_trigtuple = oldtuple = newtuple;
 
2023
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
 
2024
                LocTriggerData.tg_trigger = trigger;
 
2025
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
2026
                                                                           i,
 
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" */
 
2034
        }
 
2035
 
 
2036
        if (newtuple != slottuple)
 
2037
        {
 
2038
                /*
 
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
 
2042
                 * clear it.
 
2043
                 */
 
2044
                TupleTableSlot *newslot = estate->es_trig_tuple_slot;
 
2045
                TupleDesc       tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
 
2046
 
 
2047
                if (newslot->tts_tupleDescriptor != tupdesc)
 
2048
                        ExecSetSlotDescriptor(newslot, tupdesc);
 
2049
                ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
 
2050
                slot = newslot;
 
2051
        }
 
2052
        return slot;
 
2053
}
 
2054
 
 
2055
void
 
2056
ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
 
2057
{
 
2058
        TriggerDesc *trigdesc;
 
2059
        int                     i;
 
2060
        TriggerData LocTriggerData;
 
2061
 
 
2062
        trigdesc = relinfo->ri_TrigDesc;
 
2063
 
 
2064
        if (trigdesc == NULL)
 
2065
                return;
 
2066
        if (!trigdesc->trig_delete_before_statement)
 
2067
                return;
 
2068
 
 
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++)
 
2078
        {
 
2079
                Trigger    *trigger = &trigdesc->triggers[i];
 
2080
                HeapTuple       newtuple;
 
2081
 
 
2082
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2083
                                                                  TRIGGER_TYPE_STATEMENT,
 
2084
                                                                  TRIGGER_TYPE_BEFORE,
 
2085
                                                                  TRIGGER_TYPE_DELETE))
 
2086
                        continue;
 
2087
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2088
                                                        NULL, NULL, NULL))
 
2089
                        continue;
 
2090
 
 
2091
                LocTriggerData.tg_trigger = trigger;
 
2092
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
2093
                                                                           i,
 
2094
                                                                           relinfo->ri_TrigFunctions,
 
2095
                                                                           relinfo->ri_TrigInstrument,
 
2096
                                                                           GetPerTupleMemoryContext(estate));
 
2097
 
 
2098
                if (newtuple)
 
2099
                        ereport(ERROR,
 
2100
                                        (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
 
2101
                                  errmsg("BEFORE STATEMENT trigger cannot return a value")));
 
2102
        }
 
2103
}
 
2104
 
 
2105
void
 
2106
ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
 
2107
{
 
2108
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2109
 
 
2110
        if (trigdesc && trigdesc->trig_delete_after_statement)
 
2111
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
 
2112
                                                          false, NULL, NULL, NIL, NULL);
 
2113
}
 
2114
 
 
2115
bool
 
2116
ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
 
2117
                                         ResultRelInfo *relinfo,
 
2118
                                         ItemPointer tupleid)
 
2119
{
 
2120
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2121
        bool            result = true;
 
2122
        TriggerData LocTriggerData;
 
2123
        HeapTuple       trigtuple;
 
2124
        HeapTuple       newtuple;
 
2125
        TupleTableSlot *newSlot;
 
2126
        int                     i;
 
2127
 
 
2128
        trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
 
2129
                                                                   &newSlot);
 
2130
        if (trigtuple == NULL)
 
2131
                return false;
 
2132
 
 
2133
        LocTriggerData.type = T_TriggerData;
 
2134
        LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
 
2135
                TRIGGER_EVENT_ROW |
 
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++)
 
2141
        {
 
2142
                Trigger    *trigger = &trigdesc->triggers[i];
 
2143
 
 
2144
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2145
                                                                  TRIGGER_TYPE_ROW,
 
2146
                                                                  TRIGGER_TYPE_BEFORE,
 
2147
                                                                  TRIGGER_TYPE_DELETE))
 
2148
                        continue;
 
2149
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2150
                                                        NULL, trigtuple, NULL))
 
2151
                        continue;
 
2152
 
 
2153
                LocTriggerData.tg_trigtuple = trigtuple;
 
2154
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
 
2155
                LocTriggerData.tg_trigger = trigger;
 
2156
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
2157
                                                                           i,
 
2158
                                                                           relinfo->ri_TrigFunctions,
 
2159
                                                                           relinfo->ri_TrigInstrument,
 
2160
                                                                           GetPerTupleMemoryContext(estate));
 
2161
                if (newtuple == NULL)
 
2162
                {
 
2163
                        result = false;         /* tell caller to suppress delete */
 
2164
                        break;
 
2165
                }
 
2166
                if (newtuple != trigtuple)
 
2167
                        heap_freetuple(newtuple);
 
2168
        }
 
2169
        heap_freetuple(trigtuple);
 
2170
 
 
2171
        return result;
 
2172
}
 
2173
 
 
2174
void
 
2175
ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
 
2176
                                         ItemPointer tupleid)
 
2177
{
 
2178
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2179
 
 
2180
        if (trigdesc && trigdesc->trig_delete_after_row)
 
2181
        {
 
2182
                HeapTuple       trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
 
2183
                                                                                                   tupleid, NULL);
 
2184
 
 
2185
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
 
2186
                                                          true, trigtuple, NULL, NIL, NULL);
 
2187
                heap_freetuple(trigtuple);
 
2188
        }
 
2189
}
 
2190
 
 
2191
bool
 
2192
ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
 
2193
                                         HeapTuple trigtuple)
 
2194
{
 
2195
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2196
        TriggerData LocTriggerData;
 
2197
        HeapTuple       rettuple;
 
2198
        int                     i;
 
2199
 
 
2200
        LocTriggerData.type = T_TriggerData;
 
2201
        LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
 
2202
                TRIGGER_EVENT_ROW |
 
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++)
 
2208
        {
 
2209
                Trigger    *trigger = &trigdesc->triggers[i];
 
2210
 
 
2211
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2212
                                                                  TRIGGER_TYPE_ROW,
 
2213
                                                                  TRIGGER_TYPE_INSTEAD,
 
2214
                                                                  TRIGGER_TYPE_DELETE))
 
2215
                        continue;
 
2216
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2217
                                                        NULL, trigtuple, NULL))
 
2218
                        continue;
 
2219
 
 
2220
                LocTriggerData.tg_trigtuple = trigtuple;
 
2221
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
 
2222
                LocTriggerData.tg_trigger = trigger;
 
2223
                rettuple = ExecCallTriggerFunc(&LocTriggerData,
 
2224
                                                                           i,
 
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);
 
2232
        }
 
2233
        return true;
 
2234
}
 
2235
 
 
2236
void
 
2237
ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
 
2238
{
 
2239
        TriggerDesc *trigdesc;
 
2240
        int                     i;
 
2241
        TriggerData LocTriggerData;
 
2242
        Bitmapset  *modifiedCols;
 
2243
 
 
2244
        trigdesc = relinfo->ri_TrigDesc;
 
2245
 
 
2246
        if (trigdesc == NULL)
 
2247
                return;
 
2248
        if (!trigdesc->trig_update_before_statement)
 
2249
                return;
 
2250
 
 
2251
        modifiedCols = GetModifiedColumns(relinfo, estate);
 
2252
 
 
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++)
 
2262
        {
 
2263
                Trigger    *trigger = &trigdesc->triggers[i];
 
2264
                HeapTuple       newtuple;
 
2265
 
 
2266
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2267
                                                                  TRIGGER_TYPE_STATEMENT,
 
2268
                                                                  TRIGGER_TYPE_BEFORE,
 
2269
                                                                  TRIGGER_TYPE_UPDATE))
 
2270
                        continue;
 
2271
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2272
                                                        modifiedCols, NULL, NULL))
 
2273
                        continue;
 
2274
 
 
2275
                LocTriggerData.tg_trigger = trigger;
 
2276
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
2277
                                                                           i,
 
2278
                                                                           relinfo->ri_TrigFunctions,
 
2279
                                                                           relinfo->ri_TrigInstrument,
 
2280
                                                                           GetPerTupleMemoryContext(estate));
 
2281
 
 
2282
                if (newtuple)
 
2283
                        ereport(ERROR,
 
2284
                                        (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
 
2285
                                  errmsg("BEFORE STATEMENT trigger cannot return a value")));
 
2286
        }
 
2287
}
 
2288
 
 
2289
void
 
2290
ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
 
2291
{
 
2292
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2293
 
 
2294
        if (trigdesc && trigdesc->trig_update_after_statement)
 
2295
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
 
2296
                                                          false, NULL, NULL, NIL,
 
2297
                                                          GetModifiedColumns(relinfo, estate));
 
2298
}
 
2299
 
 
2300
TupleTableSlot *
 
2301
ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
 
2302
                                         ResultRelInfo *relinfo,
 
2303
                                         ItemPointer tupleid, TupleTableSlot *slot)
 
2304
{
 
2305
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2306
        HeapTuple       slottuple = ExecMaterializeSlot(slot);
 
2307
        HeapTuple       newtuple = slottuple;
 
2308
        TriggerData LocTriggerData;
 
2309
        HeapTuple       trigtuple;
 
2310
        HeapTuple       oldtuple;
 
2311
        TupleTableSlot *newSlot;
 
2312
        int                     i;
 
2313
        Bitmapset  *modifiedCols;
 
2314
 
 
2315
        /* get a copy of the on-disk tuple we are planning to update */
 
2316
        trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
 
2317
                                                                   &newSlot);
 
2318
        if (trigtuple == NULL)
 
2319
                return NULL;                    /* cancel the update action */
 
2320
 
 
2321
        /*
 
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.
 
2326
         *
 
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.
 
2331
         */
 
2332
        if (newSlot != NULL)
 
2333
        {
 
2334
                slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
 
2335
                slottuple = ExecMaterializeSlot(slot);
 
2336
                newtuple = slottuple;
 
2337
        }
 
2338
 
 
2339
        modifiedCols = GetModifiedColumns(relinfo, estate);
 
2340
 
 
2341
        LocTriggerData.type = T_TriggerData;
 
2342
        LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
 
2343
                TRIGGER_EVENT_ROW |
 
2344
                TRIGGER_EVENT_BEFORE;
 
2345
        LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
 
2346
        for (i = 0; i < trigdesc->numtriggers; i++)
 
2347
        {
 
2348
                Trigger    *trigger = &trigdesc->triggers[i];
 
2349
 
 
2350
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2351
                                                                  TRIGGER_TYPE_ROW,
 
2352
                                                                  TRIGGER_TYPE_BEFORE,
 
2353
                                                                  TRIGGER_TYPE_UPDATE))
 
2354
                        continue;
 
2355
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2356
                                                        modifiedCols, trigtuple, newtuple))
 
2357
                        continue;
 
2358
 
 
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,
 
2365
                                                                           i,
 
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)
 
2372
                {
 
2373
                        heap_freetuple(trigtuple);
 
2374
                        return NULL;            /* "do nothing" */
 
2375
                }
 
2376
        }
 
2377
        heap_freetuple(trigtuple);
 
2378
 
 
2379
        if (newtuple != slottuple)
 
2380
        {
 
2381
                /*
 
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
 
2385
                 * clear it.
 
2386
                 */
 
2387
                TupleTableSlot *newslot = estate->es_trig_tuple_slot;
 
2388
                TupleDesc       tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
 
2389
 
 
2390
                if (newslot->tts_tupleDescriptor != tupdesc)
 
2391
                        ExecSetSlotDescriptor(newslot, tupdesc);
 
2392
                ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
 
2393
                slot = newslot;
 
2394
        }
 
2395
        return slot;
 
2396
}
 
2397
 
 
2398
void
 
2399
ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
 
2400
                                         ItemPointer tupleid, HeapTuple newtuple,
 
2401
                                         List *recheckIndexes)
 
2402
{
 
2403
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2404
 
 
2405
        if (trigdesc && trigdesc->trig_update_after_row)
 
2406
        {
 
2407
                HeapTuple       trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
 
2408
                                                                                                   tupleid, NULL);
 
2409
 
 
2410
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
 
2411
                                                          true, trigtuple, newtuple, recheckIndexes,
 
2412
                                                          GetModifiedColumns(relinfo, estate));
 
2413
                heap_freetuple(trigtuple);
 
2414
        }
 
2415
}
 
2416
 
 
2417
TupleTableSlot *
 
2418
ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
 
2419
                                         HeapTuple trigtuple, TupleTableSlot *slot)
 
2420
{
 
2421
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2422
        HeapTuple       slottuple = ExecMaterializeSlot(slot);
 
2423
        HeapTuple       newtuple = slottuple;
 
2424
        TriggerData LocTriggerData;
 
2425
        HeapTuple       oldtuple;
 
2426
        int                     i;
 
2427
 
 
2428
        LocTriggerData.type = T_TriggerData;
 
2429
        LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
 
2430
                TRIGGER_EVENT_ROW |
 
2431
                TRIGGER_EVENT_INSTEAD;
 
2432
        LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
 
2433
        for (i = 0; i < trigdesc->numtriggers; i++)
 
2434
        {
 
2435
                Trigger    *trigger = &trigdesc->triggers[i];
 
2436
 
 
2437
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2438
                                                                  TRIGGER_TYPE_ROW,
 
2439
                                                                  TRIGGER_TYPE_INSTEAD,
 
2440
                                                                  TRIGGER_TYPE_UPDATE))
 
2441
                        continue;
 
2442
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2443
                                                        NULL, trigtuple, newtuple))
 
2444
                        continue;
 
2445
 
 
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,
 
2452
                                                                           i,
 
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" */
 
2460
        }
 
2461
 
 
2462
        if (newtuple != slottuple)
 
2463
        {
 
2464
                /*
 
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
 
2468
                 * clear it.
 
2469
                 */
 
2470
                TupleTableSlot *newslot = estate->es_trig_tuple_slot;
 
2471
                TupleDesc       tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
 
2472
 
 
2473
                if (newslot->tts_tupleDescriptor != tupdesc)
 
2474
                        ExecSetSlotDescriptor(newslot, tupdesc);
 
2475
                ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
 
2476
                slot = newslot;
 
2477
        }
 
2478
        return slot;
 
2479
}
 
2480
 
 
2481
void
 
2482
ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
 
2483
{
 
2484
        TriggerDesc *trigdesc;
 
2485
        int                     i;
 
2486
        TriggerData LocTriggerData;
 
2487
 
 
2488
        trigdesc = relinfo->ri_TrigDesc;
 
2489
 
 
2490
        if (trigdesc == NULL)
 
2491
                return;
 
2492
        if (!trigdesc->trig_truncate_before_statement)
 
2493
                return;
 
2494
 
 
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++)
 
2504
        {
 
2505
                Trigger    *trigger = &trigdesc->triggers[i];
 
2506
                HeapTuple       newtuple;
 
2507
 
 
2508
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
2509
                                                                  TRIGGER_TYPE_STATEMENT,
 
2510
                                                                  TRIGGER_TYPE_BEFORE,
 
2511
                                                                  TRIGGER_TYPE_TRUNCATE))
 
2512
                        continue;
 
2513
                if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
 
2514
                                                        NULL, NULL, NULL))
 
2515
                        continue;
 
2516
 
 
2517
                LocTriggerData.tg_trigger = trigger;
 
2518
                newtuple = ExecCallTriggerFunc(&LocTriggerData,
 
2519
                                                                           i,
 
2520
                                                                           relinfo->ri_TrigFunctions,
 
2521
                                                                           relinfo->ri_TrigInstrument,
 
2522
                                                                           GetPerTupleMemoryContext(estate));
 
2523
 
 
2524
                if (newtuple)
 
2525
                        ereport(ERROR,
 
2526
                                        (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
 
2527
                                  errmsg("BEFORE STATEMENT trigger cannot return a value")));
 
2528
        }
 
2529
}
 
2530
 
 
2531
void
 
2532
ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
 
2533
{
 
2534
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
2535
 
 
2536
        if (trigdesc && trigdesc->trig_truncate_after_statement)
 
2537
                AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_TRUNCATE,
 
2538
                                                          false, NULL, NULL, NIL, NULL);
 
2539
}
 
2540
 
 
2541
 
 
2542
static HeapTuple
 
2543
GetTupleForTrigger(EState *estate,
 
2544
                                   EPQState *epqstate,
 
2545
                                   ResultRelInfo *relinfo,
 
2546
                                   ItemPointer tid,
 
2547
                                   TupleTableSlot **newSlot)
 
2548
{
 
2549
        Relation        relation = relinfo->ri_RelationDesc;
 
2550
        HeapTupleData tuple;
 
2551
        HeapTuple       result;
 
2552
        Buffer          buffer;
 
2553
 
 
2554
        if (newSlot != NULL)
 
2555
        {
 
2556
                HTSU_Result test;
 
2557
                ItemPointerData update_ctid;
 
2558
                TransactionId update_xmax;
 
2559
 
 
2560
                *newSlot = NULL;
 
2561
 
 
2562
                /* caller must pass an epqstate if EvalPlanQual is possible */
 
2563
                Assert(epqstate != NULL);
 
2564
 
 
2565
                /*
 
2566
                 * lock tuple for update
 
2567
                 */
 
2568
ltrmark:;
 
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);
 
2574
                switch (test)
 
2575
                {
 
2576
                        case HeapTupleSelfUpdated:
 
2577
                                /* treat it as deleted; do not process */
 
2578
                                ReleaseBuffer(buffer);
 
2579
                                return NULL;
 
2580
 
 
2581
                        case HeapTupleMayBeUpdated:
 
2582
                                break;
 
2583
 
 
2584
                        case HeapTupleUpdated:
 
2585
                                ReleaseBuffer(buffer);
 
2586
                                if (IsolationUsesXactSnapshot())
 
2587
                                        ereport(ERROR,
 
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))
 
2591
                                {
 
2592
                                        /* it was updated, so look at the updated version */
 
2593
                                        TupleTableSlot *epqslot;
 
2594
 
 
2595
                                        epqslot = EvalPlanQual(estate,
 
2596
                                                                                   epqstate,
 
2597
                                                                                   relation,
 
2598
                                                                                   relinfo->ri_RangeTableIndex,
 
2599
                                                                                   &update_ctid,
 
2600
                                                                                   update_xmax);
 
2601
                                        if (!TupIsNull(epqslot))
 
2602
                                        {
 
2603
                                                *tid = update_ctid;
 
2604
                                                *newSlot = epqslot;
 
2605
 
 
2606
                                                /*
 
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.
 
2611
                                                 */
 
2612
                                                goto ltrmark;
 
2613
                                        }
 
2614
                                }
 
2615
 
 
2616
                                /*
 
2617
                                 * if tuple was deleted or PlanQual failed for updated tuple -
 
2618
                                 * we must not process this tuple!
 
2619
                                 */
 
2620
                                return NULL;
 
2621
 
 
2622
                        default:
 
2623
                                ReleaseBuffer(buffer);
 
2624
                                elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
 
2625
                                return NULL;    /* keep compiler quiet */
 
2626
                }
 
2627
        }
 
2628
        else
 
2629
        {
 
2630
                Page            page;
 
2631
                ItemId          lp;
 
2632
 
 
2633
                buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
 
2634
 
 
2635
                page = BufferGetPage(buffer);
 
2636
                lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
 
2637
 
 
2638
                Assert(ItemIdIsNormal(lp));
 
2639
 
 
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);
 
2644
        }
 
2645
 
 
2646
        result = heap_copytuple(&tuple);
 
2647
        ReleaseBuffer(buffer);
 
2648
 
 
2649
        return result;
 
2650
}
 
2651
 
 
2652
/*
 
2653
 * Is trigger enabled to fire?
 
2654
 */
 
2655
static bool
 
2656
TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
 
2657
                           Trigger *trigger, TriggerEvent event,
 
2658
                           Bitmapset *modifiedCols,
 
2659
                           HeapTuple oldtup, HeapTuple newtup)
 
2660
{
 
2661
        /* Check replication-role-dependent enable state */
 
2662
        if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
 
2663
        {
 
2664
                if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
 
2665
                        trigger->tgenabled == TRIGGER_DISABLED)
 
2666
                        return false;
 
2667
        }
 
2668
        else    /* ORIGIN or LOCAL role */
 
2669
        {
 
2670
                if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
 
2671
                        trigger->tgenabled == TRIGGER_DISABLED)
 
2672
                        return false;
 
2673
        }
 
2674
 
 
2675
        /*
 
2676
         * Check for column-specific trigger (only possible for UPDATE, and in
 
2677
         * fact we *must* ignore tgattr for other event types)
 
2678
         */
 
2679
        if (trigger->tgnattr > 0 && TRIGGER_FIRED_BY_UPDATE(event))
 
2680
        {
 
2681
                int                     i;
 
2682
                bool            modified;
 
2683
 
 
2684
                modified = false;
 
2685
                for (i = 0; i < trigger->tgnattr; i++)
 
2686
                {
 
2687
                        if (bms_is_member(trigger->tgattr[i] - FirstLowInvalidHeapAttributeNumber,
 
2688
                                                          modifiedCols))
 
2689
                        {
 
2690
                                modified = true;
 
2691
                                break;
 
2692
                        }
 
2693
                }
 
2694
                if (!modified)
 
2695
                        return false;
 
2696
        }
 
2697
 
 
2698
        /* Check for WHEN clause */
 
2699
        if (trigger->tgqual)
 
2700
        {
 
2701
                TupleDesc       tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
 
2702
                List      **predicate;
 
2703
                ExprContext *econtext;
 
2704
                TupleTableSlot *oldslot = NULL;
 
2705
                TupleTableSlot *newslot = NULL;
 
2706
                MemoryContext oldContext;
 
2707
                int                     i;
 
2708
 
 
2709
                Assert(estate != NULL);
 
2710
 
 
2711
                /*
 
2712
                 * trigger is an element of relinfo->ri_TrigDesc->triggers[]; find the
 
2713
                 * matching element of relinfo->ri_TrigWhenExprs[]
 
2714
                 */
 
2715
                i = trigger - relinfo->ri_TrigDesc->triggers;
 
2716
                predicate = &relinfo->ri_TrigWhenExprs[i];
 
2717
 
 
2718
                /*
 
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.
 
2722
                 */
 
2723
                if (*predicate == NIL)
 
2724
                {
 
2725
                        Node       *tgqual;
 
2726
 
 
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);
 
2736
                }
 
2737
 
 
2738
                /*
 
2739
                 * We will use the EState's per-tuple context for evaluating WHEN
 
2740
                 * expressions (creating it if it's not already there).
 
2741
                 */
 
2742
                econtext = GetPerTupleExprContext(estate);
 
2743
 
 
2744
                /*
 
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.
 
2748
                 */
 
2749
                if (HeapTupleIsValid(oldtup))
 
2750
                {
 
2751
                        if (estate->es_trig_oldtup_slot == NULL)
 
2752
                        {
 
2753
                                oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
 
2754
                                estate->es_trig_oldtup_slot = ExecInitExtraTupleSlot(estate);
 
2755
                                MemoryContextSwitchTo(oldContext);
 
2756
                        }
 
2757
                        oldslot = estate->es_trig_oldtup_slot;
 
2758
                        if (oldslot->tts_tupleDescriptor != tupdesc)
 
2759
                                ExecSetSlotDescriptor(oldslot, tupdesc);
 
2760
                        ExecStoreTuple(oldtup, oldslot, InvalidBuffer, false);
 
2761
                }
 
2762
                if (HeapTupleIsValid(newtup))
 
2763
                {
 
2764
                        if (estate->es_trig_tuple_slot == NULL)
 
2765
                        {
 
2766
                                oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
 
2767
                                estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
 
2768
                                MemoryContextSwitchTo(oldContext);
 
2769
                        }
 
2770
                        newslot = estate->es_trig_tuple_slot;
 
2771
                        if (newslot->tts_tupleDescriptor != tupdesc)
 
2772
                                ExecSetSlotDescriptor(newslot, tupdesc);
 
2773
                        ExecStoreTuple(newtup, newslot, InvalidBuffer, false);
 
2774
                }
 
2775
 
 
2776
                /*
 
2777
                 * Finally evaluate the expression, making the old and/or new tuples
 
2778
                 * available as INNER/OUTER respectively.
 
2779
                 */
 
2780
                econtext->ecxt_innertuple = oldslot;
 
2781
                econtext->ecxt_outertuple = newslot;
 
2782
                if (!ExecQual(*predicate, econtext, false))
 
2783
                        return false;
 
2784
        }
 
2785
 
 
2786
        return true;
 
2787
}
 
2788
 
 
2789
 
 
2790
/* ----------
 
2791
 * After-trigger stuff
 
2792
 *
 
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.
 
2800
 *
 
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.
 
2805
 *
 
2806
 * XXX We need to be able to save the per-event data in a file if it grows too
 
2807
 * large.
 
2808
 * ----------
 
2809
 */
 
2810
 
 
2811
/* Per-trigger SET CONSTRAINT status */
 
2812
typedef struct SetConstraintTriggerData
 
2813
{
 
2814
        Oid                     sct_tgoid;
 
2815
        bool            sct_tgisdeferred;
 
2816
} SetConstraintTriggerData;
 
2817
 
 
2818
typedef struct SetConstraintTriggerData *SetConstraintTrigger;
 
2819
 
 
2820
/*
 
2821
 * SET CONSTRAINT intra-transaction status.
 
2822
 *
 
2823
 * We make this a single palloc'd object so it can be copied and freed easily.
 
2824
 *
 
2825
 * all_isset and all_isdeferred are used to keep track
 
2826
 * of SET CONSTRAINTS ALL {DEFERRED, IMMEDIATE}.
 
2827
 *
 
2828
 * trigstates[] stores per-trigger tgisdeferred settings.
 
2829
 */
 
2830
typedef struct SetConstraintStateData
 
2831
{
 
2832
        bool            all_isset;
 
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;
 
2838
 
 
2839
typedef SetConstraintStateData *SetConstraintState;
 
2840
 
 
2841
 
 
2842
/*
 
2843
 * Per-trigger-event data
 
2844
 *
 
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".
 
2849
 *
 
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.
 
2853
 *
 
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.
 
2862
 */
 
2863
typedef uint32 TriggerFlags;
 
2864
 
 
2865
#define AFTER_TRIGGER_OFFSET                    0x0FFFFFFF              /* must be low-order
 
2866
                                                                                                                 * bits */
 
2867
#define AFTER_TRIGGER_2CTIDS                    0x10000000
 
2868
#define AFTER_TRIGGER_DONE                              0x20000000
 
2869
#define AFTER_TRIGGER_IN_PROGRESS               0x40000000
 
2870
 
 
2871
typedef struct AfterTriggerSharedData *AfterTriggerShared;
 
2872
 
 
2873
typedef struct AfterTriggerSharedData
 
2874
{
 
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;
 
2880
 
 
2881
typedef struct AfterTriggerEventData *AfterTriggerEvent;
 
2882
 
 
2883
typedef struct AfterTriggerEventData
 
2884
{
 
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;
 
2889
 
 
2890
/* This struct must exactly match the one above except for not having ctid2 */
 
2891
typedef struct AfterTriggerEventDataOneCtid
 
2892
{
 
2893
        TriggerFlags ate_flags;         /* status bits and offset to shared data */
 
2894
        ItemPointerData ate_ctid1;      /* inserted, deleted, or old updated tuple */
 
2895
}       AfterTriggerEventDataOneCtid;
 
2896
 
 
2897
#define SizeofTriggerEvent(evt) \
 
2898
        (((evt)->ate_flags & AFTER_TRIGGER_2CTIDS) ? \
 
2899
         sizeof(AfterTriggerEventData) : sizeof(AfterTriggerEventDataOneCtid))
 
2900
 
 
2901
#define GetTriggerSharedData(evt) \
 
2902
        ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
 
2903
 
 
2904
/*
 
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.
 
2910
 */
 
2911
typedef struct AfterTriggerEventChunk
 
2912
{
 
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;
 
2919
 
 
2920
#define CHUNK_DATA_START(cptr) ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
 
2921
 
 
2922
/* A list of events */
 
2923
typedef struct AfterTriggerEventList
 
2924
{
 
2925
        AfterTriggerEventChunk *head;
 
2926
        AfterTriggerEventChunk *tail;
 
2927
        char       *tailfree;           /* freeptr of tail chunk */
 
2928
} AfterTriggerEventList;
 
2929
 
 
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)
 
2940
 
 
2941
 
 
2942
/*
 
2943
 * All per-transaction data for the AFTER TRIGGERS module.
 
2944
 *
 
2945
 * AfterTriggersData has the following fields:
 
2946
 *
 
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.
 
2952
 *
 
2953
 * state keeps track of the transaction-local effects of SET CONSTRAINTS.
 
2954
 * This is saved and restored across failed subtransactions.
 
2955
 *
 
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.
 
2961
 *
 
2962
 * query_depth is the current depth of nested AfterTriggerBeginQuery calls
 
2963
 * (-1 when the stack is empty).
 
2964
 *
 
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
 
2970
 * list.
 
2971
 *
 
2972
 * maxquerydepth is just the allocated length of query_stack.
 
2973
 *
 
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.
 
2977
 *
 
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.
 
2980
 *
 
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.
 
2983
 *
 
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.
 
2987
 *
 
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.)
 
2993
 */
 
2994
typedef struct AfterTriggersData
 
2995
{
 
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 */
 
3003
 
 
3004
        /* these fields are just for resetting at subtrans abort: */
 
3005
 
 
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;
 
3012
 
 
3013
typedef AfterTriggersData *AfterTriggers;
 
3014
 
 
3015
static AfterTriggers afterTriggers;
 
3016
 
 
3017
 
 
3018
static void AfterTriggerExecute(AfterTriggerEvent event,
 
3019
                                        Relation rel, TriggerDesc *trigdesc,
 
3020
                                        FmgrInfo *finfo,
 
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);
 
3027
 
 
3028
 
 
3029
/* ----------
 
3030
 * afterTriggerCheckState()
 
3031
 *
 
3032
 *      Returns true if the trigger event is actually in state DEFERRED.
 
3033
 * ----------
 
3034
 */
 
3035
static bool
 
3036
afterTriggerCheckState(AfterTriggerShared evtshared)
 
3037
{
 
3038
        Oid                     tgoid = evtshared->ats_tgoid;
 
3039
        SetConstraintState state = afterTriggers->state;
 
3040
        int                     i;
 
3041
 
 
3042
        /*
 
3043
         * For not-deferrable triggers (i.e. normal AFTER ROW triggers and
 
3044
         * constraints declared NOT DEFERRABLE), the state is always false.
 
3045
         */
 
3046
        if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
 
3047
                return false;
 
3048
 
 
3049
        /*
 
3050
         * Check if SET CONSTRAINTS has been executed for this specific trigger.
 
3051
         */
 
3052
        for (i = 0; i < state->numstates; i++)
 
3053
        {
 
3054
                if (state->trigstates[i].sct_tgoid == tgoid)
 
3055
                        return state->trigstates[i].sct_tgisdeferred;
 
3056
        }
 
3057
 
 
3058
        /*
 
3059
         * Check if SET CONSTRAINTS ALL has been executed; if so use that.
 
3060
         */
 
3061
        if (state->all_isset)
 
3062
                return state->all_isdeferred;
 
3063
 
 
3064
        /*
 
3065
         * Otherwise return the default state for the trigger.
 
3066
         */
 
3067
        return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
 
3068
}
 
3069
 
 
3070
 
 
3071
/* ----------
 
3072
 * afterTriggerAddEvent()
 
3073
 *
 
3074
 *      Add a new trigger event to the specified queue.
 
3075
 *      The passed-in event data is copied.
 
3076
 * ----------
 
3077
 */
 
3078
static void
 
3079
afterTriggerAddEvent(AfterTriggerEventList *events,
 
3080
                                         AfterTriggerEvent event, AfterTriggerShared evtshared)
 
3081
{
 
3082
        Size            eventsize = SizeofTriggerEvent(event);
 
3083
        Size            needed = eventsize + sizeof(AfterTriggerSharedData);
 
3084
        AfterTriggerEventChunk *chunk;
 
3085
        AfterTriggerShared newshared;
 
3086
        AfterTriggerEvent newevent;
 
3087
 
 
3088
        /*
 
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.
 
3091
         */
 
3092
        chunk = events->tail;
 
3093
        if (chunk == NULL ||
 
3094
                chunk->endfree - chunk->freeptr < needed)
 
3095
        {
 
3096
                Size            chunksize;
 
3097
 
 
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);
 
3106
 
 
3107
                /*
 
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.
 
3121
                 */
 
3122
#define MIN_CHUNK_SIZE 1024
 
3123
#define MAX_CHUNK_SIZE (1024*1024)
 
3124
 
 
3125
#if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
 
3126
#error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
 
3127
#endif
 
3128
 
 
3129
                if (chunk == NULL)
 
3130
                        chunksize = MIN_CHUNK_SIZE;
 
3131
                else
 
3132
                {
 
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 */
 
3139
                        else
 
3140
                                chunksize /= 2; /* too many shared records */
 
3141
                        chunksize = Min(chunksize, MAX_CHUNK_SIZE);
 
3142
                }
 
3143
                chunk = MemoryContextAlloc(afterTriggers->event_cxt, chunksize);
 
3144
                chunk->next = NULL;
 
3145
                chunk->freeptr = CHUNK_DATA_START(chunk);
 
3146
                chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
 
3147
                Assert(chunk->endfree - chunk->freeptr >= needed);
 
3148
 
 
3149
                if (events->head == NULL)
 
3150
                        events->head = chunk;
 
3151
                else
 
3152
                        events->tail->next = chunk;
 
3153
                events->tail = chunk;
 
3154
                /* events->tailfree is now out of sync, but we'll fix it below */
 
3155
        }
 
3156
 
 
3157
        /*
 
3158
         * Try to locate a matching shared-data record already in the chunk. If
 
3159
         * none, make a new one.
 
3160
         */
 
3161
        for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
 
3162
                 (char *) newshared >= chunk->endfree;
 
3163
                 newshared--)
 
3164
        {
 
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)
 
3169
                        break;
 
3170
        }
 
3171
        if ((char *) newshared < chunk->endfree)
 
3172
        {
 
3173
                *newshared = *evtshared;
 
3174
                newshared->ats_firing_id = 0;   /* just to be sure */
 
3175
                chunk->endfree = (char *) newshared;
 
3176
        }
 
3177
 
 
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;
 
3184
 
 
3185
        chunk->freeptr += eventsize;
 
3186
        events->tailfree = chunk->freeptr;
 
3187
}
 
3188
 
 
3189
/* ----------
 
3190
 * afterTriggerFreeEventList()
 
3191
 *
 
3192
 *      Free all the event storage in the given list.
 
3193
 * ----------
 
3194
 */
 
3195
static void
 
3196
afterTriggerFreeEventList(AfterTriggerEventList *events)
 
3197
{
 
3198
        AfterTriggerEventChunk *chunk;
 
3199
        AfterTriggerEventChunk *next_chunk;
 
3200
 
 
3201
        for (chunk = events->head; chunk != NULL; chunk = next_chunk)
 
3202
        {
 
3203
                next_chunk = chunk->next;
 
3204
                pfree(chunk);
 
3205
        }
 
3206
        events->head = NULL;
 
3207
        events->tail = NULL;
 
3208
        events->tailfree = NULL;
 
3209
}
 
3210
 
 
3211
/* ----------
 
3212
 * afterTriggerRestoreEventList()
 
3213
 *
 
3214
 *      Restore an event list to its prior length, removing all the events
 
3215
 *      added since it had the value old_events.
 
3216
 * ----------
 
3217
 */
 
3218
static void
 
3219
afterTriggerRestoreEventList(AfterTriggerEventList *events,
 
3220
                                                         const AfterTriggerEventList *old_events)
 
3221
{
 
3222
        AfterTriggerEventChunk *chunk;
 
3223
        AfterTriggerEventChunk *next_chunk;
 
3224
 
 
3225
        if (old_events->tail == NULL)
 
3226
        {
 
3227
                /* restoring to a completely empty state, so free everything */
 
3228
                afterTriggerFreeEventList(events);
 
3229
        }
 
3230
        else
 
3231
        {
 
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)
 
3235
                {
 
3236
                        next_chunk = chunk->next;
 
3237
                        pfree(chunk);
 
3238
                }
 
3239
                /* and clean up the tail chunk to be the right length */
 
3240
                events->tail->next = NULL;
 
3241
                events->tail->freeptr = events->tailfree;
 
3242
 
 
3243
                /*
 
3244
                 * We don't make any effort to remove now-unused shared data records.
 
3245
                 * They might still be useful, anyway.
 
3246
                 */
 
3247
        }
 
3248
}
 
3249
 
 
3250
 
 
3251
/* ----------
 
3252
 * AfterTriggerExecute()
 
3253
 *
 
3254
 *      Fetch the required tuples back from the heap and fire one
 
3255
 *      single trigger function.
 
3256
 *
 
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.)
 
3261
 *
 
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.
 
3269
 * ----------
 
3270
 */
 
3271
static void
 
3272
AfterTriggerExecute(AfterTriggerEvent event,
 
3273
                                        Relation rel, TriggerDesc *trigdesc,
 
3274
                                        FmgrInfo *finfo, Instrumentation *instr,
 
3275
                                        MemoryContext per_tuple_context)
 
3276
{
 
3277
        AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
3278
        Oid                     tgoid = evtshared->ats_tgoid;
 
3279
        TriggerData LocTriggerData;
 
3280
        HeapTupleData tuple1;
 
3281
        HeapTupleData tuple2;
 
3282
        HeapTuple       rettuple;
 
3283
        Buffer          buffer1 = InvalidBuffer;
 
3284
        Buffer          buffer2 = InvalidBuffer;
 
3285
        int                     tgindx;
 
3286
 
 
3287
        /*
 
3288
         * Locate trigger in trigdesc.
 
3289
         */
 
3290
        LocTriggerData.tg_trigger = NULL;
 
3291
        for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
 
3292
        {
 
3293
                if (trigdesc->triggers[tgindx].tgoid == tgoid)
 
3294
                {
 
3295
                        LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
 
3296
                        break;
 
3297
                }
 
3298
        }
 
3299
        if (LocTriggerData.tg_trigger == NULL)
 
3300
                elog(ERROR, "could not find trigger %u", tgoid);
 
3301
 
 
3302
        /*
 
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.
 
3305
         */
 
3306
        if (instr)
 
3307
                InstrStartNode(instr + tgindx);
 
3308
 
 
3309
        /*
 
3310
         * Fetch the required tuple(s).
 
3311
         */
 
3312
        if (ItemPointerIsValid(&(event->ate_ctid1)))
 
3313
        {
 
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;
 
3319
        }
 
3320
        else
 
3321
        {
 
3322
                LocTriggerData.tg_trigtuple = NULL;
 
3323
                LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
 
3324
        }
 
3325
 
 
3326
        /* don't touch ctid2 if not there */
 
3327
        if ((event->ate_flags & AFTER_TRIGGER_2CTIDS) &&
 
3328
                ItemPointerIsValid(&(event->ate_ctid2)))
 
3329
        {
 
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;
 
3335
        }
 
3336
        else
 
3337
        {
 
3338
                LocTriggerData.tg_newtuple = NULL;
 
3339
                LocTriggerData.tg_newtuplebuf = InvalidBuffer;
 
3340
        }
 
3341
 
 
3342
        /*
 
3343
         * Setup the remaining trigger information
 
3344
         */
 
3345
        LocTriggerData.type = T_TriggerData;
 
3346
        LocTriggerData.tg_event =
 
3347
                evtshared->ats_event & (TRIGGER_EVENT_OPMASK | TRIGGER_EVENT_ROW);
 
3348
        LocTriggerData.tg_relation = rel;
 
3349
 
 
3350
        MemoryContextReset(per_tuple_context);
 
3351
 
 
3352
        /*
 
3353
         * Call the trigger and throw away any possibly returned updated tuple.
 
3354
         * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
 
3355
         */
 
3356
        rettuple = ExecCallTriggerFunc(&LocTriggerData,
 
3357
                                                                   tgindx,
 
3358
                                                                   finfo,
 
3359
                                                                   NULL,
 
3360
                                                                   per_tuple_context);
 
3361
        if (rettuple != NULL && rettuple != &tuple1 && rettuple != &tuple2)
 
3362
                heap_freetuple(rettuple);
 
3363
 
 
3364
        /*
 
3365
         * Release buffers
 
3366
         */
 
3367
        if (buffer1 != InvalidBuffer)
 
3368
                ReleaseBuffer(buffer1);
 
3369
        if (buffer2 != InvalidBuffer)
 
3370
                ReleaseBuffer(buffer2);
 
3371
 
 
3372
        /*
 
3373
         * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
 
3374
         * one "tuple returned" (really the number of firings).
 
3375
         */
 
3376
        if (instr)
 
3377
                InstrStopNode(instr + tgindx, 1);
 
3378
}
 
3379
 
 
3380
 
 
3381
/*
 
3382
 * afterTriggerMarkEvents()
 
3383
 *
 
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.
 
3386
 *
 
3387
 *      If move_list isn't NULL, events that are not to be invoked now are
 
3388
 *      transferred to move_list.
 
3389
 *
 
3390
 *      When immediate_only is TRUE, do not invoke currently-deferred triggers.
 
3391
 *      (This will be FALSE only at main transaction exit.)
 
3392
 *
 
3393
 *      Returns TRUE if any invokable events were found.
 
3394
 */
 
3395
static bool
 
3396
afterTriggerMarkEvents(AfterTriggerEventList *events,
 
3397
                                           AfterTriggerEventList *move_list,
 
3398
                                           bool immediate_only)
 
3399
{
 
3400
        bool            found = false;
 
3401
        AfterTriggerEvent event;
 
3402
        AfterTriggerEventChunk *chunk;
 
3403
 
 
3404
        for_each_event_chunk(event, chunk, *events)
 
3405
        {
 
3406
                AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
3407
                bool            defer_it = false;
 
3408
 
 
3409
                if (!(event->ate_flags &
 
3410
                          (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS)))
 
3411
                {
 
3412
                        /*
 
3413
                         * This trigger hasn't been called or scheduled yet. Check if we
 
3414
                         * should call it now.
 
3415
                         */
 
3416
                        if (immediate_only && afterTriggerCheckState(evtshared))
 
3417
                        {
 
3418
                                defer_it = true;
 
3419
                        }
 
3420
                        else
 
3421
                        {
 
3422
                                /*
 
3423
                                 * Mark it as to be fired in this firing cycle.
 
3424
                                 */
 
3425
                                evtshared->ats_firing_id = afterTriggers->firing_counter;
 
3426
                                event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
 
3427
                                found = true;
 
3428
                        }
 
3429
                }
 
3430
 
 
3431
                /*
 
3432
                 * If it's deferred, move it to move_list, if requested.
 
3433
                 */
 
3434
                if (defer_it && move_list != NULL)
 
3435
                {
 
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;
 
3440
                }
 
3441
        }
 
3442
 
 
3443
        return found;
 
3444
}
 
3445
 
 
3446
/*
 
3447
 * afterTriggerInvokeEvents()
 
3448
 *
 
3449
 *      Scan the given event list for events that are marked as to be fired
 
3450
 *      in the current firing cycle, and fire them.
 
3451
 *
 
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
 
3455
 *      events per rel.
 
3456
 *
 
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.)
 
3463
 *
 
3464
 *      Returns TRUE if no unfired events remain in the list (this allows us
 
3465
 *      to avoid repeating afterTriggerMarkEvents).
 
3466
 */
 
3467
static bool
 
3468
afterTriggerInvokeEvents(AfterTriggerEventList *events,
 
3469
                                                 CommandId firing_id,
 
3470
                                                 EState *estate,
 
3471
                                                 bool delete_ok)
 
3472
{
 
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;
 
3481
 
 
3482
        /* Make a local EState if need be */
 
3483
        if (estate == NULL)
 
3484
        {
 
3485
                estate = CreateExecutorState();
 
3486
                local_estate = true;
 
3487
        }
 
3488
 
 
3489
        /* Make a per-tuple memory context for trigger function calls */
 
3490
        per_tuple_context =
 
3491
                AllocSetContextCreate(CurrentMemoryContext,
 
3492
                                                          "AfterTriggerTupleContext",
 
3493
                                                          ALLOCSET_DEFAULT_MINSIZE,
 
3494
                                                          ALLOCSET_DEFAULT_INITSIZE,
 
3495
                                                          ALLOCSET_DEFAULT_MAXSIZE);
 
3496
 
 
3497
        for_each_chunk(chunk, *events)
 
3498
        {
 
3499
                AfterTriggerEvent event;
 
3500
                bool            all_fired_in_chunk = true;
 
3501
 
 
3502
                for_each_event(event, chunk)
 
3503
                {
 
3504
                        AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
3505
 
 
3506
                        /*
 
3507
                         * Is it one for me to fire?
 
3508
                         */
 
3509
                        if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
 
3510
                                evtshared->ats_firing_id == firing_id)
 
3511
                        {
 
3512
                                /*
 
3513
                                 * So let's fire it... but first, find the correct relation if
 
3514
                                 * this is not the same relation as before.
 
3515
                                 */
 
3516
                                if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
 
3517
                                {
 
3518
                                        ResultRelInfo *rInfo;
 
3519
 
 
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);
 
3528
                                }
 
3529
 
 
3530
                                /*
 
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.
 
3534
                                 */
 
3535
                                AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
 
3536
                                                                        per_tuple_context);
 
3537
 
 
3538
                                /*
 
3539
                                 * Mark the event as done.
 
3540
                                 */
 
3541
                                event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
 
3542
                                event->ate_flags |= AFTER_TRIGGER_DONE;
 
3543
                        }
 
3544
                        else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
 
3545
                        {
 
3546
                                /* something remains to be done */
 
3547
                                all_fired = all_fired_in_chunk = false;
 
3548
                        }
 
3549
                }
 
3550
 
 
3551
                /* Clear the chunk if delete_ok and nothing left of interest */
 
3552
                if (delete_ok && all_fired_in_chunk)
 
3553
                {
 
3554
                        chunk->freeptr = CHUNK_DATA_START(chunk);
 
3555
                        chunk->endfree = chunk->endptr;
 
3556
 
 
3557
                        /*
 
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.
 
3562
                         */
 
3563
                        if (chunk == events->tail)
 
3564
                                events->tailfree = chunk->freeptr;
 
3565
                }
 
3566
        }
 
3567
 
 
3568
        /* Release working resources */
 
3569
        MemoryContextDelete(per_tuple_context);
 
3570
 
 
3571
        if (local_estate)
 
3572
        {
 
3573
                ListCell   *l;
 
3574
 
 
3575
                foreach(l, estate->es_trig_target_relations)
 
3576
                {
 
3577
                        ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
 
3578
 
 
3579
                        /* Close indices and then the relation itself */
 
3580
                        ExecCloseIndices(resultRelInfo);
 
3581
                        heap_close(resultRelInfo->ri_RelationDesc, NoLock);
 
3582
                }
 
3583
                FreeExecutorState(estate);
 
3584
        }
 
3585
 
 
3586
        return all_fired;
 
3587
}
 
3588
 
 
3589
 
 
3590
/* ----------
 
3591
 * AfterTriggerBeginXact()
 
3592
 *
 
3593
 *      Called at transaction start (either BEGIN or implicit for single
 
3594
 *      statement outside of transaction block).
 
3595
 * ----------
 
3596
 */
 
3597
void
 
3598
AfterTriggerBeginXact(void)
 
3599
{
 
3600
        Assert(afterTriggers == NULL);
 
3601
 
 
3602
        /*
 
3603
         * Build empty after-trigger state structure
 
3604
         */
 
3605
        afterTriggers = (AfterTriggers)
 
3606
                MemoryContextAlloc(TopTransactionContext,
 
3607
                                                   sizeof(AfterTriggersData));
 
3608
 
 
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;
 
3615
 
 
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;
 
3621
 
 
3622
        /* Context for events is created only when needed */
 
3623
        afterTriggers->event_cxt = NULL;
 
3624
 
 
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;
 
3631
}
 
3632
 
 
3633
 
 
3634
/* ----------
 
3635
 * AfterTriggerBeginQuery()
 
3636
 *
 
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.
 
3641
 * ----------
 
3642
 */
 
3643
void
 
3644
AfterTriggerBeginQuery(void)
 
3645
{
 
3646
        AfterTriggerEventList *events;
 
3647
 
 
3648
        /* Must be inside a transaction */
 
3649
        Assert(afterTriggers != NULL);
 
3650
 
 
3651
        /* Increase the query stack depth */
 
3652
        afterTriggers->query_depth++;
 
3653
 
 
3654
        /*
 
3655
         * Allocate more space in the query stack if needed.
 
3656
         */
 
3657
        if (afterTriggers->query_depth >= afterTriggers->maxquerydepth)
 
3658
        {
 
3659
                /* repalloc will keep the stack in the same context */
 
3660
                int                     new_alloc = afterTriggers->maxquerydepth * 2;
 
3661
 
 
3662
                afterTriggers->query_stack = (AfterTriggerEventList *)
 
3663
                        repalloc(afterTriggers->query_stack,
 
3664
                                         new_alloc * sizeof(AfterTriggerEventList));
 
3665
                afterTriggers->maxquerydepth = new_alloc;
 
3666
        }
 
3667
 
 
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;
 
3673
}
 
3674
 
 
3675
 
 
3676
/* ----------
 
3677
 * AfterTriggerEndQuery()
 
3678
 *
 
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.
 
3682
 *
 
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.
 
3686
 * ----------
 
3687
 */
 
3688
void
 
3689
AfterTriggerEndQuery(EState *estate)
 
3690
{
 
3691
        AfterTriggerEventList *events;
 
3692
 
 
3693
        /* Must be inside a transaction */
 
3694
        Assert(afterTriggers != NULL);
 
3695
 
 
3696
        /* Must be inside a query, too */
 
3697
        Assert(afterTriggers->query_depth >= 0);
 
3698
 
 
3699
        /*
 
3700
         * Process all immediate-mode triggers queued by the query, and move the
 
3701
         * deferred ones to the main list of deferred events.
 
3702
         *
 
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
 
3707
         * to fire.
 
3708
         *
 
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.
 
3713
         *
 
3714
         * If we find no firable events, we don't have to increment
 
3715
         * firing_counter.
 
3716
         */
 
3717
        for (;;)
 
3718
        {
 
3719
                events = &afterTriggers->query_stack[afterTriggers->query_depth];
 
3720
                if (afterTriggerMarkEvents(events, &afterTriggers->events, true))
 
3721
                {
 
3722
                        CommandId       firing_id = afterTriggers->firing_counter++;
 
3723
 
 
3724
                        /* OK to delete the immediate events after processing them */
 
3725
                        if (afterTriggerInvokeEvents(events, firing_id, estate, true))
 
3726
                                break;                  /* all fired */
 
3727
                }
 
3728
                else
 
3729
                        break;
 
3730
        }
 
3731
 
 
3732
        /* Release query-local storage for events */
 
3733
        afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
 
3734
 
 
3735
        afterTriggers->query_depth--;
 
3736
}
 
3737
 
 
3738
 
 
3739
/* ----------
 
3740
 * AfterTriggerFireDeferred()
 
3741
 *
 
3742
 *      Called just before the current transaction is committed. At this
 
3743
 *      time we invoke all pending DEFERRED triggers.
 
3744
 *
 
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
 
3747
 *      multiple times.
 
3748
 * ----------
 
3749
 */
 
3750
void
 
3751
AfterTriggerFireDeferred(void)
 
3752
{
 
3753
        AfterTriggerEventList *events;
 
3754
        bool            snap_pushed = false;
 
3755
 
 
3756
        /* Must be inside a transaction */
 
3757
        Assert(afterTriggers != NULL);
 
3758
 
 
3759
        /* ... but not inside a query */
 
3760
        Assert(afterTriggers->query_depth == -1);
 
3761
 
 
3762
        /*
 
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.)
 
3766
         */
 
3767
        events = &afterTriggers->events;
 
3768
        if (events->head != NULL)
 
3769
        {
 
3770
                PushActiveSnapshot(GetTransactionSnapshot());
 
3771
                snap_pushed = true;
 
3772
        }
 
3773
 
 
3774
        /*
 
3775
         * Run all the remaining triggers.      Loop until they are all gone, in case
 
3776
         * some trigger queues more for us to do.
 
3777
         */
 
3778
        while (afterTriggerMarkEvents(events, NULL, false))
 
3779
        {
 
3780
                CommandId       firing_id = afterTriggers->firing_counter++;
 
3781
 
 
3782
                if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
 
3783
                        break;                          /* all fired */
 
3784
        }
 
3785
 
 
3786
        /*
 
3787
         * We don't bother freeing the event list, since it will go away anyway
 
3788
         * (and more efficiently than via pfree) in AfterTriggerEndXact.
 
3789
         */
 
3790
 
 
3791
        if (snap_pushed)
 
3792
                PopActiveSnapshot();
 
3793
}
 
3794
 
 
3795
 
 
3796
/* ----------
 
3797
 * AfterTriggerEndXact()
 
3798
 *
 
3799
 *      The current transaction is finishing.
 
3800
 *
 
3801
 *      Any unfired triggers are canceled so we simply throw
 
3802
 *      away anything we know.
 
3803
 *
 
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.
 
3807
 * ----------
 
3808
 */
 
3809
void
 
3810
AfterTriggerEndXact(bool isCommit)
 
3811
{
 
3812
        /*
 
3813
         * Forget everything we know about AFTER triggers.
 
3814
         *
 
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!
 
3820
         */
 
3821
        if (afterTriggers && afterTriggers->event_cxt)
 
3822
                MemoryContextDelete(afterTriggers->event_cxt);
 
3823
 
 
3824
        afterTriggers = NULL;
 
3825
}
 
3826
 
 
3827
/*
 
3828
 * AfterTriggerBeginSubXact()
 
3829
 *
 
3830
 *      Start a subtransaction.
 
3831
 */
 
3832
void
 
3833
AfterTriggerBeginSubXact(void)
 
3834
{
 
3835
        int                     my_level = GetCurrentTransactionNestLevel();
 
3836
 
 
3837
        /*
 
3838
         * Ignore call if the transaction is in aborted state.  (Probably
 
3839
         * shouldn't happen?)
 
3840
         */
 
3841
        if (afterTriggers == NULL)
 
3842
                return;
 
3843
 
 
3844
        /*
 
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.)
 
3848
         */
 
3849
        while (my_level >= afterTriggers->maxtransdepth)
 
3850
        {
 
3851
                if (afterTriggers->maxtransdepth == 0)
 
3852
                {
 
3853
                        MemoryContext old_cxt;
 
3854
 
 
3855
                        old_cxt = MemoryContextSwitchTo(TopTransactionContext);
 
3856
 
 
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;
 
3867
 
 
3868
                        MemoryContextSwitchTo(old_cxt);
 
3869
                }
 
3870
                else
 
3871
                {
 
3872
                        /* repalloc will keep the stacks in the same context */
 
3873
                        int                     new_alloc = afterTriggers->maxtransdepth * 2;
 
3874
 
 
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;
 
3888
                }
 
3889
        }
 
3890
 
 
3891
        /*
 
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.
 
3895
         */
 
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;
 
3900
}
 
3901
 
 
3902
/*
 
3903
 * AfterTriggerEndSubXact()
 
3904
 *
 
3905
 *      The current subtransaction is ending.
 
3906
 */
 
3907
void
 
3908
AfterTriggerEndSubXact(bool isCommit)
 
3909
{
 
3910
        int                     my_level = GetCurrentTransactionNestLevel();
 
3911
        SetConstraintState state;
 
3912
        AfterTriggerEvent event;
 
3913
        AfterTriggerEventChunk *chunk;
 
3914
        CommandId       subxact_firing_id;
 
3915
 
 
3916
        /*
 
3917
         * Ignore call if the transaction is in aborted state.  (Probably
 
3918
         * unneeded)
 
3919
         */
 
3920
        if (afterTriggers == NULL)
 
3921
                return;
 
3922
 
 
3923
        /*
 
3924
         * Pop the prior state if needed.
 
3925
         */
 
3926
        if (isCommit)
 
3927
        {
 
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];
 
3931
                if (state != NULL)
 
3932
                        pfree(state);
 
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]);
 
3937
        }
 
3938
        else
 
3939
        {
 
3940
                /*
 
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.
 
3944
                 */
 
3945
                if (my_level >= afterTriggers->maxtransdepth)
 
3946
                        return;
 
3947
 
 
3948
                /*
 
3949
                 * Release any event lists from queries being aborted, and restore
 
3950
                 * query_depth to its pre-subxact value.
 
3951
                 */
 
3952
                while (afterTriggers->query_depth > afterTriggers->depth_stack[my_level])
 
3953
                {
 
3954
                        afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
 
3955
                        afterTriggers->query_depth--;
 
3956
                }
 
3957
                Assert(afterTriggers->query_depth ==
 
3958
                           afterTriggers->depth_stack[my_level]);
 
3959
 
 
3960
                /*
 
3961
                 * Restore the global deferred-event list to its former length,
 
3962
                 * discarding any events queued by the subxact.
 
3963
                 */
 
3964
                afterTriggerRestoreEventList(&afterTriggers->events,
 
3965
                                                                         &afterTriggers->events_stack[my_level]);
 
3966
 
 
3967
                /*
 
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.
 
3970
                 */
 
3971
                state = afterTriggers->state_stack[my_level];
 
3972
                if (state != NULL)
 
3973
                {
 
3974
                        pfree(afterTriggers->state);
 
3975
                        afterTriggers->state = state;
 
3976
                }
 
3977
                /* this avoids double pfree if error later: */
 
3978
                afterTriggers->state_stack[my_level] = NULL;
 
3979
 
 
3980
                /*
 
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.)
 
3987
                 */
 
3988
                subxact_firing_id = afterTriggers->firing_stack[my_level];
 
3989
                for_each_event_chunk(event, chunk, afterTriggers->events)
 
3990
                {
 
3991
                        AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
3992
 
 
3993
                        if (event->ate_flags &
 
3994
                                (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS))
 
3995
                        {
 
3996
                                if (evtshared->ats_firing_id >= subxact_firing_id)
 
3997
                                        event->ate_flags &=
 
3998
                                                ~(AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS);
 
3999
                        }
 
4000
                }
 
4001
        }
 
4002
}
 
4003
 
 
4004
/*
 
4005
 * Create an empty SetConstraintState with room for numalloc trigstates
 
4006
 */
 
4007
static SetConstraintState
 
4008
SetConstraintStateCreate(int numalloc)
 
4009
{
 
4010
        SetConstraintState state;
 
4011
 
 
4012
        /* Behave sanely with numalloc == 0 */
 
4013
        if (numalloc <= 0)
 
4014
                numalloc = 1;
 
4015
 
 
4016
        /*
 
4017
         * We assume that zeroing will correctly initialize the state values.
 
4018
         */
 
4019
        state = (SetConstraintState)
 
4020
                MemoryContextAllocZero(TopTransactionContext,
 
4021
                                                           sizeof(SetConstraintStateData) +
 
4022
                                                   (numalloc - 1) *sizeof(SetConstraintTriggerData));
 
4023
 
 
4024
        state->numalloc = numalloc;
 
4025
 
 
4026
        return state;
 
4027
}
 
4028
 
 
4029
/*
 
4030
 * Copy a SetConstraintState
 
4031
 */
 
4032
static SetConstraintState
 
4033
SetConstraintStateCopy(SetConstraintState origstate)
 
4034
{
 
4035
        SetConstraintState state;
 
4036
 
 
4037
        state = SetConstraintStateCreate(origstate->numstates);
 
4038
 
 
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));
 
4044
 
 
4045
        return state;
 
4046
}
 
4047
 
 
4048
/*
 
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).
 
4051
 */
 
4052
static SetConstraintState
 
4053
SetConstraintStateAddItem(SetConstraintState state,
 
4054
                                                  Oid tgoid, bool tgisdeferred)
 
4055
{
 
4056
        if (state->numstates >= state->numalloc)
 
4057
        {
 
4058
                int                     newalloc = state->numalloc * 2;
 
4059
 
 
4060
                newalloc = Max(newalloc, 8);    /* in case original has size 0 */
 
4061
                state = (SetConstraintState)
 
4062
                        repalloc(state,
 
4063
                                         sizeof(SetConstraintStateData) +
 
4064
                                         (newalloc - 1) *sizeof(SetConstraintTriggerData));
 
4065
                state->numalloc = newalloc;
 
4066
                Assert(state->numstates < state->numalloc);
 
4067
        }
 
4068
 
 
4069
        state->trigstates[state->numstates].sct_tgoid = tgoid;
 
4070
        state->trigstates[state->numstates].sct_tgisdeferred = tgisdeferred;
 
4071
        state->numstates++;
 
4072
 
 
4073
        return state;
 
4074
}
 
4075
 
 
4076
/* ----------
 
4077
 * AfterTriggerSetState()
 
4078
 *
 
4079
 *      Execute the SET CONSTRAINTS ... utility command.
 
4080
 * ----------
 
4081
 */
 
4082
void
 
4083
AfterTriggerSetState(ConstraintsSetStmt *stmt)
 
4084
{
 
4085
        int                     my_level = GetCurrentTransactionNestLevel();
 
4086
 
 
4087
        /*
 
4088
         * Ignore call if we aren't in a transaction.  (Shouldn't happen?)
 
4089
         */
 
4090
        if (afterTriggers == NULL)
 
4091
                return;
 
4092
 
 
4093
        /*
 
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.
 
4096
         */
 
4097
        if (my_level > 1 &&
 
4098
                afterTriggers->state_stack[my_level] == NULL)
 
4099
        {
 
4100
                afterTriggers->state_stack[my_level] =
 
4101
                        SetConstraintStateCopy(afterTriggers->state);
 
4102
        }
 
4103
 
 
4104
        /*
 
4105
         * Handle SET CONSTRAINTS ALL ...
 
4106
         */
 
4107
        if (stmt->constraints == NIL)
 
4108
        {
 
4109
                /*
 
4110
                 * Forget any previous SET CONSTRAINTS commands in this transaction.
 
4111
                 */
 
4112
                afterTriggers->state->numstates = 0;
 
4113
 
 
4114
                /*
 
4115
                 * Set the per-transaction ALL state to known.
 
4116
                 */
 
4117
                afterTriggers->state->all_isset = true;
 
4118
                afterTriggers->state->all_isdeferred = stmt->deferred;
 
4119
        }
 
4120
        else
 
4121
        {
 
4122
                Relation        conrel;
 
4123
                Relation        tgrel;
 
4124
                List       *conoidlist = NIL;
 
4125
                List       *tgoidlist = NIL;
 
4126
                ListCell   *lc;
 
4127
 
 
4128
                /*
 
4129
                 * Handle SET CONSTRAINTS constraint-name [, ...]
 
4130
                 *
 
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.)
 
4138
                 */
 
4139
                conrel = heap_open(ConstraintRelationId, AccessShareLock);
 
4140
 
 
4141
                foreach(lc, stmt->constraints)
 
4142
                {
 
4143
                        RangeVar   *constraint = lfirst(lc);
 
4144
                        bool            found;
 
4145
                        List       *namespacelist;
 
4146
                        ListCell   *nslc;
 
4147
 
 
4148
                        if (constraint->catalogname)
 
4149
                        {
 
4150
                                if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
 
4151
                                        ereport(ERROR,
 
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)));
 
4156
                        }
 
4157
 
 
4158
                        /*
 
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.
 
4162
                         */
 
4163
                        if (constraint->schemaname)
 
4164
                        {
 
4165
                                Oid                     namespaceId = LookupExplicitNamespace(constraint->schemaname);
 
4166
 
 
4167
                                namespacelist = list_make1_oid(namespaceId);
 
4168
                        }
 
4169
                        else
 
4170
                        {
 
4171
                                namespacelist = fetch_search_path(true);
 
4172
                        }
 
4173
 
 
4174
                        found = false;
 
4175
                        foreach(nslc, namespacelist)
 
4176
                        {
 
4177
                                Oid                     namespaceId = lfirst_oid(nslc);
 
4178
                                SysScanDesc conscan;
 
4179
                                ScanKeyData skey[2];
 
4180
                                HeapTuple       tup;
 
4181
 
 
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));
 
4190
 
 
4191
                                conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
 
4192
                                                                                         true, SnapshotNow, 2, skey);
 
4193
 
 
4194
                                while (HeapTupleIsValid(tup = systable_getnext(conscan)))
 
4195
                                {
 
4196
                                        Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
 
4197
 
 
4198
                                        if (con->condeferrable)
 
4199
                                                conoidlist = lappend_oid(conoidlist,
 
4200
                                                                                                 HeapTupleGetOid(tup));
 
4201
                                        else if (stmt->deferred)
 
4202
                                                ereport(ERROR,
 
4203
                                                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
4204
                                                                 errmsg("constraint \"%s\" is not deferrable",
 
4205
                                                                                constraint->relname)));
 
4206
                                        found = true;
 
4207
                                }
 
4208
 
 
4209
                                systable_endscan(conscan);
 
4210
 
 
4211
                                /*
 
4212
                                 * Once we've found a matching constraint we do not search
 
4213
                                 * later parts of the search path.
 
4214
                                 */
 
4215
                                if (found)
 
4216
                                        break;
 
4217
                        }
 
4218
 
 
4219
                        list_free(namespacelist);
 
4220
 
 
4221
                        /*
 
4222
                         * Not found ?
 
4223
                         */
 
4224
                        if (!found)
 
4225
                                ereport(ERROR,
 
4226
                                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4227
                                                 errmsg("constraint \"%s\" does not exist",
 
4228
                                                                constraint->relname)));
 
4229
                }
 
4230
 
 
4231
                heap_close(conrel, AccessShareLock);
 
4232
 
 
4233
                /*
 
4234
                 * Now, locate the trigger(s) implementing each of these constraints,
 
4235
                 * and make a list of their OIDs.
 
4236
                 */
 
4237
                tgrel = heap_open(TriggerRelationId, AccessShareLock);
 
4238
 
 
4239
                foreach(lc, conoidlist)
 
4240
                {
 
4241
                        Oid                     conoid = lfirst_oid(lc);
 
4242
                        bool            found;
 
4243
                        ScanKeyData skey;
 
4244
                        SysScanDesc tgscan;
 
4245
                        HeapTuple       htup;
 
4246
 
 
4247
                        found = false;
 
4248
 
 
4249
                        ScanKeyInit(&skey,
 
4250
                                                Anum_pg_trigger_tgconstraint,
 
4251
                                                BTEqualStrategyNumber, F_OIDEQ,
 
4252
                                                ObjectIdGetDatum(conoid));
 
4253
 
 
4254
                        tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
 
4255
                                                                                SnapshotNow, 1, &skey);
 
4256
 
 
4257
                        while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
 
4258
                        {
 
4259
                                Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
 
4260
 
 
4261
                                /*
 
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
 
4265
                                 * actions.
 
4266
                                 */
 
4267
                                if (pg_trigger->tgdeferrable)
 
4268
                                        tgoidlist = lappend_oid(tgoidlist,
 
4269
                                                                                        HeapTupleGetOid(htup));
 
4270
 
 
4271
                                found = true;
 
4272
                        }
 
4273
 
 
4274
                        systable_endscan(tgscan);
 
4275
 
 
4276
                        /* Safety check: a deferrable constraint should have triggers */
 
4277
                        if (!found)
 
4278
                                elog(ERROR, "no triggers found for constraint with OID %u",
 
4279
                                         conoid);
 
4280
                }
 
4281
 
 
4282
                heap_close(tgrel, AccessShareLock);
 
4283
 
 
4284
                /*
 
4285
                 * Now we can set the trigger states of individual triggers for this
 
4286
                 * xact.
 
4287
                 */
 
4288
                foreach(lc, tgoidlist)
 
4289
                {
 
4290
                        Oid                     tgoid = lfirst_oid(lc);
 
4291
                        SetConstraintState state = afterTriggers->state;
 
4292
                        bool            found = false;
 
4293
                        int                     i;
 
4294
 
 
4295
                        for (i = 0; i < state->numstates; i++)
 
4296
                        {
 
4297
                                if (state->trigstates[i].sct_tgoid == tgoid)
 
4298
                                {
 
4299
                                        state->trigstates[i].sct_tgisdeferred = stmt->deferred;
 
4300
                                        found = true;
 
4301
                                        break;
 
4302
                                }
 
4303
                        }
 
4304
                        if (!found)
 
4305
                        {
 
4306
                                afterTriggers->state =
 
4307
                                        SetConstraintStateAddItem(state, tgoid, stmt->deferred);
 
4308
                        }
 
4309
                }
 
4310
        }
 
4311
 
 
4312
        /*
 
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
 
4318
         * immediate.
 
4319
         *
 
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.
 
4322
         */
 
4323
        if (!stmt->deferred)
 
4324
        {
 
4325
                AfterTriggerEventList *events = &afterTriggers->events;
 
4326
                bool            snapshot_set = false;
 
4327
 
 
4328
                while (afterTriggerMarkEvents(events, NULL, true))
 
4329
                {
 
4330
                        CommandId       firing_id = afterTriggers->firing_counter++;
 
4331
 
 
4332
                        /*
 
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.)
 
4340
                         */
 
4341
                        if (!snapshot_set)
 
4342
                        {
 
4343
                                PushActiveSnapshot(GetTransactionSnapshot());
 
4344
                                snapshot_set = true;
 
4345
                        }
 
4346
 
 
4347
                        /*
 
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.
 
4351
                         */
 
4352
                        if (afterTriggerInvokeEvents(events, firing_id, NULL,
 
4353
                                                                                 !IsSubTransaction()))
 
4354
                                break;                  /* all fired */
 
4355
                }
 
4356
 
 
4357
                if (snapshot_set)
 
4358
                        PopActiveSnapshot();
 
4359
        }
 
4360
}
 
4361
 
 
4362
/* ----------
 
4363
 * AfterTriggerPendingOnRel()
 
4364
 *              Test to see if there are any pending after-trigger events for rel.
 
4365
 *
 
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.
 
4371
 *
 
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.
 
4375
 * ----------
 
4376
 */
 
4377
bool
 
4378
AfterTriggerPendingOnRel(Oid relid)
 
4379
{
 
4380
        AfterTriggerEvent event;
 
4381
        AfterTriggerEventChunk *chunk;
 
4382
        int                     depth;
 
4383
 
 
4384
        /* No-op if we aren't in a transaction.  (Shouldn't happen?) */
 
4385
        if (afterTriggers == NULL)
 
4386
                return false;
 
4387
 
 
4388
        /* Scan queued events */
 
4389
        for_each_event_chunk(event, chunk, afterTriggers->events)
 
4390
        {
 
4391
                AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
4392
 
 
4393
                /*
 
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.)
 
4397
                 */
 
4398
                if (event->ate_flags & AFTER_TRIGGER_DONE)
 
4399
                        continue;
 
4400
 
 
4401
                if (evtshared->ats_relid == relid)
 
4402
                        return true;
 
4403
        }
 
4404
 
 
4405
        /*
 
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.
 
4409
         */
 
4410
        for (depth = 0; depth <= afterTriggers->query_depth; depth++)
 
4411
        {
 
4412
                for_each_event_chunk(event, chunk, afterTriggers->query_stack[depth])
 
4413
                {
 
4414
                        AfterTriggerShared evtshared = GetTriggerSharedData(event);
 
4415
 
 
4416
                        if (event->ate_flags & AFTER_TRIGGER_DONE)
 
4417
                                continue;
 
4418
 
 
4419
                        if (evtshared->ats_relid == relid)
 
4420
                                return true;
 
4421
                }
 
4422
        }
 
4423
 
 
4424
        return false;
 
4425
}
 
4426
 
 
4427
 
 
4428
/* ----------
 
4429
 * AfterTriggerSaveEvent()
 
4430
 *
 
4431
 *      Called by ExecA[RS]...Triggers() to queue up the triggers that should
 
4432
 *      be fired for an event.
 
4433
 *
 
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.
 
4437
 * ----------
 
4438
 */
 
4439
static void
 
4440
AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
 
4441
                                          int event, bool row_trigger,
 
4442
                                          HeapTuple oldtup, HeapTuple newtup,
 
4443
                                          List *recheckIndexes, Bitmapset *modifiedCols)
 
4444
{
 
4445
        Relation        rel = relinfo->ri_RelationDesc;
 
4446
        TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
 
4447
        AfterTriggerEventData new_event;
 
4448
        AfterTriggerSharedData new_shared;
 
4449
        int                     tgtype_event;
 
4450
        int                     tgtype_level;
 
4451
        int                     i;
 
4452
 
 
4453
        /*
 
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.
 
4457
         */
 
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");
 
4462
 
 
4463
        /*
 
4464
         * Validate the event code and collect the associated tuple CTIDs.
 
4465
         *
 
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
 
4468
         * arrays.
 
4469
         */
 
4470
        new_event.ate_flags = 0;
 
4471
        switch (event)
 
4472
        {
 
4473
                case TRIGGER_EVENT_INSERT:
 
4474
                        tgtype_event = TRIGGER_TYPE_INSERT;
 
4475
                        if (row_trigger)
 
4476
                        {
 
4477
                                Assert(oldtup == NULL);
 
4478
                                Assert(newtup != NULL);
 
4479
                                ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
 
4480
                                ItemPointerSetInvalid(&(new_event.ate_ctid2));
 
4481
                        }
 
4482
                        else
 
4483
                        {
 
4484
                                Assert(oldtup == NULL);
 
4485
                                Assert(newtup == NULL);
 
4486
                                ItemPointerSetInvalid(&(new_event.ate_ctid1));
 
4487
                                ItemPointerSetInvalid(&(new_event.ate_ctid2));
 
4488
                        }
 
4489
                        break;
 
4490
                case TRIGGER_EVENT_DELETE:
 
4491
                        tgtype_event = TRIGGER_TYPE_DELETE;
 
4492
                        if (row_trigger)
 
4493
                        {
 
4494
                                Assert(oldtup != NULL);
 
4495
                                Assert(newtup == NULL);
 
4496
                                ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
 
4497
                                ItemPointerSetInvalid(&(new_event.ate_ctid2));
 
4498
                        }
 
4499
                        else
 
4500
                        {
 
4501
                                Assert(oldtup == NULL);
 
4502
                                Assert(newtup == NULL);
 
4503
                                ItemPointerSetInvalid(&(new_event.ate_ctid1));
 
4504
                                ItemPointerSetInvalid(&(new_event.ate_ctid2));
 
4505
                        }
 
4506
                        break;
 
4507
                case TRIGGER_EVENT_UPDATE:
 
4508
                        tgtype_event = TRIGGER_TYPE_UPDATE;
 
4509
                        if (row_trigger)
 
4510
                        {
 
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;
 
4516
                        }
 
4517
                        else
 
4518
                        {
 
4519
                                Assert(oldtup == NULL);
 
4520
                                Assert(newtup == NULL);
 
4521
                                ItemPointerSetInvalid(&(new_event.ate_ctid1));
 
4522
                                ItemPointerSetInvalid(&(new_event.ate_ctid2));
 
4523
                        }
 
4524
                        break;
 
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));
 
4531
                        break;
 
4532
                default:
 
4533
                        elog(ERROR, "invalid after-trigger event code: %d", event);
 
4534
                        tgtype_event = 0;       /* keep compiler quiet */
 
4535
                        break;
 
4536
        }
 
4537
 
 
4538
        tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
 
4539
 
 
4540
        for (i = 0; i < trigdesc->numtriggers; i++)
 
4541
        {
 
4542
                Trigger    *trigger = &trigdesc->triggers[i];
 
4543
 
 
4544
                if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
 
4545
                                                                  tgtype_level,
 
4546
                                                                  TRIGGER_TYPE_AFTER,
 
4547
                                                                  tgtype_event))
 
4548
                        continue;
 
4549
                if (!TriggerEnabled(estate, relinfo, trigger, event,
 
4550
                                                        modifiedCols, oldtup, newtup))
 
4551
                        continue;
 
4552
 
 
4553
                /*
 
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.
 
4557
                 */
 
4558
                if (TRIGGER_FIRED_BY_UPDATE(event))
 
4559
                {
 
4560
                        switch (RI_FKey_trigger_type(trigger->tgfoid))
 
4561
                        {
 
4562
                                case RI_TRIGGER_PK:
 
4563
                                        /* Update on PK table */
 
4564
                                        if (RI_FKey_keyequal_upd_pk(trigger, rel, oldtup, newtup))
 
4565
                                        {
 
4566
                                                /* key unchanged, so skip queuing this event */
 
4567
                                                continue;
 
4568
                                        }
 
4569
                                        break;
 
4570
 
 
4571
                                case RI_TRIGGER_FK:
 
4572
 
 
4573
                                        /*
 
4574
                                         * Update on FK table
 
4575
                                         *
 
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
 
4582
                                         * anyway.
 
4583
                                         */
 
4584
                                        if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(oldtup->t_data)) &&
 
4585
                                                RI_FKey_keyequal_upd_fk(trigger, rel, oldtup, newtup))
 
4586
                                        {
 
4587
                                                continue;
 
4588
                                        }
 
4589
                                        break;
 
4590
 
 
4591
                                case RI_TRIGGER_NONE:
 
4592
                                        /* Not an FK trigger */
 
4593
                                        break;
 
4594
                        }
 
4595
                }
 
4596
 
 
4597
                /*
 
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.
 
4601
                 */
 
4602
                if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
 
4603
                {
 
4604
                        if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
 
4605
                                continue;               /* Uniqueness definitely not violated */
 
4606
                }
 
4607
 
 
4608
                /*
 
4609
                 * Fill in event structure and add it to the current query's queue.
 
4610
                 */
 
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;
 
4619
 
 
4620
                afterTriggerAddEvent(&afterTriggers->query_stack[afterTriggers->query_depth],
 
4621
                                                         &new_event, &new_shared);
 
4622
        }
 
4623
}