PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
trigger.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/sysattr.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_constraint_fn.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/bitmapset.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
#include "parser/parse_func.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "pgstat.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/bytea.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/tuplestore.h"
Include dependency graph for trigger.c:

Go to the source code of this file.

Data Structures

struct  OldTriggerInfo
 
struct  SetConstraintTriggerData
 
struct  SetConstraintStateData
 
struct  AfterTriggerSharedData
 
struct  AfterTriggerEventData
 
struct  AfterTriggerEventDataOneCtid
 
struct  AfterTriggerEventDataZeroCtids
 
struct  AfterTriggerEventChunk
 
struct  AfterTriggerEventList
 
struct  AfterTriggersData
 

Macros

#define GetUpdatedColumns(relinfo, estate)   (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
 
#define AFTER_TRIGGER_OFFSET
 
#define AFTER_TRIGGER_DONE   0x10000000
 
#define AFTER_TRIGGER_IN_PROGRESS   0x20000000
 
#define AFTER_TRIGGER_FDW_REUSE   0x00000000
 
#define AFTER_TRIGGER_FDW_FETCH   0x80000000
 
#define AFTER_TRIGGER_1CTID   0x40000000
 
#define AFTER_TRIGGER_2CTID   0xC0000000
 
#define AFTER_TRIGGER_TUP_BITS   0xC0000000
 
#define SizeofTriggerEvent(evt)
 
#define GetTriggerSharedData(evt)   ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
 
#define CHUNK_DATA_START(cptr)   ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
 
#define for_each_chunk(cptr, evtlist)   for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)
 
#define for_each_event(eptr, cptr)
 
#define for_each_event_chunk(eptr, cptr, evtlist)   for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
 
#define MIN_CHUNK_SIZE   1024
 
#define MAX_CHUNK_SIZE   (1024*1024)
 
#define DEFTRIG_INITALLOC   8
 

Typedefs

typedef struct
SetConstraintTriggerData 
SetConstraintTriggerData
 
typedef struct
SetConstraintTriggerData
SetConstraintTrigger
 
typedef struct
SetConstraintStateData 
SetConstraintStateData
 
typedef SetConstraintStateDataSetConstraintState
 
typedef uint32 TriggerFlags
 
typedef struct
AfterTriggerSharedData
AfterTriggerShared
 
typedef struct
AfterTriggerSharedData 
AfterTriggerSharedData
 
typedef struct
AfterTriggerEventData
AfterTriggerEvent
 
typedef struct
AfterTriggerEventData 
AfterTriggerEventData
 
typedef struct
AfterTriggerEventDataOneCtid 
AfterTriggerEventDataOneCtid
 
typedef struct
AfterTriggerEventDataZeroCtids 
AfterTriggerEventDataZeroCtids
 
typedef struct
AfterTriggerEventChunk 
AfterTriggerEventChunk
 
typedef struct
AfterTriggerEventList 
AfterTriggerEventList
 
typedef struct AfterTriggersData AfterTriggersData
 

Functions

static void ConvertTriggerToFK (CreateTrigStmt *stmt, Oid funcoid)
 
static void SetTriggerFlags (TriggerDesc *trigdesc, Trigger *trigger)
 
static HeapTuple GetTupleForTrigger (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
 
static bool TriggerEnabled (EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
 
static HeapTuple ExecCallTriggerFunc (TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
 
static void AfterTriggerSaveEvent (EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
 
static void AfterTriggerEnlargeQueryState (void)
 
ObjectAddress CreateTrigger (CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, bool isInternal)
 
void RemoveTriggerById (Oid trigOid)
 
Oid get_trigger_oid (Oid relid, const char *trigname, bool missing_ok)
 
static void RangeVarCallbackForRenameTrigger (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renametrig (RenameStmt *stmt)
 
void EnableDisableTrigger (Relation rel, const char *tgname, char fires_when, bool skip_system)
 
void RelationBuildTriggers (Relation relation)
 
TriggerDescCopyTriggerDesc (TriggerDesc *trigdesc)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes)
 
TupleTableSlotExecIRUpdateTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
 
void ExecBSTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
static void AfterTriggerExecute (AfterTriggerEvent event, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
 
static SetConstraintState SetConstraintStateCreate (int numalloc)
 
static SetConstraintState SetConstraintStateCopy (SetConstraintState state)
 
static SetConstraintState SetConstraintStateAddItem (SetConstraintState state, Oid tgoid, bool tgisdeferred)
 
static TuplestorestateGetCurrentFDWTuplestore (void)
 
static bool afterTriggerCheckState (AfterTriggerShared evtshared)
 
static void afterTriggerAddEvent (AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
 
static void afterTriggerFreeEventList (AfterTriggerEventList *events)
 
static void afterTriggerRestoreEventList (AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
 
static bool afterTriggerMarkEvents (AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
 
static bool afterTriggerInvokeEvents (AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
 
void AfterTriggerBeginXact (void)
 
void AfterTriggerBeginQuery (void)
 
void AfterTriggerEndQuery (EState *estate)
 
void AfterTriggerFireDeferred (void)
 
void AfterTriggerEndXact (bool isCommit)
 
void AfterTriggerBeginSubXact (void)
 
void AfterTriggerEndSubXact (bool isCommit)
 
void AfterTriggerSetState (ConstraintsSetStmt *stmt)
 
bool AfterTriggerPendingOnRel (Oid relid)
 
Datum pg_trigger_depth (PG_FUNCTION_ARGS)
 

Variables

int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN
 
static int MyTriggerDepth = 0
 
static AfterTriggersData afterTriggers
 

Macro Definition Documentation

#define AFTER_TRIGGER_1CTID   0x40000000

Definition at line 3049 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3050 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3048 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3047 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_IN_PROGRESS   0x20000000
#define AFTER_TRIGGER_OFFSET
Value:
0x0FFFFFFF /* must be low-order
* bits */

Definition at line 3042 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3051 of file trigger.c.

Referenced by AfterTriggerExecute().

#define CHUNK_DATA_START (   cptr)    ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))

Definition at line 3111 of file trigger.c.

Referenced by afterTriggerAddEvent(), and afterTriggerInvokeEvents().

#define DEFTRIG_INITALLOC   8
#define for_each_chunk (   cptr,
  evtlist 
)    for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)

Definition at line 3122 of file trigger.c.

Referenced by afterTriggerInvokeEvents().

#define for_each_event (   eptr,
  cptr 
)
Value:
for (eptr = (AfterTriggerEvent) CHUNK_DATA_START(cptr); \
(char *) eptr < (cptr)->freeptr; \
eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3111
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3085
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3063

Definition at line 3124 of file trigger.c.

Referenced by afterTriggerInvokeEvents().

#define for_each_event_chunk (   eptr,
  cptr,
  evtlist 
)    for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
#define GetTriggerSharedData (   evt)    ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
#define GetUpdatedColumns (   relinfo,
  estate 
)    (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
#define MAX_CHUNK_SIZE   (1024*1024)

Referenced by afterTriggerAddEvent().

#define MIN_CHUNK_SIZE   1024

Referenced by afterTriggerAddEvent().

#define SizeofTriggerEvent (   evt)
Value:
(((evt)->ate_flags & AFTER_TRIGGER_TUP_BITS) == AFTER_TRIGGER_2CTID ? \
((evt)->ate_flags & AFTER_TRIGGER_TUP_BITS) == AFTER_TRIGGER_1CTID ? \
#define AFTER_TRIGGER_TUP_BITS
Definition: trigger.c:3051
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3049
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3050

Definition at line 3085 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3063 of file trigger.c.

Definition at line 3053 of file trigger.c.

Definition at line 3040 of file trigger.c.

Function Documentation

static void afterTriggerAddEvent ( AfterTriggerEventList events,
AfterTriggerEvent  event,
AfterTriggerShared  evtshared 
)
static

Definition at line 3318 of file trigger.c.

References AFTER_TRIGGER_OFFSET, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, AfterTriggerSharedData::ats_tgoid, CHUNK_DATA_START, AfterTriggersData::event_cxt, AfterTriggerEventList::head, MAX_CHUNK_SIZE, MemoryContextAlloc(), Min, MIN_CHUNK_SIZE, AfterTriggerEventChunk::next, NULL, SizeofTriggerEvent, AfterTriggerEventList::tail, AfterTriggerEventList::tailfree, and TopTransactionContext.

Referenced by afterTriggerMarkEvents(), and AfterTriggerSaveEvent().

3320 {
3321  Size eventsize = SizeofTriggerEvent(event);
3322  Size needed = eventsize + sizeof(AfterTriggerSharedData);
3323  AfterTriggerEventChunk *chunk;
3324  AfterTriggerShared newshared;
3325  AfterTriggerEvent newevent;
3326 
3327  /*
3328  * If empty list or not enough room in the tail chunk, make a new chunk.
3329  * We assume here that a new shared record will always be needed.
3330  */
3331  chunk = events->tail;
3332  if (chunk == NULL ||
3333  chunk->endfree - chunk->freeptr < needed)
3334  {
3335  Size chunksize;
3336 
3337  /* Create event context if we didn't already */
3338  if (afterTriggers.event_cxt == NULL)
3341  "AfterTriggerEvents",
3345 
3346  /*
3347  * Chunk size starts at 1KB and is allowed to increase up to 1MB.
3348  * These numbers are fairly arbitrary, though there is a hard limit at
3349  * AFTER_TRIGGER_OFFSET; else we couldn't link event records to their
3350  * shared records using the available space in ate_flags. Another
3351  * constraint is that if the chunk size gets too huge, the search loop
3352  * below would get slow given a (not too common) usage pattern with
3353  * many distinct event types in a chunk. Therefore, we double the
3354  * preceding chunk size only if there weren't too many shared records
3355  * in the preceding chunk; otherwise we halve it. This gives us some
3356  * ability to adapt to the actual usage pattern of the current query
3357  * while still having large chunk sizes in typical usage. All chunk
3358  * sizes used should be MAXALIGN multiples, to ensure that the shared
3359  * records will be aligned safely.
3360  */
3361 #define MIN_CHUNK_SIZE 1024
3362 #define MAX_CHUNK_SIZE (1024*1024)
3363 
3364 #if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
3365 #error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
3366 #endif
3367 
3368  if (chunk == NULL)
3369  chunksize = MIN_CHUNK_SIZE;
3370  else
3371  {
3372  /* preceding chunk size... */
3373  chunksize = chunk->endptr - (char *) chunk;
3374  /* check number of shared records in preceding chunk */
3375  if ((chunk->endptr - chunk->endfree) <=
3376  (100 * sizeof(AfterTriggerSharedData)))
3377  chunksize *= 2; /* okay, double it */
3378  else
3379  chunksize /= 2; /* too many shared records */
3380  chunksize = Min(chunksize, MAX_CHUNK_SIZE);
3381  }
3382  chunk = MemoryContextAlloc(afterTriggers.event_cxt, chunksize);
3383  chunk->next = NULL;
3384  chunk->freeptr = CHUNK_DATA_START(chunk);
3385  chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
3386  Assert(chunk->endfree - chunk->freeptr >= needed);
3387 
3388  if (events->head == NULL)
3389  events->head = chunk;
3390  else
3391  events->tail->next = chunk;
3392  events->tail = chunk;
3393  /* events->tailfree is now out of sync, but we'll fix it below */
3394  }
3395 
3396  /*
3397  * Try to locate a matching shared-data record already in the chunk. If
3398  * none, make a new one.
3399  */
3400  for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
3401  (char *) newshared >= chunk->endfree;
3402  newshared--)
3403  {
3404  if (newshared->ats_tgoid == evtshared->ats_tgoid &&
3405  newshared->ats_relid == evtshared->ats_relid &&
3406  newshared->ats_event == evtshared->ats_event &&
3407  newshared->ats_firing_id == 0)
3408  break;
3409  }
3410  if ((char *) newshared < chunk->endfree)
3411  {
3412  *newshared = *evtshared;
3413  newshared->ats_firing_id = 0; /* just to be sure */
3414  chunk->endfree = (char *) newshared;
3415  }
3416 
3417  /* Insert the data */
3418  newevent = (AfterTriggerEvent) chunk->freeptr;
3419  memcpy(newevent, event, eventsize);
3420  /* ... and link the new event to its shared record */
3421  newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
3422  newevent->ate_flags |= (char *) newshared - (char *) newevent;
3423 
3424  chunk->freeptr += eventsize;
3425  events->tailfree = chunk->freeptr;
3426 }
TriggerEvent ats_event
Definition: trigger.c:3057
MemoryContext TopTransactionContext
Definition: mcxt.c:48
#define MIN_CHUNK_SIZE
TriggerFlags ate_flags
Definition: trigger.c:3067
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3111
struct AfterTriggerSharedData AfterTriggerSharedData
#define Min(x, y)
Definition: c.h:798
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
#define ALLOCSET_DEFAULT_MINSIZE
Definition: memutils.h:142
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3085
#define AFTER_TRIGGER_OFFSET
Definition: trigger.c:3042
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:436
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
size_t Size
Definition: c.h:352
CommandId ats_firing_id
Definition: trigger.c:3060
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3063
#define MAX_CHUNK_SIZE
AfterTriggerEventChunk * head
Definition: trigger.c:3116
MemoryContext event_cxt
Definition: trigger.c:3198
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:752
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:143
#define ALLOCSET_DEFAULT_MAXSIZE
Definition: memutils.h:144
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginQuery ( void  )

Definition at line 3939 of file trigger.c.

References AfterTriggersData::query_depth.

Referenced by CopyFrom(), ExecuteTruncate(), and standard_ExecutorStart().

3940 {
3941  /* Increase the query stack depth */
3943 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginSubXact ( void  )

Definition at line 4147 of file trigger.c.

References DEFTRIG_INITALLOC, AfterTriggersData::depth_stack, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::firing_counter, AfterTriggersData::firing_stack, GetCurrentTransactionNestLevel(), AfterTriggersData::maxtransdepth, MemoryContextSwitchTo(), NULL, palloc(), AfterTriggersData::query_depth, repalloc(), AfterTriggersData::state_stack, and TopTransactionContext.

Referenced by StartSubTransaction().

4148 {
4149  int my_level = GetCurrentTransactionNestLevel();
4150 
4151  /*
4152  * Allocate more space in the stacks if needed. (Note: because the
4153  * minimum nest level of a subtransaction is 2, we waste the first couple
4154  * entries of each array; not worth the notational effort to avoid it.)
4155  */
4156  while (my_level >= afterTriggers.maxtransdepth)
4157  {
4158  if (afterTriggers.maxtransdepth == 0)
4159  {
4160  MemoryContext old_cxt;
4161 
4163 
4164 #define DEFTRIG_INITALLOC 8
4169  afterTriggers.depth_stack = (int *)
4170  palloc(DEFTRIG_INITALLOC * sizeof(int));
4172  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4174 
4175  MemoryContextSwitchTo(old_cxt);
4176  }
4177  else
4178  {
4179  /* repalloc will keep the stacks in the same context */
4180  int new_alloc = afterTriggers.maxtransdepth * 2;
4181 
4184  new_alloc * sizeof(SetConstraintState));
4187  new_alloc * sizeof(AfterTriggerEventList));
4188  afterTriggers.depth_stack = (int *)
4190  new_alloc * sizeof(int));
4193  new_alloc * sizeof(CommandId));
4194  afterTriggers.maxtransdepth = new_alloc;
4195  }
4196  }
4197 
4198  /*
4199  * Push the current information into the stack. The SET CONSTRAINTS state
4200  * is not saved until/unless changed. Likewise, we don't make a
4201  * per-subtransaction event context until needed.
4202  */
4203  afterTriggers.state_stack[my_level] = NULL;
4207 }
uint32 CommandId
Definition: c.h:407
MemoryContext TopTransactionContext
Definition: mcxt.c:48
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define DEFTRIG_INITALLOC
CommandId * firing_stack
Definition: trigger.c:3205
SetConstraintState * state_stack
Definition: trigger.c:3202
CommandId firing_counter
Definition: trigger.c:3191
AfterTriggerEventList * events_stack
Definition: trigger.c:3203
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:758
#define NULL
Definition: c.h:226
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1024
void * palloc(Size size)
Definition: mcxt.c:894
AfterTriggerEventList events
Definition: trigger.c:3193
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginXact ( void  )

Definition at line 3903 of file trigger.c.

References Assert, AfterTriggersData::depth_stack, AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::firing_stack, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, and AfterTriggersData::state_stack.

Referenced by StartTransaction().

3904 {
3905  /*
3906  * Initialize after-trigger state structure to empty
3907  */
3908  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
3910 
3911  /*
3912  * Verify that there is no leftover state remaining. If these assertions
3913  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
3914  * up properly.
3915  */
3927 }
uint32 CommandId
Definition: c.h:407
CommandId * firing_stack
Definition: trigger.c:3205
SetConstraintState * state_stack
Definition: trigger.c:3202
SetConstraintState state
Definition: trigger.c:3192
CommandId firing_counter
Definition: trigger.c:3191
AfterTriggerEventList * events_stack
Definition: trigger.c:3203
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
AfterTriggerEventChunk * head
Definition: trigger.c:3116
MemoryContext event_cxt
Definition: trigger.c:3198
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3196
AfterTriggerEventList events
Definition: trigger.c:3193
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

Definition at line 3272 of file trigger.c.

References AFTER_TRIGGER_DEFERRABLE, AFTER_TRIGGER_INITDEFERRED, SetConstraintStateData::all_isdeferred, SetConstraintStateData::all_isset, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_tgoid, i, NULL, SetConstraintStateData::numstates, SetConstraintTriggerData::sct_tgisdeferred, SetConstraintTriggerData::sct_tgoid, AfterTriggersData::state, and SetConstraintStateData::trigstates.

Referenced by afterTriggerMarkEvents().

3273 {
3274  Oid tgoid = evtshared->ats_tgoid;
3276  int i;
3277 
3278  /*
3279  * For not-deferrable triggers (i.e. normal AFTER ROW triggers and
3280  * constraints declared NOT DEFERRABLE), the state is always false.
3281  */
3282  if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
3283  return false;
3284 
3285  /*
3286  * If constraint state exists, SET CONSTRAINTS might have been executed
3287  * either for this trigger or for all triggers.
3288  */
3289  if (state != NULL)
3290  {
3291  /* Check for SET CONSTRAINTS for this specific trigger. */
3292  for (i = 0; i < state->numstates; i++)
3293  {
3294  if (state->trigstates[i].sct_tgoid == tgoid)
3295  return state->trigstates[i].sct_tgisdeferred;
3296  }
3297 
3298  /* Check for SET CONSTRAINTS ALL. */
3299  if (state->all_isset)
3300  return state->all_isdeferred;
3301  }
3302 
3303  /*
3304  * Otherwise return the default state for the trigger.
3305  */
3306  return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
3307 }
TriggerEvent ats_event
Definition: trigger.c:3057
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:66
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:65
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3004
unsigned int Oid
Definition: postgres_ext.h:31
SetConstraintState state
Definition: trigger.c:3192
#define NULL
Definition: c.h:226
Definition: regguts.h:313
int i
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerEndQuery ( EState estate)

Definition at line 3959 of file trigger.c.

References afterTriggerFreeEventList(), afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::maxquerydepth, NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, and tuplestore_end().

Referenced by CopyFrom(), ExecuteTruncate(), and standard_ExecutorFinish().

3960 {
3961  AfterTriggerEventList *events;
3962  Tuplestorestate *fdw_tuplestore;
3963 
3964  /* Must be inside a query, too */
3966 
3967  /*
3968  * If we never even got as far as initializing the event stack, there
3969  * certainly won't be any events, so exit quickly.
3970  */
3972  {
3974  return;
3975  }
3976 
3977  /*
3978  * Process all immediate-mode triggers queued by the query, and move the
3979  * deferred ones to the main list of deferred events.
3980  *
3981  * Notice that we decide which ones will be fired, and put the deferred
3982  * ones on the main list, before anything is actually fired. This ensures
3983  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
3984  * IMMEDIATE: all events we have decided to defer will be available for it
3985  * to fire.
3986  *
3987  * We loop in case a trigger queues more events at the same query level.
3988  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
3989  * will instead fire any triggers in a dedicated query level. Foreign key
3990  * enforcement triggers do add to the current query level, thanks to their
3991  * passing fire_triggers = false to SPI_execute_snapshot(). Other
3992  * C-language triggers might do likewise. Be careful here: firing a
3993  * trigger could result in query_stack being repalloc'd, so we can't save
3994  * its address across afterTriggerInvokeEvents calls.
3995  *
3996  * If we find no firable events, we don't have to increment
3997  * firing_counter.
3998  */
3999  for (;;)
4000  {
4002  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4003  {
4004  CommandId firing_id = afterTriggers.firing_counter++;
4005 
4006  /* OK to delete the immediate events after processing them */
4007  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4008  break; /* all fired */
4009  }
4010  else
4011  break;
4012  }
4013 
4014  /* Release query-local storage for events, including tuplestore if any */
4016  if (fdw_tuplestore)
4017  {
4018  tuplestore_end(fdw_tuplestore);
4020  }
4022 
4024 }
uint32 CommandId
Definition: c.h:407
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3756
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3435
CommandId firing_counter
Definition: trigger.c:3191
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:450
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3684
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3196
AfterTriggerEventList events
Definition: trigger.c:3193
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerEndSubXact ( bool  isCommit)

Definition at line 4215 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, afterTriggerFreeEventList(), afterTriggerRestoreEventList(), Assert, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggersData::depth_stack, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_stack, for_each_event_chunk, GetCurrentTransactionNestLevel(), GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, NULL, pfree(), AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, and tuplestore_end().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

4216 {
4217  int my_level = GetCurrentTransactionNestLevel();
4219  AfterTriggerEvent event;
4220  AfterTriggerEventChunk *chunk;
4221  CommandId subxact_firing_id;
4222 
4223  /*
4224  * Pop the prior state if needed.
4225  */
4226  if (isCommit)
4227  {
4228  Assert(my_level < afterTriggers.maxtransdepth);
4229  /* If we saved a prior state, we don't need it anymore */
4230  state = afterTriggers.state_stack[my_level];
4231  if (state != NULL)
4232  pfree(state);
4233  /* this avoids double pfree if error later: */
4234  afterTriggers.state_stack[my_level] = NULL;
4236  afterTriggers.depth_stack[my_level]);
4237  }
4238  else
4239  {
4240  /*
4241  * Aborting. It is possible subxact start failed before calling
4242  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4243  * stack levels that aren't there.
4244  */
4245  if (my_level >= afterTriggers.maxtransdepth)
4246  return;
4247 
4248  /*
4249  * Release any event lists from queries being aborted, and restore
4250  * query_depth to its pre-subxact value. This assumes that a
4251  * subtransaction will not add events to query levels started in a
4252  * earlier transaction state.
4253  */
4255  {
4257  {
4258  Tuplestorestate *ts;
4259 
4261  if (ts)
4262  {
4263  tuplestore_end(ts);
4265  }
4266 
4268  }
4269 
4271  }
4273  afterTriggers.depth_stack[my_level]);
4274 
4275  /*
4276  * Restore the global deferred-event list to its former length,
4277  * discarding any events queued by the subxact.
4278  */
4280  &afterTriggers.events_stack[my_level]);
4281 
4282  /*
4283  * Restore the trigger state. If the saved state is NULL, then this
4284  * subxact didn't save it, so it doesn't need restoring.
4285  */
4286  state = afterTriggers.state_stack[my_level];
4287  if (state != NULL)
4288  {
4290  afterTriggers.state = state;
4291  }
4292  /* this avoids double pfree if error later: */
4293  afterTriggers.state_stack[my_level] = NULL;
4294 
4295  /*
4296  * Scan for any remaining deferred events that were marked DONE or IN
4297  * PROGRESS by this subxact or a child, and un-mark them. We can
4298  * recognize such events because they have a firing ID greater than or
4299  * equal to the firing_counter value we saved at subtransaction start.
4300  * (This essentially assumes that the current subxact includes all
4301  * subxacts started after it.)
4302  */
4303  subxact_firing_id = afterTriggers.firing_stack[my_level];
4305  {
4306  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4307 
4308  if (event->ate_flags &
4310  {
4311  if (evtshared->ats_firing_id >= subxact_firing_id)
4312  event->ate_flags &=
4314  }
4315  }
4316  }
4317 }
uint32 CommandId
Definition: c.h:407
TriggerFlags ate_flags
Definition: trigger.c:3067
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3044
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3129
CommandId * firing_stack
Definition: trigger.c:3205
#define GetTriggerSharedData(evt)
Definition: trigger.c:3092
void pfree(void *pointer)
Definition: mcxt.c:995
SetConstraintState * state_stack
Definition: trigger.c:3202
SetConstraintState state
Definition: trigger.c:3192
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3435
AfterTriggerEventList * events_stack
Definition: trigger.c:3203
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:758
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
Definition: regguts.h:313
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:450
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3458
CommandId ats_firing_id
Definition: trigger.c:3060
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3045
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3196
AfterTriggerEventList events
Definition: trigger.c:3193
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerEndXact ( bool  isCommit)

Definition at line 4095 of file trigger.c.

References AfterTriggersData::depth_stack, AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_stack, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, MemoryContextDelete(), NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

4096 {
4097  /*
4098  * Forget the pending-events list.
4099  *
4100  * Since all the info is in TopTransactionContext or children thereof, we
4101  * don't really need to do anything to reclaim memory. However, the
4102  * pending-events list could be large, and so it's useful to discard it as
4103  * soon as possible --- especially if we are aborting because we ran out
4104  * of memory for the list!
4105  */
4107  {
4113  }
4114 
4115  /*
4116  * Forget any subtransaction state as well. Since this can't be very
4117  * large, we let the eventual reset of TopTransactionContext free the
4118  * memory instead of doing it here.
4119  */
4125 
4126 
4127  /*
4128  * Forget the query stack and constraint-related state information. As
4129  * with the subtransaction state information, we don't bother freeing the
4130  * memory here.
4131  */
4136 
4137  /* No more afterTriggers manipulation until next transaction starts. */
4139 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:203
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
CommandId * firing_stack
Definition: trigger.c:3205
SetConstraintState * state_stack
Definition: trigger.c:3202
SetConstraintState state
Definition: trigger.c:3192
AfterTriggerEventList * events_stack
Definition: trigger.c:3203
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3116
MemoryContext event_cxt
Definition: trigger.c:3198
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3196
AfterTriggerEventList events
Definition: trigger.c:3193
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static void AfterTriggerEnlargeQueryState ( void  )
static

Definition at line 4329 of file trigger.c.

References Assert, AfterTriggersData::fdw_tuplestores, AfterTriggerEventList::head, Max, AfterTriggersData::maxquerydepth, MemoryContextAlloc(), MemoryContextAllocZero(), NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, repalloc(), AfterTriggerEventList::tail, AfterTriggerEventList::tailfree, and TopTransactionContext.

Referenced by AfterTriggerSaveEvent().

4330 {
4331  int init_depth = afterTriggers.maxquerydepth;
4332 
4334 
4335  if (afterTriggers.maxquerydepth == 0)
4336  {
4337  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4338 
4341  new_alloc * sizeof(AfterTriggerEventList));
4344  new_alloc * sizeof(Tuplestorestate *));
4345  afterTriggers.maxquerydepth = new_alloc;
4346  }
4347  else
4348  {
4349  /* repalloc will keep the stack in the same context */
4350  int old_alloc = afterTriggers.maxquerydepth;
4351  int new_alloc = Max(afterTriggers.query_depth + 1,
4352  old_alloc * 2);
4353 
4356  new_alloc * sizeof(AfterTriggerEventList));
4359  new_alloc * sizeof(Tuplestorestate *));
4360  /* Clear newly-allocated slots for subsequent lazy initialization. */
4361  memset(afterTriggers.fdw_tuplestores + old_alloc,
4362  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4363  afterTriggers.maxquerydepth = new_alloc;
4364  }
4365 
4366  /* Initialize new query lists to empty */
4367  while (init_depth < afterTriggers.maxquerydepth)
4368  {
4369  AfterTriggerEventList *events;
4370 
4371  events = &afterTriggers.query_stack[init_depth];
4372  events->head = NULL;
4373  events->tail = NULL;
4374  events->tailfree = NULL;
4375 
4376  ++init_depth;
4377  }
4378 }
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:787
#define Max(x, y)
Definition: c.h:792
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1024
AfterTriggerEventChunk * head
Definition: trigger.c:3116
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:752
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3196
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static void AfterTriggerExecute ( AfterTriggerEvent  event,
Relation  rel,
TriggerDesc trigdesc,
FmgrInfo finfo,
Instrumentation instr,
MemoryContext  per_tuple_context,
TupleTableSlot trig_tuple_slot1,
TupleTableSlot trig_tuple_slot2 
)
static

Definition at line 3513 of file trigger.c.

References AFTER_TRIGGER_2CTID, AFTER_TRIGGER_FDW_FETCH, AFTER_TRIGGER_FDW_REUSE, AFTER_TRIGGER_TUP_BITS, AfterTriggerEventData::ate_ctid1, AfterTriggerEventData::ate_ctid2, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_tgoid, elog, ERROR, ExecCallTriggerFunc(), ExecMaterializeSlot(), GetCurrentFDWTuplestore(), GetTriggerSharedData, heap_fetch(), heap_freetuple(), InstrStartNode(), InstrStopNode(), InvalidBuffer, ItemPointerCopy, ItemPointerIsValid, MemoryContextReset(), NULL, TriggerDesc::numtriggers, ReleaseBuffer(), SnapshotAny, HeapTupleData::t_self, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgoid, TRIGGER_EVENT_OPMASK, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerDesc::triggers, tuplestore_gettupleslot(), and TriggerData::type.

Referenced by afterTriggerInvokeEvents().

3519 {
3520  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3521  Oid tgoid = evtshared->ats_tgoid;
3522  TriggerData LocTriggerData;
3523  HeapTupleData tuple1;
3524  HeapTupleData tuple2;
3525  HeapTuple rettuple;
3526  Buffer buffer1 = InvalidBuffer;
3527  Buffer buffer2 = InvalidBuffer;
3528  int tgindx;
3529 
3530  /*
3531  * Locate trigger in trigdesc.
3532  */
3533  LocTriggerData.tg_trigger = NULL;
3534  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3535  {
3536  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3537  {
3538  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3539  break;
3540  }
3541  }
3542  if (LocTriggerData.tg_trigger == NULL)
3543  elog(ERROR, "could not find trigger %u", tgoid);
3544 
3545  /*
3546  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3547  * to include time spent re-fetching tuples in the trigger cost.
3548  */
3549  if (instr)
3550  InstrStartNode(instr + tgindx);
3551 
3552  /*
3553  * Fetch the required tuple(s).
3554  */
3555  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3556  {
3558  {
3559  Tuplestorestate *fdw_tuplestore = GetCurrentFDWTuplestore();
3560 
3561  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3562  trig_tuple_slot1))
3563  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3564 
3565  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3567  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3568  trig_tuple_slot2))
3569  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3570  }
3571  /* fall through */
3573 
3574  /*
3575  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3576  * ensures that tg_trigtuple does not reference tuplestore memory.
3577  * (It is formally possible for the trigger function to queue
3578  * trigger events that add to the same tuplestore, which can push
3579  * other tuples out of memory.) The distinction is academic,
3580  * because we start with a minimal tuple that ExecFetchSlotTuple()
3581  * must materialize anyway.
3582  */
3583  LocTriggerData.tg_trigtuple =
3584  ExecMaterializeSlot(trig_tuple_slot1);
3585  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3586 
3587  LocTriggerData.tg_newtuple =
3588  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3590  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3591  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3592 
3593  break;
3594 
3595  default:
3596  if (ItemPointerIsValid(&(event->ate_ctid1)))
3597  {
3598  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3599  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3600  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3601  LocTriggerData.tg_trigtuple = &tuple1;
3602  LocTriggerData.tg_trigtuplebuf = buffer1;
3603  }
3604  else
3605  {
3606  LocTriggerData.tg_trigtuple = NULL;
3607  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3608  }
3609 
3610  /* don't touch ctid2 if not there */
3611  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3613  ItemPointerIsValid(&(event->ate_ctid2)))
3614  {
3615  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3616  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3617  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3618  LocTriggerData.tg_newtuple = &tuple2;
3619  LocTriggerData.tg_newtuplebuf = buffer2;
3620  }
3621  else
3622  {
3623  LocTriggerData.tg_newtuple = NULL;
3624  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3625  }
3626  }
3627 
3628  /*
3629  * Setup the remaining trigger information
3630  */
3631  LocTriggerData.type = T_TriggerData;
3632  LocTriggerData.tg_event =
3634  LocTriggerData.tg_relation = rel;
3635 
3636  MemoryContextReset(per_tuple_context);
3637 
3638  /*
3639  * Call the trigger and throw away any possibly returned updated tuple.
3640  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3641  */
3642  rettuple = ExecCallTriggerFunc(&LocTriggerData,
3643  tgindx,
3644  finfo,
3645  NULL,
3646  per_tuple_context);
3647  if (rettuple != NULL &&
3648  rettuple != LocTriggerData.tg_trigtuple &&
3649  rettuple != LocTriggerData.tg_newtuple)
3650  heap_freetuple(rettuple);
3651 
3652  /*
3653  * Release buffers
3654  */
3655  if (buffer1 != InvalidBuffer)
3656  ReleaseBuffer(buffer1);
3657  if (buffer2 != InvalidBuffer)
3658  ReleaseBuffer(buffer2);
3659 
3660  /*
3661  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3662  * one "tuple returned" (really the number of firings).
3663  */
3664  if (instr)
3665  InstrStopNode(instr + tgindx, 1);
3666 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
TriggerEvent ats_event
Definition: trigger.c:3057
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3047
static Tuplestorestate * GetCurrentFDWTuplestore(void)
Definition: trigger.c:3228
ItemPointerData ate_ctid2
Definition: trigger.c:3069
TriggerFlags ate_flags
Definition: trigger.c:3067
Buffer tg_newtuplebuf
Definition: trigger.h:39
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1860
Oid tgoid
Definition: reltrigger.h:25
#define AFTER_TRIGGER_TUP_BITS
Definition: trigger.c:3051
#define InvalidBuffer
Definition: buf.h:25
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:138
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
unsigned int Oid
Definition: postgres_ext.h:31
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:54
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define GetTriggerSharedData(evt)
Definition: trigger.c:3092
#define ERROR
Definition: elog.h:43
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:63
ItemPointerData t_self
Definition: htup.h:65
Trigger * triggers
Definition: reltrigger.h:46
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3050
int numtriggers
Definition: reltrigger.h:47
#define SnapshotAny
Definition: tqual.h:28
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1061
#define NULL
Definition: c.h:226
TriggerEvent tg_event
Definition: trigger.h:33
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3048
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:729
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:52
NodeTag type
Definition: trigger.h:32
#define elog
Definition: elog.h:218
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:1862
ItemPointerData ate_ctid1
Definition: trigger.c:3068
int Buffer
Definition: buf.h:23
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:124
Relation tg_relation
Definition: trigger.h:34
void AfterTriggerFireDeferred ( void  )

Definition at line 4039 of file trigger.c.

References afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::firing_counter, GetTransactionSnapshot(), AfterTriggerEventList::head, NULL, PopActiveSnapshot(), PushActiveSnapshot(), and AfterTriggersData::query_depth.

Referenced by CommitTransaction(), and PrepareTransaction().

4040 {
4041  AfterTriggerEventList *events;
4042  bool snap_pushed = false;
4043 
4044  /* Must not be inside a query */
4046 
4047  /*
4048  * If there are any triggers to fire, make sure we have set a snapshot for
4049  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4050  * can't assume ActiveSnapshot is valid on entry.)
4051  */
4052  events = &afterTriggers.events;
4053  if (events->head != NULL)
4054  {
4056  snap_pushed = true;
4057  }
4058 
4059  /*
4060  * Run all the remaining triggers. Loop until they are all gone, in case
4061  * some trigger queues more for us to do.
4062  */
4063  while (afterTriggerMarkEvents(events, NULL, false))
4064  {
4065  CommandId firing_id = afterTriggers.firing_counter++;
4066 
4067  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4068  break; /* all fired */
4069  }
4070 
4071  /*
4072  * We don't bother freeing the event list, since it will go away anyway
4073  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4074  */
4075 
4076  if (snap_pushed)
4078 }
uint32 CommandId
Definition: c.h:407
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3756
void PopActiveSnapshot(void)
Definition: snapmgr.c:730
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:298
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:653
CommandId firing_counter
Definition: trigger.c:3191
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
AfterTriggerEventChunk * head
Definition: trigger.c:3116
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3684
AfterTriggerEventList events
Definition: trigger.c:3193
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3435 of file trigger.c.

References AfterTriggerEventList::head, AfterTriggerEventChunk::next, NULL, pfree(), AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

Referenced by AfterTriggerEndQuery(), AfterTriggerEndSubXact(), and afterTriggerRestoreEventList().

3436 {
3437  AfterTriggerEventChunk *chunk;
3438  AfterTriggerEventChunk *next_chunk;
3439 
3440  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3441  {
3442  next_chunk = chunk->next;
3443  pfree(chunk);
3444  }
3445  events->head = NULL;
3446  events->tail = NULL;
3447  events->tailfree = NULL;
3448 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
void pfree(void *pointer)
Definition: mcxt.c:995
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3116
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

Definition at line 3756 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, AfterTriggerExecute(), ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, CHUNK_DATA_START, CreateExecutorState(), CurrentMemoryContext, elog, AfterTriggerEventChunk::endfree, AfterTriggerEventChunk::endptr, ERROR, EState::es_trig_target_relations, ExecCloseIndices(), ExecDropSingleTupleTableSlot(), ExecGetTriggerResultRel(), for_each_chunk, for_each_event, FreeExecutorState(), AfterTriggerEventChunk::freeptr, GetTriggerSharedData, heap_close, lfirst, MakeSingleTupleTableSlot(), MemoryContextDelete(), NoLock, NULL, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

Referenced by AfterTriggerEndQuery(), AfterTriggerFireDeferred(), and AfterTriggerSetState().

3760 {
3761  bool all_fired = true;
3762  AfterTriggerEventChunk *chunk;
3763  MemoryContext per_tuple_context;
3764  bool local_estate = false;
3765  Relation rel = NULL;
3766  TriggerDesc *trigdesc = NULL;
3767  FmgrInfo *finfo = NULL;
3768  Instrumentation *instr = NULL;
3769  TupleTableSlot *slot1 = NULL,
3770  *slot2 = NULL;
3771 
3772  /* Make a local EState if need be */
3773  if (estate == NULL)
3774  {
3775  estate = CreateExecutorState();
3776  local_estate = true;
3777  }
3778 
3779  /* Make a per-tuple memory context for trigger function calls */
3780  per_tuple_context =
3782  "AfterTriggerTupleContext",
3786 
3787  for_each_chunk(chunk, *events)
3788  {
3789  AfterTriggerEvent event;
3790  bool all_fired_in_chunk = true;
3791 
3792  for_each_event(event, chunk)
3793  {
3794  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3795 
3796  /*
3797  * Is it one for me to fire?
3798  */
3799  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
3800  evtshared->ats_firing_id == firing_id)
3801  {
3802  /*
3803  * So let's fire it... but first, find the correct relation if
3804  * this is not the same relation as before.
3805  */
3806  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
3807  {
3808  ResultRelInfo *rInfo;
3809 
3810  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
3811  rel = rInfo->ri_RelationDesc;
3812  trigdesc = rInfo->ri_TrigDesc;
3813  finfo = rInfo->ri_TrigFunctions;
3814  instr = rInfo->ri_TrigInstrument;
3815  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3816  {
3817  if (slot1 != NULL)
3818  {
3821  }
3822  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
3823  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
3824  }
3825  if (trigdesc == NULL) /* should not happen */
3826  elog(ERROR, "relation %u has no triggers",
3827  evtshared->ats_relid);
3828  }
3829 
3830  /*
3831  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
3832  * still set, so recursive examinations of the event list
3833  * won't try to re-fire it.
3834  */
3835  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
3836  per_tuple_context, slot1, slot2);
3837 
3838  /*
3839  * Mark the event as done.
3840  */
3841  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
3842  event->ate_flags |= AFTER_TRIGGER_DONE;
3843  }
3844  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
3845  {
3846  /* something remains to be done */
3847  all_fired = all_fired_in_chunk = false;
3848  }
3849  }
3850 
3851  /* Clear the chunk if delete_ok and nothing left of interest */
3852  if (delete_ok && all_fired_in_chunk)
3853  {
3854  chunk->freeptr = CHUNK_DATA_START(chunk);
3855  chunk->endfree = chunk->endptr;
3856 
3857  /*
3858  * If it's last chunk, must sync event list's tailfree too. Note
3859  * that delete_ok must NOT be passed as true if there could be
3860  * stacked AfterTriggerEventList values pointing at this event
3861  * list, since we'd fail to fix their copies of tailfree.
3862  */
3863  if (chunk == events->tail)
3864  events->tailfree = chunk->freeptr;
3865  }
3866  }
3867  if (slot1 != NULL)
3868  {
3871  }
3872 
3873  /* Release working resources */
3874  MemoryContextDelete(per_tuple_context);
3875 
3876  if (local_estate)
3877  {
3878  ListCell *l;
3879 
3880  foreach(l, estate->es_trig_target_relations)
3881  {
3882  ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
3883 
3884  /* Close indices and then the relation itself */
3885  ExecCloseIndices(resultRelInfo);
3886  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
3887  }
3888  FreeExecutorState(estate);
3889  }
3890 
3891  return all_fired;
3892 }
Definition: fmgr.h:53
Relation ri_RelationDesc
Definition: execnodes.h:328
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:203
TriggerFlags ate_flags
Definition: trigger.c:3067
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3044
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3111
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:335
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:83
#define ALLOCSET_DEFAULT_MINSIZE
Definition: memutils.h:142
#define GetTriggerSharedData(evt)
Definition: trigger.c:3092
#define for_each_event(eptr, cptr)
Definition: trigger.c:3124
void FreeExecutorState(EState *estate)
Definition: execUtils.c:169
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:220
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:161
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:203
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
EState * CreateExecutorState(void)
Definition: execUtils.c:72
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid)
Definition: execMain.c:1271
List * es_trig_target_relations
Definition: execnodes.h:376
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:436
TupleDesc rd_att
Definition: rel.h:84
#define for_each_chunk(cptr, evtlist)
Definition: trigger.c:3122
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
CommandId ats_firing_id
Definition: trigger.c:3060
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:143
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3045
#define ALLOCSET_DEFAULT_MAXSIZE
Definition: memutils.h:144
#define elog
Definition: elog.h:218
#define RelationGetRelid(relation)
Definition: rel.h:341
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:224
static void AfterTriggerExecute(AfterTriggerEvent event, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
Definition: trigger.c:3513
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:333
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

Definition at line 3684 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, afterTriggerAddEvent(), afterTriggerCheckState(), AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggersData::firing_counter, for_each_event_chunk, GetTriggerSharedData, and NULL.

Referenced by AfterTriggerEndQuery(), AfterTriggerFireDeferred(), and AfterTriggerSetState().

3687 {
3688  bool found = false;
3689  AfterTriggerEvent event;
3690  AfterTriggerEventChunk *chunk;
3691 
3692  for_each_event_chunk(event, chunk, *events)
3693  {
3694  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3695  bool defer_it = false;
3696 
3697  if (!(event->ate_flags &
3699  {
3700  /*
3701  * This trigger hasn't been called or scheduled yet. Check if we
3702  * should call it now.
3703  */
3704  if (immediate_only && afterTriggerCheckState(evtshared))
3705  {
3706  defer_it = true;
3707  }
3708  else
3709  {
3710  /*
3711  * Mark it as to be fired in this firing cycle.
3712  */
3714  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3715  found = true;
3716  }
3717  }
3718 
3719  /*
3720  * If it's deferred, move it to move_list, if requested.
3721  */
3722  if (defer_it && move_list != NULL)
3723  {
3724  /* add it to move_list */
3725  afterTriggerAddEvent(move_list, event, evtshared);
3726  /* mark original copy "done" so we don't do it again */
3727  event->ate_flags |= AFTER_TRIGGER_DONE;
3728  }
3729  }
3730 
3731  return found;
3732 }
TriggerFlags ate_flags
Definition: trigger.c:3067
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3044
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3129
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3272
#define GetTriggerSharedData(evt)
Definition: trigger.c:3092
CommandId firing_counter
Definition: trigger.c:3191
#define NULL
Definition: c.h:226
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3318
CommandId ats_firing_id
Definition: trigger.c:3060
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3045
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
bool AfterTriggerPendingOnRel ( Oid  relid)

Definition at line 4753 of file trigger.c.

References AFTER_TRIGGER_DONE, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_relid, AfterTriggersData::events, for_each_event_chunk, GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::query_depth, and AfterTriggersData::query_stack.

Referenced by CheckTableNotInUse().

4754 {
4755  AfterTriggerEvent event;
4756  AfterTriggerEventChunk *chunk;
4757  int depth;
4758 
4759  /* Scan queued events */
4761  {
4762  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4763 
4764  /*
4765  * We can ignore completed events. (Even if a DONE flag is rolled
4766  * back by subxact abort, it's OK because the effects of the TRUNCATE
4767  * or whatever must get rolled back too.)
4768  */
4769  if (event->ate_flags & AFTER_TRIGGER_DONE)
4770  continue;
4771 
4772  if (evtshared->ats_relid == relid)
4773  return true;
4774  }
4775 
4776  /*
4777  * Also scan events queued by incomplete queries. This could only matter
4778  * if TRUNCATE/etc is executed by a function or trigger within an updating
4779  * query on the same relation, which is pretty perverse, but let's check.
4780  */
4781  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
4782  {
4783  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
4784  {
4785  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4786 
4787  if (event->ate_flags & AFTER_TRIGGER_DONE)
4788  continue;
4789 
4790  if (evtshared->ats_relid == relid)
4791  return true;
4792  }
4793  }
4794 
4795  return false;
4796 }
TriggerFlags ate_flags
Definition: trigger.c:3067
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3044
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3129
#define GetTriggerSharedData(evt)
Definition: trigger.c:3092
AfterTriggerEventList events
Definition: trigger.c:3193
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static void afterTriggerRestoreEventList ( AfterTriggerEventList events,
const AfterTriggerEventList old_events 
)
static

Definition at line 3458 of file trigger.c.

References afterTriggerFreeEventList(), AfterTriggerEventChunk::freeptr, AfterTriggerEventChunk::next, NULL, pfree(), AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

Referenced by AfterTriggerEndSubXact().

3460 {
3461  AfterTriggerEventChunk *chunk;
3462  AfterTriggerEventChunk *next_chunk;
3463 
3464  if (old_events->tail == NULL)
3465  {
3466  /* restoring to a completely empty state, so free everything */
3467  afterTriggerFreeEventList(events);
3468  }
3469  else
3470  {
3471  *events = *old_events;
3472  /* free any chunks after the last one we want to keep */
3473  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3474  {
3475  next_chunk = chunk->next;
3476  pfree(chunk);
3477  }
3478  /* and clean up the tail chunk to be the right length */
3479  events->tail->next = NULL;
3480  events->tail->freeptr = events->tailfree;
3481 
3482  /*
3483  * We don't make any effort to remove now-unused shared data records.
3484  * They might still be useful, anyway.
3485  */
3486  }
3487 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
void pfree(void *pointer)
Definition: mcxt.c:995
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3435
#define NULL
Definition: c.h:226
static void AfterTriggerSaveEvent ( EState estate,
ResultRelInfo relinfo,
int  event,
bool  row_trigger,
HeapTuple  oldtup,
HeapTuple  newtup,
List recheckIndexes,
Bitmapset modifiedCols 
)
static

Definition at line 4811 of file trigger.c.

References AFTER_TRIGGER_1CTID, AFTER_TRIGGER_2CTID, AFTER_TRIGGER_DEFERRABLE, AFTER_TRIGGER_FDW_FETCH, AFTER_TRIGGER_FDW_REUSE, AFTER_TRIGGER_INITDEFERRED, afterTriggerAddEvent(), AfterTriggerEnlargeQueryState(), Assert, AfterTriggerEventData::ate_ctid1, AfterTriggerEventData::ate_ctid2, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, AfterTriggerSharedData::ats_tgoid, elog, ERROR, GetCurrentFDWTuplestore(), i, ItemPointerCopy, ItemPointerSetInvalid, list_member_oid(), AfterTriggersData::maxquerydepth, NULL, TriggerDesc::numtriggers, AfterTriggersData::query_depth, AfterTriggersData::query_stack, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, RI_FKey_fk_upd_check_required(), RI_FKey_pk_upd_check_required(), RI_FKey_trigger_type(), ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, RI_TRIGGER_FK, RI_TRIGGER_NONE, RI_TRIGGER_PK, HeapTupleData::t_self, Trigger::tgconstrindid, Trigger::tgdeferrable, Trigger::tgfoid, Trigger::tginitdeferred, Trigger::tgoid, Trigger::tgtype, TRIGGER_EVENT_DELETE, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_OPMASK, TRIGGER_EVENT_ROW, TRIGGER_EVENT_TRUNCATE, TRIGGER_EVENT_UPDATE, TRIGGER_FIRED_BY_UPDATE, TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_MATCHES, TRIGGER_TYPE_ROW, TRIGGER_TYPE_STATEMENT, TRIGGER_TYPE_TRUNCATE, TRIGGER_TYPE_UPDATE, TriggerEnabled(), TriggerDesc::triggers, and tuplestore_puttuple().

Referenced by ExecARDeleteTriggers(), ExecARInsertTriggers(), ExecARUpdateTriggers(), ExecASDeleteTriggers(), ExecASInsertTriggers(), ExecASTruncateTriggers(), and ExecASUpdateTriggers().

4815 {
4816  Relation rel = relinfo->ri_RelationDesc;
4817  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
4818  AfterTriggerEventData new_event;
4819  AfterTriggerSharedData new_shared;
4820  char relkind = relinfo->ri_RelationDesc->rd_rel->relkind;
4821  int tgtype_event;
4822  int tgtype_level;
4823  int i;
4824  Tuplestorestate *fdw_tuplestore = NULL;
4825 
4826  /*
4827  * Check state. We use a normal test not Assert because it is possible to
4828  * reach here in the wrong state given misconfigured RI triggers, in
4829  * particular deferring a cascade action trigger.
4830  */
4831  if (afterTriggers.query_depth < 0)
4832  elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
4833 
4834  /* Be sure we have enough space to record events at this query depth. */
4837 
4838  /*
4839  * Validate the event code and collect the associated tuple CTIDs.
4840  *
4841  * The event code will be used both as a bitmask and an array offset, so
4842  * validation is important to make sure we don't walk off the edge of our
4843  * arrays.
4844  */
4845  switch (event)
4846  {
4847  case TRIGGER_EVENT_INSERT:
4848  tgtype_event = TRIGGER_TYPE_INSERT;
4849  if (row_trigger)
4850  {
4851  Assert(oldtup == NULL);
4852  Assert(newtup != NULL);
4853  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
4854  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4855  }
4856  else
4857  {
4858  Assert(oldtup == NULL);
4859  Assert(newtup == NULL);
4860  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4861  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4862  }
4863  break;
4864  case TRIGGER_EVENT_DELETE:
4865  tgtype_event = TRIGGER_TYPE_DELETE;
4866  if (row_trigger)
4867  {
4868  Assert(oldtup != NULL);
4869  Assert(newtup == NULL);
4870  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4871  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4872  }
4873  else
4874  {
4875  Assert(oldtup == NULL);
4876  Assert(newtup == NULL);
4877  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4878  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4879  }
4880  break;
4881  case TRIGGER_EVENT_UPDATE:
4882  tgtype_event = TRIGGER_TYPE_UPDATE;
4883  if (row_trigger)
4884  {
4885  Assert(oldtup != NULL);
4886  Assert(newtup != NULL);
4887  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4888  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
4889  }
4890  else
4891  {
4892  Assert(oldtup == NULL);
4893  Assert(newtup == NULL);
4894  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4895  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4896  }
4897  break;
4899  tgtype_event = TRIGGER_TYPE_TRUNCATE;
4900  Assert(oldtup == NULL);
4901  Assert(newtup == NULL);
4902  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4903  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4904  break;
4905  default:
4906  elog(ERROR, "invalid after-trigger event code: %d", event);
4907  tgtype_event = 0; /* keep compiler quiet */
4908  break;
4909  }
4910 
4911  if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
4912  new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
4914  /* else, we'll initialize ate_flags for each trigger */
4915 
4916  tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
4917 
4918  for (i = 0; i < trigdesc->numtriggers; i++)
4919  {
4920  Trigger *trigger = &trigdesc->triggers[i];
4921 
4922  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
4923  tgtype_level,
4925  tgtype_event))
4926  continue;
4927  if (!TriggerEnabled(estate, relinfo, trigger, event,
4928  modifiedCols, oldtup, newtup))
4929  continue;
4930 
4931  if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
4932  {
4933  if (fdw_tuplestore == NULL)
4934  {
4935  fdw_tuplestore = GetCurrentFDWTuplestore();
4936  new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
4937  }
4938  else
4939  /* subsequent event for the same tuple */
4940  new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
4941  }
4942 
4943  /*
4944  * If the trigger is a foreign key enforcement trigger, there are
4945  * certain cases where we can skip queueing the event because we can
4946  * tell by inspection that the FK constraint will still pass.
4947  */
4948  if (TRIGGER_FIRED_BY_UPDATE(event))
4949  {
4950  switch (RI_FKey_trigger_type(trigger->tgfoid))
4951  {
4952  case RI_TRIGGER_PK:
4953  /* Update on trigger's PK table */
4954  if (!RI_FKey_pk_upd_check_required(trigger, rel,
4955  oldtup, newtup))
4956  {
4957  /* skip queuing this event */
4958  continue;
4959  }
4960  break;
4961 
4962  case RI_TRIGGER_FK:
4963  /* Update on trigger's FK table */
4964  if (!RI_FKey_fk_upd_check_required(trigger, rel,
4965  oldtup, newtup))
4966  {
4967  /* skip queuing this event */
4968  continue;
4969  }
4970  break;
4971 
4972  case RI_TRIGGER_NONE:
4973  /* Not an FK trigger */
4974  break;
4975  }
4976  }
4977 
4978  /*
4979  * If the trigger is a deferred unique constraint check trigger, only
4980  * queue it if the unique constraint was potentially violated, which
4981  * we know from index insertion time.
4982  */
4983  if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
4984  {
4985  if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
4986  continue; /* Uniqueness definitely not violated */
4987  }
4988 
4989  /*
4990  * Fill in event structure and add it to the current query's queue.
4991  */
4992  new_shared.ats_event =
4993  (event & TRIGGER_EVENT_OPMASK) |
4994  (row_trigger ? TRIGGER_EVENT_ROW : 0) |
4995  (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
4996  (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
4997  new_shared.ats_tgoid = trigger->tgoid;
4998  new_shared.ats_relid = RelationGetRelid(rel);
4999  new_shared.ats_firing_id = 0;
5000 
5002  &new_event, &new_shared);
5003  }
5004 
5005  /*
5006  * Finally, spool any foreign tuple(s). The tuplestore squashes them to
5007  * minimal tuples, so this loses any system columns. The executor lost
5008  * those columns before us, for an unrelated reason, so this is fine.
5009  */
5010  if (fdw_tuplestore)
5011  {
5012  if (oldtup != NULL)
5013  tuplestore_puttuple(fdw_tuplestore, oldtup);
5014  if (newtup != NULL)
5015  tuplestore_puttuple(fdw_tuplestore, newtup);
5016  }
5017 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
TriggerEvent ats_event
Definition: trigger.c:3057
Relation ri_RelationDesc
Definition: execnodes.h:328
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3706
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3047
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:66
static Tuplestorestate * GetCurrentFDWTuplestore(void)
Definition: trigger.c:3228
ItemPointerData ate_ctid2
Definition: trigger.c:3069
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:97
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:51
Oid tgfoid
Definition: reltrigger.h:28
TriggerFlags ate_flags
Definition: trigger.c:3067
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:65
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:142
Oid tgoid
Definition: reltrigger.h:25
Form_pg_class rd_rel
Definition: rel.h:83
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:54
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
bool tgdeferrable
Definition: reltrigger.h:35
ItemPointerData t_self
Definition: htup.h:65
bool tginitdeferred
Definition: reltrigger.h:36
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:715
Trigger * triggers
Definition: reltrigger.h:46
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:161
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:94
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3049
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3050
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
int numtriggers
Definition: reltrigger.h:47
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, HeapTuple old_row, HeapTuple new_row)
Definition: ri_triggers.c:2146
#define TRIGGER_TYPE_TRUNCATE
Definition: pg_trigger.h:99
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:98
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:2824
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4329
#define RI_TRIGGER_FK
Definition: trigger.h:208
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3318
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:53
Oid tgconstrindid
Definition: reltrigger.h:33
bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, HeapTuple old_row, HeapTuple new_row)
Definition: ri_triggers.c:2089
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:96
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3048
CommandId ats_firing_id
Definition: trigger.c:3060
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:52
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:50
#define RI_TRIGGER_PK
Definition: trigger.h:207
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:135
int i
AfterTriggerEventList * query_stack
Definition: trigger.c:3195
#define elog
Definition: elog.h:218
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:103
ItemPointerData ate_ctid1
Definition: trigger.c:3068
#define RI_TRIGGER_NONE
Definition: trigger.h:209
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:74
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
#define RelationGetRelid(relation)
Definition: rel.h:341
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:124
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 4459 of file trigger.c.

References AccessShareLock, afterTriggerInvokeEvents(), afterTriggerMarkEvents(), SetConstraintStateData::all_isdeferred, SetConstraintStateData::all_isset, Anum_pg_constraint_conname, Anum_pg_constraint_connamespace, Anum_pg_trigger_tgconstraint, BTEqualStrategyNumber, RangeVar::catalogname, ConstraintNameNspIndexId, ConstraintRelationId, ConstraintsSetStmt::constraints, CStringGetDatum, ConstraintsSetStmt::deferred, elog, ereport, errcode(), errmsg(), ERROR, AfterTriggersData::events, fetch_search_path(), AfterTriggersData::firing_counter, get_database_name(), GetCurrentTransactionNestLevel(), GETSTRUCT, GetTransactionSnapshot(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, i, IsSubTransaction(), lappend_oid(), lfirst, lfirst_oid, list_free(), list_make1_oid, LookupExplicitNamespace(), MyDatabaseId, NIL, NULL, SetConstraintStateData::numstates, ObjectIdGetDatum, PopActiveSnapshot(), PushActiveSnapshot(), RangeVar::relname, ScanKeyInit(), RangeVar::schemaname, SetConstraintTriggerData::sct_tgisdeferred, SetConstraintTriggerData::sct_tgoid, SetConstraintStateAddItem(), SetConstraintStateCopy(), SetConstraintStateCreate(), AfterTriggersData::state, AfterTriggersData::state_stack, systable_beginscan(), systable_endscan(), systable_getnext(), TriggerConstraintIndexId, TriggerRelationId, and SetConstraintStateData::trigstates.

Referenced by standard_ProcessUtility().

4460 {
4461  int my_level = GetCurrentTransactionNestLevel();
4462 
4463  /* If we haven't already done so, initialize our state. */
4464  if (afterTriggers.state == NULL)
4466 
4467  /*
4468  * If in a subtransaction, and we didn't save the current state already,
4469  * save it so it can be restored if the subtransaction aborts.
4470  */
4471  if (my_level > 1 &&
4472  afterTriggers.state_stack[my_level] == NULL)
4473  {
4474  afterTriggers.state_stack[my_level] =
4476  }
4477 
4478  /*
4479  * Handle SET CONSTRAINTS ALL ...
4480  */
4481  if (stmt->constraints == NIL)
4482  {
4483  /*
4484  * Forget any previous SET CONSTRAINTS commands in this transaction.
4485  */
4487 
4488  /*
4489  * Set the per-transaction ALL state to known.
4490  */
4491  afterTriggers.state->all_isset = true;
4493  }
4494  else
4495  {
4496  Relation conrel;
4497  Relation tgrel;
4498  List *conoidlist = NIL;
4499  List *tgoidlist = NIL;
4500  ListCell *lc;
4501 
4502  /*
4503  * Handle SET CONSTRAINTS constraint-name [, ...]
4504  *
4505  * First, identify all the named constraints and make a list of their
4506  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4507  * the same name within a schema, the specifications are not
4508  * necessarily unique. Our strategy is to target all matching
4509  * constraints within the first search-path schema that has any
4510  * matches, but disregard matches in schemas beyond the first match.
4511  * (This is a bit odd but it's the historical behavior.)
4512  */
4514 
4515  foreach(lc, stmt->constraints)
4516  {
4517  RangeVar *constraint = lfirst(lc);
4518  bool found;
4519  List *namespacelist;
4520  ListCell *nslc;
4521 
4522  if (constraint->catalogname)
4523  {
4524  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4525  ereport(ERROR,
4526  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4527  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4528  constraint->catalogname, constraint->schemaname,
4529  constraint->relname)));
4530  }
4531 
4532  /*
4533  * If we're given the schema name with the constraint, look only
4534  * in that schema. If given a bare constraint name, use the
4535  * search path to find the first matching constraint.
4536  */
4537  if (constraint->schemaname)
4538  {
4539  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4540  false);
4541 
4542  namespacelist = list_make1_oid(namespaceId);
4543  }
4544  else
4545  {
4546  namespacelist = fetch_search_path(true);
4547  }
4548 
4549  found = false;
4550  foreach(nslc, namespacelist)
4551  {
4552  Oid namespaceId = lfirst_oid(nslc);
4553  SysScanDesc conscan;
4554  ScanKeyData skey[2];
4555  HeapTuple tup;
4556 
4557  ScanKeyInit(&skey[0],
4559  BTEqualStrategyNumber, F_NAMEEQ,
4560  CStringGetDatum(constraint->relname));
4561  ScanKeyInit(&skey[1],
4563  BTEqualStrategyNumber, F_OIDEQ,
4564  ObjectIdGetDatum(namespaceId));
4565 
4566  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4567  true, NULL, 2, skey);
4568 
4569  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4570  {
4572 
4573  if (con->condeferrable)
4574  conoidlist = lappend_oid(conoidlist,
4575  HeapTupleGetOid(tup));
4576  else if (stmt->deferred)
4577  ereport(ERROR,
4578  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4579  errmsg("constraint \"%s\" is not deferrable",
4580  constraint->relname)));
4581  found = true;
4582  }
4583 
4584  systable_endscan(conscan);
4585 
4586  /*
4587  * Once we've found a matching constraint we do not search
4588  * later parts of the search path.
4589  */
4590  if (found)
4591  break;
4592  }
4593 
4594  list_free(namespacelist);
4595 
4596  /*
4597  * Not found ?
4598  */
4599  if (!found)
4600  ereport(ERROR,
4601  (errcode(ERRCODE_UNDEFINED_OBJECT),
4602  errmsg("constraint \"%s\" does not exist",
4603  constraint->relname)));
4604  }
4605 
4606  heap_close(conrel, AccessShareLock);
4607 
4608  /*
4609  * Now, locate the trigger(s) implementing each of these constraints,
4610  * and make a list of their OIDs.
4611  */
4613 
4614  foreach(lc, conoidlist)
4615  {
4616  Oid conoid = lfirst_oid(lc);
4617  bool found;
4618  ScanKeyData skey;
4619  SysScanDesc tgscan;
4620  HeapTuple htup;
4621 
4622  found = false;
4623 
4624  ScanKeyInit(&skey,
4626  BTEqualStrategyNumber, F_OIDEQ,
4627  ObjectIdGetDatum(conoid));
4628 
4629  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
4630  NULL, 1, &skey);
4631 
4632  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
4633  {
4634  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
4635 
4636  /*
4637  * Silently skip triggers that are marked as non-deferrable in
4638  * pg_trigger. This is not an error condition, since a
4639  * deferrable RI constraint may have some non-deferrable
4640  * actions.
4641  */
4642  if (pg_trigger->tgdeferrable)
4643  tgoidlist = lappend_oid(tgoidlist,
4644  HeapTupleGetOid(htup));
4645 
4646  found = true;
4647  }
4648 
4649  systable_endscan(tgscan);
4650 
4651  /* Safety check: a deferrable constraint should have triggers */
4652  if (!found)
4653  elog(ERROR, "no triggers found for constraint with OID %u",
4654  conoid);
4655  }
4656 
4657  heap_close(tgrel, AccessShareLock);
4658 
4659  /*
4660  * Now we can set the trigger states of individual triggers for this
4661  * xact.
4662  */
4663  foreach(lc, tgoidlist)
4664  {
4665  Oid tgoid = lfirst_oid(lc);
4667  bool found = false;
4668  int i;
4669 
4670  for (i = 0; i < state->numstates; i++)
4671  {
4672  if (state->trigstates[i].sct_tgoid == tgoid)
4673  {
4674  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
4675  found = true;
4676  break;
4677  }
4678  }
4679  if (!found)
4680  {
4682  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
4683  }
4684  }
4685  }
4686 
4687  /*
4688  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
4689  * checks against that constraint must be made when the SET CONSTRAINTS
4690  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
4691  * apply retroactively. We've updated the constraints state, so scan the
4692  * list of previously deferred events to fire any that have now become
4693  * immediate.
4694  *
4695  * Obviously, if this was SET ... DEFERRED then it can't have converted
4696  * any unfired events to immediate, so we need do nothing in that case.
4697  */
4698  if (!stmt->deferred)
4699  {
4701  bool snapshot_set = false;
4702 
4703  while (afterTriggerMarkEvents(events, NULL, true))
4704  {
4705  CommandId firing_id = afterTriggers.firing_counter++;
4706 
4707  /*
4708  * Make sure a snapshot has been established in case trigger
4709  * functions need one. Note that we avoid setting a snapshot if
4710  * we don't find at least one trigger that has to be fired now.
4711  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
4712  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
4713  * at the start of a transaction it's not possible for any trigger
4714  * events to be queued yet.)
4715  */
4716  if (!snapshot_set)
4717  {
4719  snapshot_set = true;
4720  }
4721 
4722  /*
4723  * We can delete fired events if we are at top transaction level,
4724  * but we'd better not if inside a subtransaction, since the
4725  * subtransaction could later get rolled back.
4726  */
4727  if (afterTriggerInvokeEvents(events, firing_id, NULL,
4728  !IsSubTransaction()))
4729  break; /* all fired */
4730  }
4731 
4732  if (snapshot_set)
4734  }
4735 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:407
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2702
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:631
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:85
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3004
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
Definition: trigger.c:4429
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3756
void PopActiveSnapshot(void)
Definition: snapmgr.c:730
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_constraint_conname
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:298
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
char * schemaname
Definition: primnodes.h:73
char * relname
Definition: primnodes.h:74
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
SetConstraintState * state_stack
Definition: trigger.c:3202
SetConstraintState state
Definition: trigger.c:3192
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2024
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:653
#define CStringGetDatum(X)
Definition: postgres.h:586
#define TriggerConstraintIndexId
Definition: indexing.h:231
#define ereport(elevel, rest)
Definition: elog.h:122
static SetConstraintState SetConstraintStateCreate(int numalloc)
Definition: trigger.c:4384
#define list_make1_oid(x1)
Definition: pg_list.h:145
Oid MyDatabaseId
Definition: globals.c:74
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1298
CommandId firing_counter
Definition: trigger.c:3191
#define ConstraintNameNspIndexId
Definition: indexing.h:118
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:758
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Definition: regguts.h:313
#define TriggerRelationId
Definition: pg_trigger.h:34
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:70
bool IsSubTransaction(void)
Definition: xact.c:4372
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
int i
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3684
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3193
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:218
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:670
Definition: pg_list.h:45
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:3983
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
char * catalogname
Definition: primnodes.h:72
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:4409
static void ConvertTriggerToFK ( CreateTrigStmt stmt,
Oid  funcoid 
)
static

Definition at line 833 of file trigger.c.

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, OldTriggerInfo::args, CreateTrigStmt::args, AT_AddConstraint, buf, AlterTableStmt::cmds, Constraint::conname, CONSTR_FOREIGN, CreateTrigStmt::constrrel, Constraint::contype, copyObject(), StringInfoData::data, AlterTableCmd::def, Constraint::deferrable, CreateTrigStmt::deferrable, elog, equal(), ereport, errdetail_internal(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, FKCONSTR_ACTION_CASCADE, FKCONSTR_ACTION_NOACTION, FKCONSTR_ACTION_RESTRICT, FKCONSTR_ACTION_SETDEFAULT, FKCONSTR_ACTION_SETNULL, FKCONSTR_MATCH_FULL, FKCONSTR_MATCH_SIMPLE, OldTriggerInfo::funcoids, gettext_noop, i, Constraint::initdeferred, CreateTrigStmt::initdeferred, Constraint::initially_valid, initStringInfo(), InvalidOid, lappend(), lfirst, linitial, list_delete_ptr(), list_make1, Constraint::location, lsecond, lthird, makeNode, makeRangeVar(), MemoryContextSwitchTo(), NIL, None_Receiver, NOTICE, NULL, OBJECT_TABLE, palloc0(), pfree(), Constraint::pk_attrs, Constraint::pktable, PROCESS_UTILITY_SUBCOMMAND, ProcessUtility(), quote_identifier(), AlterTableStmt::relation, CreateTrigStmt::relation, AlterTableStmt::relkind, Constraint::skip_validation, strVal, AlterTableCmd::subtype, and TopMemoryContext.

Referenced by CreateTrigger().

834 {
835  static List *info_list = NIL;
836 
837  static const char *const funcdescr[3] = {
838  gettext_noop("Found referenced table's UPDATE trigger."),
839  gettext_noop("Found referenced table's DELETE trigger."),
840  gettext_noop("Found referencing table's trigger.")
841  };
842 
843  char *constr_name;
844  char *fk_table_name;
845  char *pk_table_name;
846  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
847  List *fk_attrs = NIL;
848  List *pk_attrs = NIL;
850  int funcnum;
851  OldTriggerInfo *info = NULL;
852  ListCell *l;
853  int i;
854 
855  /* Parse out the trigger arguments */
856  constr_name = strVal(linitial(stmt->args));
857  fk_table_name = strVal(lsecond(stmt->args));
858  pk_table_name = strVal(lthird(stmt->args));
859  i = 0;
860  foreach(l, stmt->args)
861  {
862  Value *arg = (Value *) lfirst(l);
863 
864  i++;
865  if (i < 4) /* skip constraint and table names */
866  continue;
867  if (i == 4) /* handle match type */
868  {
869  if (strcmp(strVal(arg), "FULL") == 0)
870  fk_matchtype = FKCONSTR_MATCH_FULL;
871  else
872  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
873  continue;
874  }
875  if (i % 2)
876  fk_attrs = lappend(fk_attrs, arg);
877  else
878  pk_attrs = lappend(pk_attrs, arg);
879  }
880 
881  /* Prepare description of constraint for use in messages */
882  initStringInfo(&buf);
883  appendStringInfo(&buf, "FOREIGN KEY %s(",
884  quote_identifier(fk_table_name));
885  i = 0;
886  foreach(l, fk_attrs)
887  {
888  Value *arg = (Value *) lfirst(l);
889 
890  if (i++ > 0)
891  appendStringInfoChar(&buf, ',');
893  }
894  appendStringInfo(&buf, ") REFERENCES %s(",
895  quote_identifier(pk_table_name));
896  i = 0;
897  foreach(l, pk_attrs)
898  {
899  Value *arg = (Value *) lfirst(l);
900 
901  if (i++ > 0)
902  appendStringInfoChar(&buf, ',');
904  }
905  appendStringInfoChar(&buf, ')');
906 
907  /* Identify class of trigger --- update, delete, or referencing-table */
908  switch (funcoid)
909  {
910  case F_RI_FKEY_CASCADE_UPD:
911  case F_RI_FKEY_RESTRICT_UPD:
912  case F_RI_FKEY_SETNULL_UPD:
913  case F_RI_FKEY_SETDEFAULT_UPD:
914  case F_RI_FKEY_NOACTION_UPD:
915  funcnum = 0;
916  break;
917 
918  case F_RI_FKEY_CASCADE_DEL:
919  case F_RI_FKEY_RESTRICT_DEL:
920  case F_RI_FKEY_SETNULL_DEL:
921  case F_RI_FKEY_SETDEFAULT_DEL:
922  case F_RI_FKEY_NOACTION_DEL:
923  funcnum = 1;
924  break;
925 
926  default:
927  funcnum = 2;
928  break;
929  }
930 
931  /* See if we have a match to this trigger */
932  foreach(l, info_list)
933  {
934  info = (OldTriggerInfo *) lfirst(l);
935  if (info->funcoids[funcnum] == InvalidOid &&
936  equal(info->args, stmt->args))
937  {
938  info->funcoids[funcnum] = funcoid;
939  break;
940  }
941  }
942 
943  if (l == NULL)
944  {
945  /* First trigger of set, so create a new list entry */
946  MemoryContext oldContext;
947 
948  ereport(NOTICE,
949  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
950  constr_name, buf.data),
951  errdetail_internal("%s", _(funcdescr[funcnum]))));
953  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
954  info->args = copyObject(stmt->args);
955  info->funcoids[funcnum] = funcoid;
956  info_list = lappend(info_list, info);
957  MemoryContextSwitchTo(oldContext);
958  }
959  else if (info->funcoids[0] == InvalidOid ||
960  info->funcoids[1] == InvalidOid ||
961  info->funcoids[2] == InvalidOid)
962  {
963  /* Second trigger of set */
964  ereport(NOTICE,
965  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
966  constr_name, buf.data),
967  errdetail_internal("%s", _(funcdescr[funcnum]))));
968  }
969  else
970  {
971  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
974  Constraint *fkcon = makeNode(Constraint);
975 
976  ereport(NOTICE,
977  (errmsg("converting trigger group into constraint \"%s\" %s",
978  constr_name, buf.data),
979  errdetail_internal("%s", _(funcdescr[funcnum]))));
980  fkcon->contype = CONSTR_FOREIGN;
981  fkcon->location = -1;
982  if (funcnum == 2)
983  {
984  /* This trigger is on the FK table */
985  atstmt->relation = stmt->relation;
986  if (stmt->constrrel)
987  fkcon->pktable = stmt->constrrel;
988  else
989  {
990  /* Work around ancient pg_dump bug that omitted constrrel */
991  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
992  }
993  }
994  else
995  {
996  /* This trigger is on the PK table */
997  fkcon->pktable = stmt->relation;
998  if (stmt->constrrel)
999  atstmt->relation = stmt->constrrel;
1000  else
1001  {
1002  /* Work around ancient pg_dump bug that omitted constrrel */
1003  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1004  }
1005  }
1006  atstmt->cmds = list_make1(atcmd);
1007  atstmt->relkind = OBJECT_TABLE;
1008  atcmd->subtype = AT_AddConstraint;
1009  atcmd->def = (Node *) fkcon;
1010  if (strcmp(constr_name, "<unnamed>") == 0)
1011  fkcon->conname = NULL;
1012  else
1013  fkcon->conname = constr_name;
1014  fkcon->fk_attrs = fk_attrs;
1015  fkcon->pk_attrs = pk_attrs;
1016  fkcon->fk_matchtype = fk_matchtype;
1017  switch (info->funcoids[0])
1018  {
1019  case F_RI_FKEY_NOACTION_UPD:
1021  break;
1022  case F_RI_FKEY_CASCADE_UPD:
1024  break;
1025  case F_RI_FKEY_RESTRICT_UPD:
1027  break;
1028  case F_RI_FKEY_SETNULL_UPD:
1030  break;
1031  case F_RI_FKEY_SETDEFAULT_UPD:
1033  break;
1034  default:
1035  /* can't get here because of earlier checks */
1036  elog(ERROR, "confused about RI update function");
1037  }
1038  switch (info->funcoids[1])
1039  {
1040  case F_RI_FKEY_NOACTION_DEL:
1042  break;
1043  case F_RI_FKEY_CASCADE_DEL:
1045  break;
1046  case F_RI_FKEY_RESTRICT_DEL:
1048  break;
1049  case F_RI_FKEY_SETNULL_DEL:
1051  break;
1052  case F_RI_FKEY_SETDEFAULT_DEL:
1054  break;
1055  default:
1056  /* can't get here because of earlier checks */
1057  elog(ERROR, "confused about RI delete function");
1058  }
1059  fkcon->deferrable = stmt->deferrable;
1060  fkcon->initdeferred = stmt->initdeferred;
1061  fkcon->skip_validation = false;
1062  fkcon->initially_valid = true;
1063 
1064  /* ... and execute it */
1065  ProcessUtility((Node *) atstmt,
1066  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1068  None_Receiver, NULL);
1069 
1070  /* Remove the matched item from the list */
1071  info_list = list_delete_ptr(info_list, info);
1072  pfree(info);
1073  /* We leak the copied args ... not worth worrying about */
1074  }
1075 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:1819
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:9518
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2716
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:1810
char fk_matchtype
Definition: parsenodes.h:1855
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:1814
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:491
#define strVal(v)
Definition: value.h:54
bool initdeferred
Definition: parsenodes.h:1829
AlterTableType subtype
Definition: parsenodes.h:1540
List * pk_attrs
Definition: parsenodes.h:1854
char * conname
Definition: parsenodes.h:1827
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
DestReceiver * None_Receiver
Definition: dest.c:84
#define lsecond(l)
Definition: pg_list.h:114
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void * copyObject(const void *from)
Definition: copyfuncs.c:4262
#define list_make1(x1)
Definition: pg_list.h:133
RangeVar * constrrel
Definition: parsenodes.h:2108
void pfree(void *pointer)
Definition: mcxt.c:995
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:1828
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
static char * buf
Definition: pg_test_fsync.c:65
Oid funcoids[3]
Definition: trigger.c:828
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1460
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:1812
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:1817
void * palloc0(Size size)
Definition: mcxt.c:923
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:1863
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:539
char fk_del_action
Definition: parsenodes.h:1857
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:827
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1458
int i
RangeVar * relation
Definition: parsenodes.h:2094
ConstrType contype
Definition: parsenodes.h:1824
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:1811
#define lthird(l)
Definition: pg_list.h:118
#define elog
Definition: elog.h:218
RangeVar * pktable
Definition: parsenodes.h:1852
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:1813
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:1862
#define _(x)
Definition: elog.c:83
List * fk_attrs
Definition: parsenodes.h:1853
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:1856
void ProcessUtility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:317
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1691 of file trigger.c.

References i, NULL, TriggerDesc::numtriggers, palloc(), pstrdup(), Trigger::tgargs, Trigger::tgattr, Trigger::tgname, Trigger::tgnargs, Trigger::tgnattr, Trigger::tgqual, and TriggerDesc::triggers.

Referenced by InitResultRelInfo(), and RelationBuildTriggers().

1692 {
1693  TriggerDesc *newdesc;
1694  Trigger *trigger;
1695  int i;
1696 
1697  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1698  return NULL;
1699 
1700  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1701  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1702 
1703  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1704  memcpy(trigger, trigdesc->triggers,
1705  trigdesc->numtriggers * sizeof(Trigger));
1706  newdesc->triggers = trigger;
1707 
1708  for (i = 0; i < trigdesc->numtriggers; i++)
1709  {
1710  trigger->tgname = pstrdup(trigger->tgname);
1711  if (trigger->tgnattr > 0)
1712  {
1713  int16 *newattr;
1714 
1715  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1716  memcpy(newattr, trigger->tgattr,
1717  trigger->tgnattr * sizeof(int16));
1718  trigger->tgattr = newattr;
1719  }
1720  if (trigger->tgnargs > 0)
1721  {
1722  char **newargs;
1723  int16 j;
1724 
1725  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1726  for (j = 0; j < trigger->tgnargs; j++)
1727  newargs[j] = pstrdup(trigger->tgargs[j]);
1728  trigger->tgargs = newargs;
1729  }
1730  if (trigger->tgqual)
1731  trigger->tgqual = pstrdup(trigger->tgqual);
1732  trigger++;
1733  }
1734 
1735  return newdesc;
1736 }
signed short int16
Definition: c.h:252
char * pstrdup(const char *in)
Definition: mcxt.c:1168
char * tgqual
Definition: reltrigger.h:41
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:46
int numtriggers
Definition: reltrigger.h:47
char ** tgargs
Definition: reltrigger.h:40
int16 * tgattr
Definition: reltrigger.h:39
#define NULL
Definition: c.h:226
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:894
int i
int16 tgnargs
Definition: reltrigger.h:37
ObjectAddress CreateTrigger ( CreateTrigStmt stmt,
const char *  queryString,
Oid  relOid,
Oid  refRelOid,
Oid  constraintOid,
Oid  indexOid,
bool  isInternal 
)

Definition at line 138 of file trigger.c.

References AccessShareLock, ACL_EXECUTE, ACL_KIND_CLASS, ACL_KIND_PROC, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addRangeTableEntryForRelation(), addRTEtoQuery(), allowSystemTableMods, Anum_pg_trigger_tgargs, Anum_pg_trigger_tgattr, Anum_pg_trigger_tgconstraint, Anum_pg_trigger_tgconstrindid, Anum_pg_trigger_tgconstrrelid, Anum_pg_trigger_tgdeferrable, Anum_pg_trigger_tgenabled, Anum_pg_trigger_tgfoid, Anum_pg_trigger_tginitdeferred, Anum_pg_trigger_tgisinternal, Anum_pg_trigger_tgname, Anum_pg_trigger_tgnargs, Anum_pg_trigger_tgqual, Anum_pg_trigger_tgrelid, Anum_pg_trigger_tgtype, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CatalogUpdateIndexes(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CONSTRAINT_TRIGGER, ConstraintRelationId, CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject(), CreateConstraintEntry(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), GetNewOid(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleIsValid, HeapTupleSetOid, i, CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, IsSystemRelation(), lfirst, list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), name, NAMEDATALEN, namein(), NameListToString(), namestrcmp(), Natts_pg_trigger, NIL, nodeToString(), NoLock, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPAQUEOID, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, ProcedureRelationId, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_FOREIGN_TABLE, RELKIND_RELATION, RELKIND_VIEW, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, simple_heap_insert(), simple_heap_update(), snprintf(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, CreateTrigStmt::timing, transformWhereClause(), TRIGGER_CLEAR_TYPE, TRIGGER_FIRES_ON_ORIGIN, TRIGGER_FOR_BEFORE, TRIGGER_FOR_DELETE, TRIGGER_FOR_INSERT, TRIGGER_FOR_INSTEAD, TRIGGER_FOR_ROW, TRIGGER_FOR_TRUNCATE, TRIGGER_SETT_ROW, TRIGGER_TYPE_AFTER, TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSTEAD, TRIGGEROID, TriggerRelationId, TriggerRelidNameIndexId, CreateTrigStmt::trigname, values, Var::varattno, Var::varno, WARNING, and CreateTrigStmt::whenClause.

Referenced by CreateFKCheckTrigger(), createForeignKeyTriggers(), index_constraint_create(), and ProcessUtilitySlow().

141 {
142  int16 tgtype;
143  int ncolumns;
144  int16 *columns;
145  int2vector *tgattr;
146  Node *whenClause;
147  List *whenRtable;
148  char *qual;
150  bool nulls[Natts_pg_trigger];
151  Relation rel;
152  AclResult aclresult;
153  Relation tgrel;
154  SysScanDesc tgscan;
155  ScanKeyData key;
156  Relation pgrel;
157  HeapTuple tuple;
158  Oid fargtypes[1]; /* dummy */
159  Oid funcoid;
160  Oid funcrettype;
161  Oid trigoid;
162  char internaltrigname[NAMEDATALEN];
163  char *trigname;
164  Oid constrrelid = InvalidOid;
165  ObjectAddress myself,
166  referenced;
167 
168  if (OidIsValid(relOid))
169  rel = heap_open(relOid, ShareRowExclusiveLock);
170  else
172 
173  /*
174  * Triggers must be on tables or views, and there are additional
175  * relation-type-specific restrictions.
176  */
177  if (rel->rd_rel->relkind == RELKIND_RELATION)
178  {
179  /* Tables can't have INSTEAD OF triggers */
180  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
181  stmt->timing != TRIGGER_TYPE_AFTER)
182  ereport(ERROR,
183  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
184  errmsg("\"%s\" is a table",
186  errdetail("Tables cannot have INSTEAD OF triggers.")));
187  }
188  else if (rel->rd_rel->relkind == RELKIND_VIEW)
189  {
190  /*
191  * Views can have INSTEAD OF triggers (which we check below are
192  * row-level), or statement-level BEFORE/AFTER triggers.
193  */
194  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
195  ereport(ERROR,
196  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
197  errmsg("\"%s\" is a view",
199  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
200  /* Disallow TRUNCATE triggers on VIEWs */
201  if (TRIGGER_FOR_TRUNCATE(stmt->events))
202  ereport(ERROR,
203  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
204  errmsg("\"%s\" is a view",
206  errdetail("Views cannot have TRUNCATE triggers.")));
207  }
208  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
209  {
210  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
211  stmt->timing != TRIGGER_TYPE_AFTER)
212  ereport(ERROR,
213  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
214  errmsg("\"%s\" is a foreign table",
216  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
217 
218  if (TRIGGER_FOR_TRUNCATE(stmt->events))
219  ereport(ERROR,
220  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
221  errmsg("\"%s\" is a foreign table",
223  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
224 
225  if (stmt->isconstraint)
226  ereport(ERROR,
227  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
228  errmsg("\"%s\" is a foreign table",
230  errdetail("Foreign tables cannot have constraint triggers.")));
231  }
232  else
233  ereport(ERROR,
234  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
235  errmsg("\"%s\" is not a table or view",
236  RelationGetRelationName(rel))));
237 
239  ereport(ERROR,
240  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
241  errmsg("permission denied: \"%s\" is a system catalog",
242  RelationGetRelationName(rel))));
243 
244  if (stmt->isconstraint)
245  {
246  /*
247  * We must take a lock on the target relation to protect against
248  * concurrent drop. It's not clear that AccessShareLock is strong
249  * enough, but we certainly need at least that much... otherwise, we
250  * might end up creating a pg_constraint entry referencing a
251  * nonexistent table.
252  */
253  if (OidIsValid(refRelOid))
254  {
255  LockRelationOid(refRelOid, AccessShareLock);
256  constrrelid = refRelOid;
257  }
258  else if (stmt->constrrel != NULL)
259  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
260  false);
261  }
262 
263  /* permission checks */
264  if (!isInternal)
265  {
266  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
267  ACL_TRIGGER);
268  if (aclresult != ACLCHECK_OK)
269  aclcheck_error(aclresult, ACL_KIND_CLASS,
271 
272  if (OidIsValid(constrrelid))
273  {
274  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
275  ACL_TRIGGER);
276  if (aclresult != ACLCHECK_OK)
277  aclcheck_error(aclresult, ACL_KIND_CLASS,
278  get_rel_name(constrrelid));
279  }
280  }
281 
282  /* Compute tgtype */
283  TRIGGER_CLEAR_TYPE(tgtype);
284  if (stmt->row)
285  TRIGGER_SETT_ROW(tgtype);
286  tgtype |= stmt->timing;
287  tgtype |= stmt->events;
288 
289  /* Disallow ROW-level TRUNCATE triggers */
290  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
291  ereport(ERROR,
292  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
293  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
294 
295  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
296  if (TRIGGER_FOR_INSTEAD(tgtype))
297  {
298  if (!TRIGGER_FOR_ROW(tgtype))
299  ereport(ERROR,
300  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
301  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
302  if (stmt->whenClause)
303  ereport(ERROR,
304  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
306  if (stmt->columns != NIL)
307  ereport(ERROR,
308  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
309  errmsg("INSTEAD OF triggers cannot have column lists")));
310  }
311 
312  /*
313  * Parse the WHEN clause, if any
314  */
315  if (stmt->whenClause)
316  {
317  ParseState *pstate;
318  RangeTblEntry *rte;
319  List *varList;
320  ListCell *lc;
321 
322  /* Set up a pstate to parse with */
323  pstate = make_parsestate(NULL);
324  pstate->p_sourcetext = queryString;
325 
326  /*
327  * Set up RTEs for OLD and NEW references.
328  *
329  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
330  */
331  rte = addRangeTableEntryForRelation(pstate, rel,
332  makeAlias("old", NIL),
333  false, false);
334  addRTEtoQuery(pstate, rte, false, true, true);
335  rte = addRangeTableEntryForRelation(pstate, rel,
336  makeAlias("new", NIL),
337  false, false);
338  addRTEtoQuery(pstate, rte, false, true, true);
339 
340  /* Transform expression. Copy to be sure we don't modify original */
341  whenClause = transformWhereClause(pstate,
342  copyObject(stmt->whenClause),
344  "WHEN");
345  /* we have to fix its collations too */
346  assign_expr_collations(pstate, whenClause);
347 
348  /*
349  * Check for disallowed references to OLD/NEW.
350  *
351  * NB: pull_var_clause is okay here only because we don't allow
352  * subselects in WHEN clauses; it would fail to examine the contents
353  * of subselects.
354  */
355  varList = pull_var_clause(whenClause, 0);
356  foreach(lc, varList)
357  {
358  Var *var = (Var *) lfirst(lc);
359 
360  switch (var->varno)
361  {
362  case PRS2_OLD_VARNO:
363  if (!TRIGGER_FOR_ROW(tgtype))
364  ereport(ERROR,
365  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
366  errmsg("statement trigger's WHEN condition cannot reference column values"),
367  parser_errposition(pstate, var->location)));
368  if (TRIGGER_FOR_INSERT(tgtype))
369  ereport(ERROR,
370  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
371  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
372  parser_errposition(pstate, var->location)));
373  /* system columns are okay here */
374  break;
375  case PRS2_NEW_VARNO:
376  if (!TRIGGER_FOR_ROW(tgtype))
377  ereport(ERROR,
378  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
379  errmsg("statement trigger's WHEN condition cannot reference column values"),
380  parser_errposition(pstate, var->location)));
381  if (TRIGGER_FOR_DELETE(tgtype))
382  ereport(ERROR,
383  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
384  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
385  parser_errposition(pstate, var->location)));
386  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
387  ereport(ERROR,
388  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
389  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
390  parser_errposition(pstate, var->location)));
391  break;
392  default:
393  /* can't happen without add_missing_from, so just elog */
394  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
395  break;
396  }
397  }
398 
399  /* we'll need the rtable for recordDependencyOnExpr */
400  whenRtable = pstate->p_rtable;
401 
402  qual = nodeToString(whenClause);
403 
404  free_parsestate(pstate);
405  }
406  else
407  {
408  whenClause = NULL;
409  whenRtable = NIL;
410  qual = NULL;
411  }
412 
413  /*
414  * Find and validate the trigger function.
415  */
416  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
417  if (!isInternal)
418  {
419  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
420  if (aclresult != ACLCHECK_OK)
421  aclcheck_error(aclresult, ACL_KIND_PROC,
422  NameListToString(stmt->funcname));
423  }
424  funcrettype = get_func_rettype(funcoid);
425  if (funcrettype != TRIGGEROID)
426  {
427  /*
428  * We allow OPAQUE just so we can load old dump files. When we see a
429  * trigger function declared OPAQUE, change it to TRIGGER.
430  */
431  if (funcrettype == OPAQUEOID)
432  {
434  (errmsg("changing return type of function %s from \"opaque\" to \"trigger\"",
435  NameListToString(stmt->funcname))));
437  }
438  else
439  ereport(ERROR,
440  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
441  errmsg("function %s must return type %s",
442  NameListToString(stmt->funcname), "trigger")));
443  }
444 
445  /*
446  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
447  * references one of the built-in RI_FKey trigger functions, assume it is
448  * from a dump of a pre-7.3 foreign key constraint, and take steps to
449  * convert this legacy representation into a regular foreign key
450  * constraint. Ugly, but necessary for loading old dump files.
451  */
452  if (stmt->isconstraint && !isInternal &&
453  list_length(stmt->args) >= 6 &&
454  (list_length(stmt->args) % 2) == 0 &&
456  {
457  /* Keep lock on target rel until end of xact */
458  heap_close(rel, NoLock);
459 
460  ConvertTriggerToFK(stmt, funcoid);
461 
462  return InvalidObjectAddress;
463  }
464 
465  /*
466  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
467  * corresponding pg_constraint entry.
468  */
469  if (stmt->isconstraint && !OidIsValid(constraintOid))
470  {
471  /* Internal callers should have made their own constraints */
472  Assert(!isInternal);
473  constraintOid = CreateConstraintEntry(stmt->trigname,
476  stmt->deferrable,
477  stmt->initdeferred,
478  true,
479  RelationGetRelid(rel),
480  NULL, /* no conkey */
481  0,
482  InvalidOid, /* no domain */
483  InvalidOid, /* no index */
484  InvalidOid, /* no foreign key */
485  NULL,
486  NULL,
487  NULL,
488  NULL,
489  0,
490  ' ',
491  ' ',
492  ' ',
493  NULL, /* no exclusion */
494  NULL, /* no check constraint */
495  NULL,
496  NULL,
497  true, /* islocal */
498  0, /* inhcount */
499  true, /* isnoinherit */
500  isInternal); /* is_internal */
501  }
502 
503  /*
504  * Generate the trigger's OID now, so that we can use it in the name if
505  * needed.
506  */
508 
509  trigoid = GetNewOid(tgrel);
510 
511  /*
512  * If trigger is internally generated, modify the provided trigger name to
513  * ensure uniqueness by appending the trigger OID. (Callers will usually
514  * supply a simple constant trigger name in these cases.)
515  */
516  if (isInternal)
517  {
518  snprintf(internaltrigname, sizeof(internaltrigname),
519  "%s_%u", stmt->trigname, trigoid);
520  trigname = internaltrigname;
521  }
522  else
523  {
524  /* user-defined trigger; use the specified trigger name as-is */
525  trigname = stmt->trigname;
526  }
527 
528  /*
529  * Scan pg_trigger for existing triggers on relation. We do this only to
530  * give a nice error message if there's already a trigger of the same
531  * name. (The unique index on tgrelid/tgname would complain anyway.) We
532  * can skip this for internally generated triggers, since the name
533  * modification above should be sufficient.
534  *
535  * NOTE that this is cool only because we have ShareRowExclusiveLock on the
536  * relation, so the trigger set won't be changing underneath us.
537  */
538  if (!isInternal)
539  {
540  ScanKeyInit(&key,
542  BTEqualStrategyNumber, F_OIDEQ,
544  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
545  NULL, 1, &key);
546  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
547  {
548  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
549 
550  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
551  ereport(ERROR,
553  errmsg("trigger \"%s\" for relation \"%s\" already exists",
554  trigname, RelationGetRelationName(rel))));
555  }
556  systable_endscan(tgscan);
557  }
558 
559  /*
560  * Build the new pg_trigger tuple.
561  */
562  memset(nulls, false, sizeof(nulls));
563 
566  CStringGetDatum(trigname));
567  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
568  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
570  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
571  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
572  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
573  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
576 
577  if (stmt->args)
578  {
579  ListCell *le;
580  char *args;
581  int16 nargs = list_length(stmt->args);
582  int len = 0;
583 
584  foreach(le, stmt->args)
585  {
586  char *ar = strVal(lfirst(le));
587 
588  len += strlen(ar) + 4;
589  for (; *ar; ar++)
590  {
591  if (*ar == '\\')
592  len++;
593  }
594  }
595  args = (char *) palloc(len + 1);
596  args[0] = '\0';
597  foreach(le, stmt->args)
598  {
599  char *s = strVal(lfirst(le));
600  char *d = args + strlen(args);
601 
602  while (*s)
603  {
604  if (*s == '\\')
605  *d++ = '\\';
606  *d++ = *s++;
607  }
608  strcpy(d, "\\000");
609  }
610  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
612  CStringGetDatum(args));
613  }
614  else
615  {
616  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
618  CStringGetDatum(""));
619  }
620 
621  /* build column number array if it's a column-specific trigger */
622  ncolumns = list_length(stmt->columns);
623  if (ncolumns == 0)
624  columns = NULL;
625  else
626  {
627  ListCell *cell;
628  int i = 0;
629 
630  columns = (int16 *) palloc(ncolumns * sizeof(int16));
631  foreach(cell, stmt->columns)
632  {
633  char *name = strVal(lfirst(cell));
634  int16 attnum;
635  int j;
636 
637  /* Lookup column name. System columns are not allowed */
638  attnum = attnameAttNum(rel, name, false);
639  if (attnum == InvalidAttrNumber)
640  ereport(ERROR,
641  (errcode(ERRCODE_UNDEFINED_COLUMN),
642  errmsg("column \"%s\" of relation \"%s\" does not exist",
643  name, RelationGetRelationName(rel))));
644 
645  /* Check for duplicates */
646  for (j = i - 1; j >= 0; j--)
647  {
648  if (columns[j] == attnum)
649  ereport(ERROR,
650  (errcode(ERRCODE_DUPLICATE_COLUMN),
651  errmsg("column \"%s\" specified more than once",
652  name)));
653  }
654 
655  columns[i++] = attnum;
656  }
657  }
658  tgattr = buildint2vector(columns, ncolumns);
659  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
660 
661  /* set tgqual if trigger has WHEN clause */
662  if (qual)
663  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
664  else
665  nulls[Anum_pg_trigger_tgqual - 1] = true;
666 
667  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
668 
669  /* force tuple to have the desired OID */
670  HeapTupleSetOid(tuple, trigoid);
671 
672  /*
673  * Insert tuple into pg_trigger.
674  */
675  simple_heap_insert(tgrel, tuple);
676 
677  CatalogUpdateIndexes(tgrel, tuple);
678 
679  heap_freetuple(tuple);
681 
685 
686  /*
687  * Update relation's pg_class entry. Crucial side-effect: other backends
688  * (and this one too!) are sent SI message to make them rebuild relcache
689  * entries.
690  */
692  tuple = SearchSysCacheCopy1(RELOID,
694  if (!HeapTupleIsValid(tuple))
695  elog(ERROR, "cache lookup failed for relation %u",
696  RelationGetRelid(rel));
697 
698  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
699 
700  simple_heap_update(pgrel, &tuple->t_self, tuple);
701 
702  CatalogUpdateIndexes(pgrel, tuple);
703 
704  heap_freetuple(tuple);
706 
707  /*
708  * We used to try to update the rel's relcache entry here, but that's
709  * fairly pointless since it will happen as a byproduct of the upcoming
710  * CommandCounterIncrement...
711  */
712 
713  /*
714  * Record dependencies for trigger. Always place a normal dependency on
715  * the function.
716  */
717  myself.classId = TriggerRelationId;
718  myself.objectId = trigoid;
719  myself.objectSubId = 0;
720 
721  referenced.classId = ProcedureRelationId;
722  referenced.objectId = funcoid;
723  referenced.objectSubId = 0;
724  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
725 
726  if (isInternal && OidIsValid(constraintOid))
727  {
728  /*
729  * Internally-generated trigger for a constraint, so make it an
730  * internal dependency of the constraint. We can skip depending on
731  * the relation(s), as there'll be an indirect dependency via the
732  * constraint.
733  */
734  referenced.classId = ConstraintRelationId;
735  referenced.objectId = constraintOid;
736  referenced.objectSubId = 0;
737  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
738  }
739  else
740  {
741  /*
742  * User CREATE TRIGGER, so place dependencies. We make trigger be
743  * auto-dropped if its relation is dropped or if the FK relation is
744  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
745  */
746  referenced.classId = RelationRelationId;
747  referenced.objectId = RelationGetRelid(rel);
748  referenced.objectSubId = 0;
749  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
750  if (OidIsValid(constrrelid))
751  {
752  referenced.classId = RelationRelationId;
753  referenced.objectId = constrrelid;
754  referenced.objectSubId = 0;
755  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
756  }
757  /* Not possible to have an index dependency in this case */
758  Assert(!OidIsValid(indexOid));
759 
760  /*
761  * If it's a user-specified constraint trigger, make the constraint
762  * internally dependent on the trigger instead of vice versa.
763  */
764  if (OidIsValid(constraintOid))
765  {
766  referenced.classId = ConstraintRelationId;
767  referenced.objectId = constraintOid;
768  referenced.objectSubId = 0;
769  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
770  }
771  }
772 
773  /* If column-specific trigger, add normal dependencies on columns */
774  if (columns != NULL)
775  {
776  int i;
777 
778  referenced.classId = RelationRelationId;
779  referenced.objectId = RelationGetRelid(rel);
780  for (i = 0; i < ncolumns; i++)
781  {
782  referenced.objectSubId = columns[i];
783  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
784  }
785  }
786 
787  /*
788  * If it has a WHEN clause, add dependencies on objects mentioned in the
789  * expression (eg, functions, as well as any columns used).
790  */
791  if (whenClause != NULL)
792  recordDependencyOnExpr(&myself, whenClause, whenRtable,
794 
795  /* Post creation hook for new trigger */
797  isInternal);
798 
799  /* Keep lock on target rel until end of xact */
800  heap_close(rel, NoLock);
801 
802  return myself;
803 }
signed short int16
Definition: c.h:252
#define NIL
Definition: pg_list.h:69
#define Anum_pg_trigger_tgdeferrable
Definition: pg_trigger.h:86
#define TRIGGER_FOR_DELETE(type)
Definition: pg_trigger.h:131
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3706
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:631
bool IsSystemRelation(Relation relation)
Definition: catalog.c:61
Oid GetUserId(void)
Definition: miscinit.c:282
#define PointerGetDatum(X)
Definition: postgres.h:564
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:85
#define ProcedureRelationId
Definition: pg_proc.h:33
Node * whenClause
Definition: parsenodes.h:2103
#define RelationRelationId
Definition: pg_class.h:29
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:112
#define Anum_pg_trigger_tgqual
Definition: pg_trigger.h:91
#define TRIGGER_CLEAR_TYPE(type)
Definition: pg_trigger.h:114
#define Int16GetDatum(X)
Definition: postgres.h:459
#define Anum_pg_trigger_tgtype
Definition: pg_trigger.h:80
#define AccessShareLock
Definition: lockdefs.h:36
#define Anum_pg_trigger_tgnargs
Definition: pg_trigger.h:88
Definition: nodes.h:491
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
int namestrcmp(Name name, const char *str)
Definition: name.c:248
AttrNumber varattno
Definition: primnodes.h:153
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:548
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:148
#define Anum_pg_trigger_tgisinternal
Definition: pg_trigger.h:82
#define OidIsValid(objectId)
Definition: c.h:530
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:107
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1427
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4262
#define TriggerRelidNameIndexId
Definition: indexing.h:233
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:673
#define NAMEDATALEN
void assign_expr_collations(ParseState *pstate, Node *expr)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:384
RangeVar * constrrel
Definition: parsenodes.h:2108
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:100
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define TRIGGER_FOR_ROW(type)
Definition: pg_trigger.h:126
void pfree(void *pointer)
Definition: mcxt.c:995
#define OPAQUEOID
Definition: pg_type.h:688
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:108
#define TRIGGEROID
Definition: pg_type.h:680
ItemPointerData t_self
Definition: htup.h:65
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:256
#define ACL_TRIGGER
Definition: parsenodes.h:69
int location
Definition: primnodes.h:163
#define NoLock
Definition: lockdefs.h:34
#define TRIGGER_SETT_ROW(type)
Definition: pg_trigger.h:116
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3391
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define CStringGetDatum(X)
Definition: postgres.h:586
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1352
#define RelationGetRelationName(relation)
Definition: rel.h:361
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:161
const char * p_sourcetext
Definition: parse_node.h:134
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:127
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:833
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
#define PRS2_OLD_VARNO
Definition: primnodes.h:145
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:77
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:151
char * NameListToString(List *names)
Definition: namespace.c:2912
Definition: c.h:462
#define Anum_pg_trigger_tgconstrindid
Definition: pg_trigger.h:84
AclResult
Definition: acl.h:169
uintptr_t Datum
Definition: postgres.h:374
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2926
#define Anum_pg_trigger_tgenabled
Definition: pg_trigger.h:81
Oid GetNewOid(Relation relation)
Definition: catalog.c:284
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1298
void SetFunctionReturnType(Oid funcOid, Oid newRetType)
#define TRIGGER_FOR_TRUNCATE(type)
Definition: pg_trigger.h:133
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
TupleDesc rd_att
Definition: rel.h:84
#define BoolGetDatum(X)
Definition: postgres.h:410
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1326
bool allowSystemTableMods
Definition: globals.c:109
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define lfirst(lc)
Definition: pg_list.h:106
#define Anum_pg_trigger_tgargs
Definition: pg_trigger.h:90
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
Definition: indexing.c:157
#define Anum_pg_trigger_tgconstrrelid
Definition: pg_trigger.h:83
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:78
#define TriggerRelationId
Definition: pg_trigger.h:34
#define TRIGGER_FOR_INSERT(type)
Definition: pg_trigger.h:130
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:108
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4422
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:70
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
#define CharGetDatum(X)
Definition: postgres.h:424
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4405
#define DatumGetPointer(X)
Definition: postgres.h:557
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:95
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1902
static Datum values[MAXATTR]
Definition: bootstrap.c:160
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:150
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:894
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:70
#define RELKIND_VIEW
Definition: pg_class.h:159
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4429
int i
RangeVar * relation
Definition: parsenodes.h:2094
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:806
char * nodeToString(const void *obj)
Definition: outfuncs.c:3819
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:218
#define CONSTRAINT_TRIGGER
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:74
#define RELKIND_RELATION
Definition: pg_class.h:155
#define RI_TRIGGER_NONE
Definition: trigger.h:209
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:34
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
#define RelationGetRelid(relation)
Definition: rel.h:341
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
#define PRS2_NEW_VARNO
Definition: primnodes.h:146
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define Anum_pg_trigger_tgfoid
Definition: pg_trigger.h:79
#define Anum_pg_trigger_tginitdeferred
Definition: pg_trigger.h:87
#define Anum_pg_trigger_tgattr
Definition: pg_trigger.h:89
#define Natts_pg_trigger
Definition: pg_trigger.h:76
#define TRIGGER_FOR_INSTEAD(type)
Definition: pg_trigger.h:129
#define RelationGetNamespace(relation)
Definition: rel.h:368
List * p_rtable
Definition: parse_node.h:135
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

Definition at line 1388 of file trigger.c.

References Anum_pg_trigger_tgname, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogUpdateIndexes(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_copytuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NameStr, NULL, ObjectIdGetDatum, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), simple_heap_update(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TriggerRelationId, and TriggerRelidNameIndexId.

Referenced by ATExecEnableDisableTrigger().

1390 {
1391  Relation tgrel;
1392  int nkeys;
1393  ScanKeyData keys[2];
1394  SysScanDesc tgscan;
1395  HeapTuple tuple;
1396  bool found;
1397  bool changed;
1398 
1399  /* Scan the relevant entries in pg_triggers */
1401 
1402  ScanKeyInit(&keys[0],
1404  BTEqualStrategyNumber, F_OIDEQ,
1406  if (tgname)
1407  {
1408  ScanKeyInit(&keys[1],
1410  BTEqualStrategyNumber, F_NAMEEQ,
1411  CStringGetDatum(tgname));
1412  nkeys = 2;
1413  }
1414  else
1415  nkeys = 1;
1416 
1417  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1418  NULL, nkeys, keys);
1419 
1420  found = changed = false;
1421 
1422  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1423  {
1424  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1425 
1426  if (oldtrig->tgisinternal)
1427  {
1428  /* system trigger ... ok to process? */
1429  if (skip_system)
1430  continue;
1431  if (!superuser())
1432  ereport(ERROR,
1433  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1434  errmsg("permission denied: \"%s\" is a system trigger",
1435  NameStr(oldtrig->tgname))));
1436  }
1437 
1438  found = true;
1439 
1440  if (oldtrig->tgenabled != fires_when)
1441  {
1442  /* need to change this one ... make a copy to scribble on */
1443  HeapTuple newtup = heap_copytuple(tuple);
1444  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1445 
1446  newtrig->tgenabled = fires_when;
1447 
1448  simple_heap_update(tgrel, &newtup->t_self, newtup);
1449 
1450  /* Keep catalog indexes current */
1451  CatalogUpdateIndexes(tgrel, newtup);
1452 
1453  heap_freetuple(newtup);
1454 
1455  changed = true;
1456  }
1457 
1459  HeapTupleGetOid(tuple), 0);
1460  }
1461 
1462  systable_endscan(tgscan);
1463 
1464  heap_close(tgrel, RowExclusiveLock);
1465 
1466  if (tgname && !found)
1467  ereport(ERROR,
1468  (errcode(ERRCODE_UNDEFINED_OBJECT),
1469  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1470  tgname, RelationGetRelationName(rel))));
1471 
1472  /*
1473  * If we changed anything, broadcast a SI inval message to force each
1474  * backend (including our own!) to rebuild relation's relcache entry.
1475  * Otherwise they will fail to apply the change promptly.
1476  */
1477  if (changed)
1479 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:631
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
#define TriggerRelidNameIndexId
Definition: indexing.h:233
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:586
#define RelationGetRelationName(relation)
Definition: rel.h:361
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:77
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1298
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
Definition: indexing.c:157
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:78
#define TriggerRelationId
Definition: pg_trigger.h:34
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4422
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:70
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1213
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:494
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:670
#define RelationGetRelid(relation)
Definition: rel.h:341
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2270 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), heap_freetuple(), HeapTupleIsValid, ItemPointerIsValid, LockTupleExclusive, NIL, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_delete_after_row, and TRIGGER_EVENT_DELETE.

Referenced by ExecDelete().

2273 {
2274  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2275 
2276  if (trigdesc && trigdesc->trig_delete_after_row)
2277  {
2278  HeapTuple trigtuple;
2279 
2280  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2281  if (fdw_trigtuple == NULL)
2282  trigtuple = GetTupleForTrigger(estate,
2283  NULL,
2284  relinfo,
2285  tupleid,
2287  NULL);
2288  else
2289  trigtuple = fdw_trigtuple;
2290 
2292  true, trigtuple, NULL, NIL, NULL);
2293  if (trigtuple != fdw_trigtuple)
2294  heap_freetuple(trigtuple);
2295  }
2296 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:51
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
bool trig_delete_after_row
Definition: reltrigger.h:64
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2680
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

Definition at line 2068 of file trigger.c.

References AfterTriggerSaveEvent(), NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_insert_after_row, and TRIGGER_EVENT_INSERT.

Referenced by CopyFrom(), CopyFromInsertBatch(), and ExecInsert().

2070 {
2071  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2072 
2073  if (trigdesc && trigdesc->trig_insert_after_row)
2075  true, NULL, trigtuple, recheckIndexes, NULL);
2076 }
bool trig_insert_after_row
Definition: reltrigger.h:54
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define NULL
Definition: c.h:226
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:50
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes 
)

Definition at line 2523 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), HeapTupleIsValid, ItemPointerIsValid, LockTupleExclusive, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_update_after_row, and TRIGGER_EVENT_UPDATE.

Referenced by ExecUpdate().

2528 {
2529  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2530 
2531  if (trigdesc && trigdesc->trig_update_after_row)
2532  {
2533  HeapTuple trigtuple;
2534 
2535  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2536  if (fdw_trigtuple == NULL)
2537  trigtuple = GetTupleForTrigger(estate,
2538  NULL,
2539  relinfo,
2540  tupleid,
2542  NULL);
2543  else
2544  trigtuple = fdw_trigtuple;
2545 
2547  true, trigtuple, newtuple, recheckIndexes,
2548  GetUpdatedColumns(relinfo, estate));
2549  if (trigtuple != fdw_trigtuple)
2550  heap_freetuple(trigtuple);
2551  }
2552 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
bool trig_update_after_row
Definition: reltrigger.h:59
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:52
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2680
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2193 of file trigger.c.

References AfterTriggerSaveEvent(), NIL, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_delete_after_statement, and TRIGGER_EVENT_DELETE.

Referenced by fireASTriggers().

2194 {
2195  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2196 
2197  if (trigdesc && trigdesc->trig_delete_after_statement)
2199  false, NULL, NULL, NIL, NULL);
2200 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:51
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define NULL
Definition: c.h:226
bool trig_delete_after_statement
Definition: reltrigger.h:67
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 1994 of file trigger.c.

References AfterTriggerSaveEvent(), NIL, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_insert_after_statement, and TRIGGER_EVENT_INSERT.

Referenced by CopyFrom(), and fireASTriggers().

1995 {
1996  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1997 
1998  if (trigdesc && trigdesc->trig_insert_after_statement)
2000  false, NULL, NULL, NIL, NULL);
2001 }
#define NIL
Definition: pg_list.h:69
bool trig_insert_after_statement
Definition: reltrigger.h:57
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define NULL
Definition: c.h:226
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:50
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2669 of file trigger.c.

References AfterTriggerSaveEvent(), NIL, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_truncate_after_statement, and TRIGGER_EVENT_TRUNCATE.

Referenced by ExecuteTruncate().

2670 {
2671  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2672 
2673  if (trigdesc && trigdesc->trig_truncate_after_statement)
2675  false, NULL, NULL, NIL, NULL);
2676 }
#define NIL
Definition: pg_list.h:69
bool trig_truncate_after_statement
Definition: reltrigger.h:70
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define NULL
Definition: c.h:226
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:53
void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2397 of file trigger.c.

References AfterTriggerSaveEvent(), GetUpdatedColumns, NIL, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_update_after_statement, and TRIGGER_EVENT_UPDATE.

Referenced by fireASTriggers().

2398 {
2399  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2400 
2401  if (trigdesc && trigdesc->trig_update_after_statement)
2403  false, NULL, NULL, NIL,
2404  GetUpdatedColumns(relinfo, estate));
2405 }
#define NIL
Definition: pg_list.h:69
bool trig_update_after_statement
Definition: reltrigger.h:62
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4811
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#define NULL
Definition: c.h:226
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:52
bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2203 of file trigger.c.

References Assert, ExecCallTriggerFunc(), GetPerTupleMemoryContext, GetTupleForTrigger(), heap_freetuple(), HeapTupleIsValid, i, InvalidBuffer, ItemPointerIsValid, LockTupleExclusive, NULL, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_DELETE, TRIGGER_EVENT_ROW, TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE, TRIGGER_TYPE_MATCHES, TRIGGER_TYPE_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecDelete().

2207 {
2208  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2209  bool result = true;
2210  TriggerData LocTriggerData;
2211  HeapTuple trigtuple;
2212  HeapTuple newtuple;
2213  TupleTableSlot *newSlot;
2214  int i;
2215 
2216  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2217  if (fdw_trigtuple == NULL)
2218  {
2219  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2220  LockTupleExclusive, &newSlot);
2221  if (trigtuple == NULL)
2222  return false;
2223  }
2224  else
2225  trigtuple = fdw_trigtuple;
2226 
2227  LocTriggerData.type = T_TriggerData;
2228  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2231  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2232  LocTriggerData.tg_newtuple = NULL;
2233  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2234  for (i = 0; i < trigdesc->numtriggers; i++)
2235  {
2236  Trigger *trigger = &trigdesc->triggers[i];
2237 
2238  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2242  continue;
2243  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2244  NULL, trigtuple, NULL))
2245  continue;
2246 
2247  LocTriggerData.tg_trigtuple = trigtuple;
2248  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2249  LocTriggerData.tg_trigger = trigger;
2250  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2251  i,
2252  relinfo->ri_TrigFunctions,
2253  relinfo->ri_TrigInstrument,
2254  GetPerTupleMemoryContext(estate));
2255  if (newtuple == NULL)
2256  {
2257  result = false; /* tell caller to suppress delete */
2258  break;
2259  }
2260  if (newtuple != trigtuple)
2261  heap_freetuple(newtuple);
2262  }
2263  if (trigtuple != fdw_trigtuple)
2264  heap_freetuple(trigtuple);
2265 
2266  return result;
2267 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
Relation ri_RelationDesc
Definition: execnodes.h:328
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:97
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:51
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:142
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:335
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:58
Trigger * triggers
Definition: reltrigger.h:46
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:94
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
int numtriggers
Definition: reltrigger.h:47
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:2824
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:327
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:95
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2680
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:1862
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:333
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecBRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

Definition at line 2004 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, NULL, TriggerDesc::numtriggers, RelationGetDescr, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_ROW, TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT, TRIGGER_TYPE_MATCHES, TRIGGER_TYPE_ROW, TriggerEnabled(), TriggerDesc::triggers, TupleTableSlot::tts_tupleDescriptor, and TriggerData::type.

Referenced by CopyFrom(), and ExecInsert().

2006 {
2007  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2008  HeapTuple slottuple = ExecMaterializeSlot(slot);
2009  HeapTuple newtuple = slottuple;
2010  HeapTuple oldtuple;
2011  TriggerData LocTriggerData;
2012  int i;
2013 
2014  LocTriggerData.type = T_TriggerData;
2015  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2018  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2019  LocTriggerData.tg_newtuple = NULL;
2020  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2021  for (i = 0; i < trigdesc->numtriggers; i++)
2022  {
2023  Trigger *trigger = &trigdesc->triggers[i];
2024 
2025  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2029  continue;
2030  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2031  NULL, NULL, newtuple))
2032  continue;
2033 
2034  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2035  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2036  LocTriggerData.tg_trigger = trigger;
2037  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2038  i,
2039  relinfo->ri_TrigFunctions,
2040  relinfo->ri_TrigInstrument,
2041  GetPerTupleMemoryContext(estate));
2042  if (oldtuple != newtuple && oldtuple != slottuple)
2043  heap_freetuple(oldtuple);
2044  if (newtuple == NULL)
2045  return NULL; /* "do nothing" */
2046  }
2047 
2048  if (newtuple != slottuple)
2049  {
2050  /*
2051  * Return the modified tuple using the es_trig_tuple_slot. We assume
2052  * the tuple was allocated in per-tuple memory context, and therefore
2053  * will go away by itself. The tuple table slot should not try to
2054  * clear it.
2055  */
2056  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2057  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2058 
2059  if (newslot->tts_tupleDescriptor != tupdesc)
2060  ExecSetSlotDescriptor(newslot, tupdesc);
2061  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2062  slot = newslot;
2063  }
2064  return slot;
2065 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:324
Relation ri_RelationDesc
Definition: execnodes.h:328
#define RelationGetDescr(relation)
Definition: rel.h:353
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:142
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:335
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1306
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:58
Trigger * triggers
Definition: reltrigger.h:46
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:94
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:377
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:332
int numtriggers
Definition: reltrigger.h:47
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:251
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:2824
#define NULL
Definition: c.h:226