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_SIZES, 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",
3343 
3344  /*
3345  * Chunk size starts at 1KB and is allowed to increase up to 1MB.
3346  * These numbers are fairly arbitrary, though there is a hard limit at
3347  * AFTER_TRIGGER_OFFSET; else we couldn't link event records to their
3348  * shared records using the available space in ate_flags. Another
3349  * constraint is that if the chunk size gets too huge, the search loop
3350  * below would get slow given a (not too common) usage pattern with
3351  * many distinct event types in a chunk. Therefore, we double the
3352  * preceding chunk size only if there weren't too many shared records
3353  * in the preceding chunk; otherwise we halve it. This gives us some
3354  * ability to adapt to the actual usage pattern of the current query
3355  * while still having large chunk sizes in typical usage. All chunk
3356  * sizes used should be MAXALIGN multiples, to ensure that the shared
3357  * records will be aligned safely.
3358  */
3359 #define MIN_CHUNK_SIZE 1024
3360 #define MAX_CHUNK_SIZE (1024*1024)
3361 
3362 #if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
3363 #error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
3364 #endif
3365 
3366  if (chunk == NULL)
3367  chunksize = MIN_CHUNK_SIZE;
3368  else
3369  {
3370  /* preceding chunk size... */
3371  chunksize = chunk->endptr - (char *) chunk;
3372  /* check number of shared records in preceding chunk */
3373  if ((chunk->endptr - chunk->endfree) <=
3374  (100 * sizeof(AfterTriggerSharedData)))
3375  chunksize *= 2; /* okay, double it */
3376  else
3377  chunksize /= 2; /* too many shared records */
3378  chunksize = Min(chunksize, MAX_CHUNK_SIZE);
3379  }
3380  chunk = MemoryContextAlloc(afterTriggers.event_cxt, chunksize);
3381  chunk->next = NULL;
3382  chunk->freeptr = CHUNK_DATA_START(chunk);
3383  chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
3384  Assert(chunk->endfree - chunk->freeptr >= needed);
3385 
3386  if (events->head == NULL)
3387  events->head = chunk;
3388  else
3389  events->tail->next = chunk;
3390  events->tail = chunk;
3391  /* events->tailfree is now out of sync, but we'll fix it below */
3392  }
3393 
3394  /*
3395  * Try to locate a matching shared-data record already in the chunk. If
3396  * none, make a new one.
3397  */
3398  for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
3399  (char *) newshared >= chunk->endfree;
3400  newshared--)
3401  {
3402  if (newshared->ats_tgoid == evtshared->ats_tgoid &&
3403  newshared->ats_relid == evtshared->ats_relid &&
3404  newshared->ats_event == evtshared->ats_event &&
3405  newshared->ats_firing_id == 0)
3406  break;
3407  }
3408  if ((char *) newshared < chunk->endfree)
3409  {
3410  *newshared = *evtshared;
3411  newshared->ats_firing_id = 0; /* just to be sure */
3412  chunk->endfree = (char *) newshared;
3413  }
3414 
3415  /* Insert the data */
3416  newevent = (AfterTriggerEvent) chunk->freeptr;
3417  memcpy(newevent, event, eventsize);
3418  /* ... and link the new event to its shared record */
3419  newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
3420  newevent->ate_flags |= (char *) newshared - (char *) newevent;
3421 
3422  chunk->freeptr += eventsize;
3423  events->tailfree = chunk->freeptr;
3424 }
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
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
#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:440
#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:749
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginQuery ( void  )

Definition at line 3935 of file trigger.c.

References AfterTriggersData::query_depth.

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

3936 {
3937  /* Increase the query stack depth */
3939 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginSubXact ( void  )

Definition at line 4143 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().

4144 {
4145  int my_level = GetCurrentTransactionNestLevel();
4146 
4147  /*
4148  * Allocate more space in the stacks if needed. (Note: because the
4149  * minimum nest level of a subtransaction is 2, we waste the first couple
4150  * entries of each array; not worth the notational effort to avoid it.)
4151  */
4152  while (my_level >= afterTriggers.maxtransdepth)
4153  {
4154  if (afterTriggers.maxtransdepth == 0)
4155  {
4156  MemoryContext old_cxt;
4157 
4159 
4160 #define DEFTRIG_INITALLOC 8
4165  afterTriggers.depth_stack = (int *)
4166  palloc(DEFTRIG_INITALLOC * sizeof(int));
4168  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4170 
4171  MemoryContextSwitchTo(old_cxt);
4172  }
4173  else
4174  {
4175  /* repalloc will keep the stacks in the same context */
4176  int new_alloc = afterTriggers.maxtransdepth * 2;
4177 
4180  new_alloc * sizeof(SetConstraintState));
4183  new_alloc * sizeof(AfterTriggerEventList));
4184  afterTriggers.depth_stack = (int *)
4186  new_alloc * sizeof(int));
4189  new_alloc * sizeof(CommandId));
4190  afterTriggers.maxtransdepth = new_alloc;
4191  }
4192  }
4193 
4194  /*
4195  * Push the current information into the stack. The SET CONSTRAINTS state
4196  * is not saved until/unless changed. Likewise, we don't make a
4197  * per-subtransaction event context until needed.
4198  */
4199  afterTriggers.state_stack[my_level] = NULL;
4203 }
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:1021
void * palloc(Size size)
Definition: mcxt.c:891
AfterTriggerEventList events
Definition: trigger.c:3193
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerBeginXact ( void  )

Definition at line 3899 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().

3900 {
3901  /*
3902  * Initialize after-trigger state structure to empty
3903  */
3904  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
3906 
3907  /*
3908  * Verify that there is no leftover state remaining. If these assertions
3909  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
3910  * up properly.
3911  */
3923 }
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:312
int i
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
void AfterTriggerEndQuery ( EState estate)

Definition at line 3955 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().

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

4212 {
4213  int my_level = GetCurrentTransactionNestLevel();
4215  AfterTriggerEvent event;
4216  AfterTriggerEventChunk *chunk;
4217  CommandId subxact_firing_id;
4218 
4219  /*
4220  * Pop the prior state if needed.
4221  */
4222  if (isCommit)
4223  {
4224  Assert(my_level < afterTriggers.maxtransdepth);
4225  /* If we saved a prior state, we don't need it anymore */
4226  state = afterTriggers.state_stack[my_level];
4227  if (state != NULL)
4228  pfree(state);
4229  /* this avoids double pfree if error later: */
4230  afterTriggers.state_stack[my_level] = NULL;
4232  afterTriggers.depth_stack[my_level]);
4233  }
4234  else
4235  {
4236  /*
4237  * Aborting. It is possible subxact start failed before calling
4238  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4239  * stack levels that aren't there.
4240  */
4241  if (my_level >= afterTriggers.maxtransdepth)
4242  return;
4243 
4244  /*
4245  * Release any event lists from queries being aborted, and restore
4246  * query_depth to its pre-subxact value. This assumes that a
4247  * subtransaction will not add events to query levels started in a
4248  * earlier transaction state.
4249  */
4251  {
4253  {
4254  Tuplestorestate *ts;
4255 
4257  if (ts)
4258  {
4259  tuplestore_end(ts);
4261  }
4262 
4264  }
4265 
4267  }
4269  afterTriggers.depth_stack[my_level]);
4270 
4271  /*
4272  * Restore the global deferred-event list to its former length,
4273  * discarding any events queued by the subxact.
4274  */
4276  &afterTriggers.events_stack[my_level]);
4277 
4278  /*
4279  * Restore the trigger state. If the saved state is NULL, then this
4280  * subxact didn't save it, so it doesn't need restoring.
4281  */
4282  state = afterTriggers.state_stack[my_level];
4283  if (state != NULL)
4284  {
4286  afterTriggers.state = state;
4287  }
4288  /* this avoids double pfree if error later: */
4289  afterTriggers.state_stack[my_level] = NULL;
4290 
4291  /*
4292  * Scan for any remaining deferred events that were marked DONE or IN
4293  * PROGRESS by this subxact or a child, and un-mark them. We can
4294  * recognize such events because they have a firing ID greater than or
4295  * equal to the firing_counter value we saved at subtransaction start.
4296  * (This essentially assumes that the current subxact includes all
4297  * subxacts started after it.)
4298  */
4299  subxact_firing_id = afterTriggers.firing_stack[my_level];
4301  {
4302  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4303 
4304  if (event->ate_flags &
4306  {
4307  if (evtshared->ats_firing_id >= subxact_firing_id)
4308  event->ate_flags &=
4310  }
4311  }
4312  }
4313 }
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:992
SetConstraintState * state_stack
Definition: trigger.c:3202
SetConstraintState state
Definition: trigger.c:3192
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3433
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:312
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:450
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3456
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 4091 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().

4092 {
4093  /*
4094  * Forget the pending-events list.
4095  *
4096  * Since all the info is in TopTransactionContext or children thereof, we
4097  * don't really need to do anything to reclaim memory. However, the
4098  * pending-events list could be large, and so it's useful to discard it as
4099  * soon as possible --- especially if we are aborting because we ran out
4100  * of memory for the list!
4101  */
4103  {
4109  }
4110 
4111  /*
4112  * Forget any subtransaction state as well. Since this can't be very
4113  * large, we let the eventual reset of TopTransactionContext free the
4114  * memory instead of doing it here.
4115  */
4121 
4122 
4123  /*
4124  * Forget the query stack and constraint-related state information. As
4125  * with the subtransaction state information, we don't bother freeing the
4126  * memory here.
4127  */
4132 
4133  /* No more afterTriggers manipulation until next transaction starts. */
4135 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
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 4325 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().

4326 {
4327  int init_depth = afterTriggers.maxquerydepth;
4328 
4330 
4331  if (afterTriggers.maxquerydepth == 0)
4332  {
4333  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4334 
4337  new_alloc * sizeof(AfterTriggerEventList));
4340  new_alloc * sizeof(Tuplestorestate *));
4341  afterTriggers.maxquerydepth = new_alloc;
4342  }
4343  else
4344  {
4345  /* repalloc will keep the stack in the same context */
4346  int old_alloc = afterTriggers.maxquerydepth;
4347  int new_alloc = Max(afterTriggers.query_depth + 1,
4348  old_alloc * 2);
4349 
4352  new_alloc * sizeof(AfterTriggerEventList));
4355  new_alloc * sizeof(Tuplestorestate *));
4356  /* Clear newly-allocated slots for subsequent lazy initialization. */
4357  memset(afterTriggers.fdw_tuplestores + old_alloc,
4358  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4359  afterTriggers.maxquerydepth = new_alloc;
4360  }
4361 
4362  /* Initialize new query lists to empty */
4363  while (init_depth < afterTriggers.maxquerydepth)
4364  {
4365  AfterTriggerEventList *events;
4366 
4367  events = &afterTriggers.query_stack[init_depth];
4368  events->head = NULL;
4369  events->tail = NULL;
4370  events->tailfree = NULL;
4371 
4372  ++init_depth;
4373  }
4374 }
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:784
#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:1021
AfterTriggerEventChunk * head
Definition: trigger.c:3116
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
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 3511 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().

3517 {
3518  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3519  Oid tgoid = evtshared->ats_tgoid;
3520  TriggerData LocTriggerData;
3521  HeapTupleData tuple1;
3522  HeapTupleData tuple2;
3523  HeapTuple rettuple;
3524  Buffer buffer1 = InvalidBuffer;
3525  Buffer buffer2 = InvalidBuffer;
3526  int tgindx;
3527 
3528  /*
3529  * Locate trigger in trigdesc.
3530  */
3531  LocTriggerData.tg_trigger = NULL;
3532  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3533  {
3534  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3535  {
3536  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3537  break;
3538  }
3539  }
3540  if (LocTriggerData.tg_trigger == NULL)
3541  elog(ERROR, "could not find trigger %u", tgoid);
3542 
3543  /*
3544  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3545  * to include time spent re-fetching tuples in the trigger cost.
3546  */
3547  if (instr)
3548  InstrStartNode(instr + tgindx);
3549 
3550  /*
3551  * Fetch the required tuple(s).
3552  */
3553  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3554  {
3556  {
3557  Tuplestorestate *fdw_tuplestore = GetCurrentFDWTuplestore();
3558 
3559  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3560  trig_tuple_slot1))
3561  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3562 
3563  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3565  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3566  trig_tuple_slot2))
3567  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3568  }
3569  /* fall through */
3571 
3572  /*
3573  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3574  * ensures that tg_trigtuple does not reference tuplestore memory.
3575  * (It is formally possible for the trigger function to queue
3576  * trigger events that add to the same tuplestore, which can push
3577  * other tuples out of memory.) The distinction is academic,
3578  * because we start with a minimal tuple that ExecFetchSlotTuple()
3579  * must materialize anyway.
3580  */
3581  LocTriggerData.tg_trigtuple =
3582  ExecMaterializeSlot(trig_tuple_slot1);
3583  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3584 
3585  LocTriggerData.tg_newtuple =
3586  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3588  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3589  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3590 
3591  break;
3592 
3593  default:
3594  if (ItemPointerIsValid(&(event->ate_ctid1)))
3595  {
3596  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3597  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3598  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3599  LocTriggerData.tg_trigtuple = &tuple1;
3600  LocTriggerData.tg_trigtuplebuf = buffer1;
3601  }
3602  else
3603  {
3604  LocTriggerData.tg_trigtuple = NULL;
3605  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3606  }
3607 
3608  /* don't touch ctid2 if not there */
3609  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3611  ItemPointerIsValid(&(event->ate_ctid2)))
3612  {
3613  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3614  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3615  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3616  LocTriggerData.tg_newtuple = &tuple2;
3617  LocTriggerData.tg_newtuplebuf = buffer2;
3618  }
3619  else
3620  {
3621  LocTriggerData.tg_newtuple = NULL;
3622  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3623  }
3624  }
3625 
3626  /*
3627  * Setup the remaining trigger information
3628  */
3629  LocTriggerData.type = T_TriggerData;
3630  LocTriggerData.tg_event =
3632  LocTriggerData.tg_relation = rel;
3633 
3634  MemoryContextReset(per_tuple_context);
3635 
3636  /*
3637  * Call the trigger and throw away any possibly returned updated tuple.
3638  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3639  */
3640  rettuple = ExecCallTriggerFunc(&LocTriggerData,
3641  tgindx,
3642  finfo,
3643  NULL,
3644  per_tuple_context);
3645  if (rettuple != NULL &&
3646  rettuple != LocTriggerData.tg_trigtuple &&
3647  rettuple != LocTriggerData.tg_newtuple)
3648  heap_freetuple(rettuple);
3649 
3650  /*
3651  * Release buffers
3652  */
3653  if (buffer1 != InvalidBuffer)
3654  ReleaseBuffer(buffer1);
3655  if (buffer2 != InvalidBuffer)
3656  ReleaseBuffer(buffer2);
3657 
3658  /*
3659  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3660  * one "tuple returned" (really the number of firings).
3661  */
3662  if (instr)
3663  InstrStopNode(instr + tgindx, 1);
3664 }
#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:1848
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:135
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:728
#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 4035 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().

4036 {
4037  AfterTriggerEventList *events;
4038  bool snap_pushed = false;
4039 
4040  /* Must not be inside a query */
4042 
4043  /*
4044  * If there are any triggers to fire, make sure we have set a snapshot for
4045  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4046  * can't assume ActiveSnapshot is valid on entry.)
4047  */
4048  events = &afterTriggers.events;
4049  if (events->head != NULL)
4050  {
4052  snap_pushed = true;
4053  }
4054 
4055  /*
4056  * Run all the remaining triggers. Loop until they are all gone, in case
4057  * some trigger queues more for us to do.
4058  */
4059  while (afterTriggerMarkEvents(events, NULL, false))
4060  {
4061  CommandId firing_id = afterTriggers.firing_counter++;
4062 
4063  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4064  break; /* all fired */
4065  }
4066 
4067  /*
4068  * We don't bother freeing the event list, since it will go away anyway
4069  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4070  */
4071 
4072  if (snap_pushed)
4074 }
uint32 CommandId
Definition: c.h:407
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3754
void PopActiveSnapshot(void)
Definition: snapmgr.c:766
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:302
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:687
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:3682
AfterTriggerEventList events
Definition: trigger.c:3193
static AfterTriggersData afterTriggers
Definition: trigger.c:3209
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3433 of file trigger.c.

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

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

3434 {
3435  AfterTriggerEventChunk *chunk;
3436  AfterTriggerEventChunk *next_chunk;
3437 
3438  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3439  {
3440  next_chunk = chunk->next;
3441  pfree(chunk);
3442  }
3443  events->head = NULL;
3444  events->tail = NULL;
3445  events->tailfree = NULL;
3446 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
void pfree(void *pointer)
Definition: mcxt.c:992
#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 3754 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, AfterTriggerExecute(), ALLOCSET_DEFAULT_SIZES, 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().

3758 {
3759  bool all_fired = true;
3760  AfterTriggerEventChunk *chunk;
3761  MemoryContext per_tuple_context;
3762  bool local_estate = false;
3763  Relation rel = NULL;
3764  TriggerDesc *trigdesc = NULL;
3765  FmgrInfo *finfo = NULL;
3766  Instrumentation *instr = NULL;
3767  TupleTableSlot *slot1 = NULL,
3768  *slot2 = NULL;
3769 
3770  /* Make a local EState if need be */
3771  if (estate == NULL)
3772  {
3773  estate = CreateExecutorState();
3774  local_estate = true;
3775  }
3776 
3777  /* Make a per-tuple memory context for trigger function calls */
3778  per_tuple_context =
3780  "AfterTriggerTupleContext",
3782 
3783  for_each_chunk(chunk, *events)
3784  {
3785  AfterTriggerEvent event;
3786  bool all_fired_in_chunk = true;
3787 
3788  for_each_event(event, chunk)
3789  {
3790  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3791 
3792  /*
3793  * Is it one for me to fire?
3794  */
3795  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
3796  evtshared->ats_firing_id == firing_id)
3797  {
3798  /*
3799  * So let's fire it... but first, find the correct relation if
3800  * this is not the same relation as before.
3801  */
3802  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
3803  {
3804  ResultRelInfo *rInfo;
3805 
3806  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
3807  rel = rInfo->ri_RelationDesc;
3808  trigdesc = rInfo->ri_TrigDesc;
3809  finfo = rInfo->ri_TrigFunctions;
3810  instr = rInfo->ri_TrigInstrument;
3811  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
3812  {
3813  if (slot1 != NULL)
3814  {
3817  }
3818  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
3819  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
3820  }
3821  if (trigdesc == NULL) /* should not happen */
3822  elog(ERROR, "relation %u has no triggers",
3823  evtshared->ats_relid);
3824  }
3825 
3826  /*
3827  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
3828  * still set, so recursive examinations of the event list
3829  * won't try to re-fire it.
3830  */
3831  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
3832  per_tuple_context, slot1, slot2);
3833 
3834  /*
3835  * Mark the event as done.
3836  */
3837  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
3838  event->ate_flags |= AFTER_TRIGGER_DONE;
3839  }
3840  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
3841  {
3842  /* something remains to be done */
3843  all_fired = all_fired_in_chunk = false;
3844  }
3845  }
3846 
3847  /* Clear the chunk if delete_ok and nothing left of interest */
3848  if (delete_ok && all_fired_in_chunk)
3849  {
3850  chunk->freeptr = CHUNK_DATA_START(chunk);
3851  chunk->endfree = chunk->endptr;
3852 
3853  /*
3854  * If it's last chunk, must sync event list's tailfree too. Note
3855  * that delete_ok must NOT be passed as true if there could be
3856  * stacked AfterTriggerEventList values pointing at this event
3857  * list, since we'd fail to fix their copies of tailfree.
3858  */
3859  if (chunk == events->tail)
3860  events->tailfree = chunk->freeptr;
3861  }
3862  }
3863  if (slot1 != NULL)
3864  {
3867  }
3868 
3869  /* Release working resources */
3870  MemoryContextDelete(per_tuple_context);
3871 
3872  if (local_estate)
3873  {
3874  ListCell *l;
3875 
3876  foreach(l, estate->es_trig_target_relations)
3877  {
3878  ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
3879 
3880  /* Close indices and then the relation itself */
3881  ExecCloseIndices(resultRelInfo);
3882  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
3883  }
3884  FreeExecutorState(estate);
3885  }
3886 
3887  return all_fired;
3888 }
Definition: fmgr.h:53
Relation ri_RelationDesc
Definition: execnodes.h:328
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
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 GetTriggerSharedData(evt)
Definition: trigger.c:3092
#define for_each_event(eptr, cptr)
Definition: trigger.c:3124
void FreeExecutorState(EState *estate)
Definition: execUtils.c:167
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:219
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:162
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:202
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:440
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 AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3045
#define elog
Definition: elog.h:218
#define RelationGetRelid(relation)
Definition: rel.h:371
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:3511
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:333
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

Definition at line 3682 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().

3685 {
3686  bool found = false;
3687  AfterTriggerEvent event;
3688  AfterTriggerEventChunk *chunk;
3689 
3690  for_each_event_chunk(event, chunk, *events)
3691  {
3692  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3693  bool defer_it = false;
3694 
3695  if (!(event->ate_flags &
3697  {
3698  /*
3699  * This trigger hasn't been called or scheduled yet. Check if we
3700  * should call it now.
3701  */
3702  if (immediate_only && afterTriggerCheckState(evtshared))
3703  {
3704  defer_it = true;
3705  }
3706  else
3707  {
3708  /*
3709  * Mark it as to be fired in this firing cycle.
3710  */
3712  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3713  found = true;
3714  }
3715  }
3716 
3717  /*
3718  * If it's deferred, move it to move_list, if requested.
3719  */
3720  if (defer_it && move_list != NULL)
3721  {
3722  /* add it to move_list */
3723  afterTriggerAddEvent(move_list, event, evtshared);
3724  /* mark original copy "done" so we don't do it again */
3725  event->ate_flags |= AFTER_TRIGGER_DONE;
3726  }
3727  }
3728 
3729  return found;
3730 }
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 4749 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().

4750 {
4751  AfterTriggerEvent event;
4752  AfterTriggerEventChunk *chunk;
4753  int depth;
4754 
4755  /* Scan queued events */
4757  {
4758  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4759 
4760  /*
4761  * We can ignore completed events. (Even if a DONE flag is rolled
4762  * back by subxact abort, it's OK because the effects of the TRUNCATE
4763  * or whatever must get rolled back too.)
4764  */
4765  if (event->ate_flags & AFTER_TRIGGER_DONE)
4766  continue;
4767 
4768  if (evtshared->ats_relid == relid)
4769  return true;
4770  }
4771 
4772  /*
4773  * Also scan events queued by incomplete queries. This could only matter
4774  * if TRUNCATE/etc is executed by a function or trigger within an updating
4775  * query on the same relation, which is pretty perverse, but let's check.
4776  */
4777  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
4778  {
4779  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
4780  {
4781  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4782 
4783  if (event->ate_flags & AFTER_TRIGGER_DONE)
4784  continue;
4785 
4786  if (evtshared->ats_relid == relid)
4787  return true;
4788  }
4789  }
4790 
4791  return false;
4792 }
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 3456 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

3458 {
3459  AfterTriggerEventChunk *chunk;
3460  AfterTriggerEventChunk *next_chunk;
3461 
3462  if (old_events->tail == NULL)
3463  {
3464  /* restoring to a completely empty state, so free everything */
3465  afterTriggerFreeEventList(events);
3466  }
3467  else
3468  {
3469  *events = *old_events;
3470  /* free any chunks after the last one we want to keep */
3471  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3472  {
3473  next_chunk = chunk->next;
3474  pfree(chunk);
3475  }
3476  /* and clean up the tail chunk to be the right length */
3477  events->tail->next = NULL;
3478  events->tail->freeptr = events->tailfree;
3479 
3480  /*
3481  * We don't make any effort to remove now-unused shared data records.
3482  * They might still be useful, anyway.
3483  */
3484  }
3485 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3117
struct AfterTriggerEventChunk * next
Definition: trigger.c:3104
void pfree(void *pointer)
Definition: mcxt.c:992
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3433
#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 4807 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().

4811 {
4812  Relation rel = relinfo->ri_RelationDesc;
4813  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
4814  AfterTriggerEventData new_event;
4815  AfterTriggerSharedData new_shared;
4816  char relkind = relinfo->ri_RelationDesc->rd_rel->relkind;
4817  int tgtype_event;
4818  int tgtype_level;
4819  int i;
4820  Tuplestorestate *fdw_tuplestore = NULL;
4821 
4822  /*
4823  * Check state. We use a normal test not Assert because it is possible to
4824  * reach here in the wrong state given misconfigured RI triggers, in
4825  * particular deferring a cascade action trigger.
4826  */
4827  if (afterTriggers.query_depth < 0)
4828  elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
4829 
4830  /* Be sure we have enough space to record events at this query depth. */
4833 
4834  /*
4835  * Validate the event code and collect the associated tuple CTIDs.
4836  *
4837  * The event code will be used both as a bitmask and an array offset, so
4838  * validation is important to make sure we don't walk off the edge of our
4839  * arrays.
4840  */
4841  switch (event)
4842  {
4843  case TRIGGER_EVENT_INSERT:
4844  tgtype_event = TRIGGER_TYPE_INSERT;
4845  if (row_trigger)
4846  {
4847  Assert(oldtup == NULL);
4848  Assert(newtup != NULL);
4849  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
4850  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4851  }
4852  else
4853  {
4854  Assert(oldtup == NULL);
4855  Assert(newtup == NULL);
4856  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4857  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4858  }
4859  break;
4860  case TRIGGER_EVENT_DELETE:
4861  tgtype_event = TRIGGER_TYPE_DELETE;
4862  if (row_trigger)
4863  {
4864  Assert(oldtup != NULL);
4865  Assert(newtup == NULL);
4866  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4867  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4868  }
4869  else
4870  {
4871  Assert(oldtup == NULL);
4872  Assert(newtup == NULL);
4873  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4874  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4875  }
4876  break;
4877  case TRIGGER_EVENT_UPDATE:
4878  tgtype_event = TRIGGER_TYPE_UPDATE;
4879  if (row_trigger)
4880  {
4881  Assert(oldtup != NULL);
4882  Assert(newtup != NULL);
4883  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
4884  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
4885  }
4886  else
4887  {
4888  Assert(oldtup == NULL);
4889  Assert(newtup == NULL);
4890  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4891  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4892  }
4893  break;
4895  tgtype_event = TRIGGER_TYPE_TRUNCATE;
4896  Assert(oldtup == NULL);
4897  Assert(newtup == NULL);
4898  ItemPointerSetInvalid(&(new_event.ate_ctid1));
4899  ItemPointerSetInvalid(&(new_event.ate_ctid2));
4900  break;
4901  default:
4902  elog(ERROR, "invalid after-trigger event code: %d", event);
4903  tgtype_event = 0; /* keep compiler quiet */
4904  break;
4905  }
4906 
4907  if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
4908  new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
4910  /* else, we'll initialize ate_flags for each trigger */
4911 
4912  tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
4913 
4914  for (i = 0; i < trigdesc->numtriggers; i++)
4915  {
4916  Trigger *trigger = &trigdesc->triggers[i];
4917 
4918  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
4919  tgtype_level,
4921  tgtype_event))
4922  continue;
4923  if (!TriggerEnabled(estate, relinfo, trigger, event,
4924  modifiedCols, oldtup, newtup))
4925  continue;
4926 
4927  if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
4928  {
4929  if (fdw_tuplestore == NULL)
4930  {
4931  fdw_tuplestore = GetCurrentFDWTuplestore();
4932  new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
4933  }
4934  else
4935  /* subsequent event for the same tuple */
4936  new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
4937  }
4938 
4939  /*
4940  * If the trigger is a foreign key enforcement trigger, there are
4941  * certain cases where we can skip queueing the event because we can
4942  * tell by inspection that the FK constraint will still pass.
4943  */
4944  if (TRIGGER_FIRED_BY_UPDATE(event))
4945  {
4946  switch (RI_FKey_trigger_type(trigger->tgfoid))
4947  {
4948  case RI_TRIGGER_PK:
4949  /* Update on trigger's PK table */
4950  if (!RI_FKey_pk_upd_check_required(trigger, rel,
4951  oldtup, newtup))
4952  {
4953  /* skip queuing this event */
4954  continue;
4955  }
4956  break;
4957 
4958  case RI_TRIGGER_FK:
4959  /* Update on trigger's FK table */
4960  if (!RI_FKey_fk_upd_check_required(trigger, rel,
4961  oldtup, newtup))
4962  {
4963  /* skip queuing this event */
4964  continue;
4965  }
4966  break;
4967 
4968  case RI_TRIGGER_NONE:
4969  /* Not an FK trigger */
4970  break;
4971  }
4972  }
4973 
4974  /*
4975  * If the trigger is a deferred unique constraint check trigger, only
4976  * queue it if the unique constraint was potentially violated, which
4977  * we know from index insertion time.
4978  */
4979  if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
4980  {
4981  if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
4982  continue; /* Uniqueness definitely not violated */
4983  }
4984 
4985  /*
4986  * Fill in event structure and add it to the current query's queue.
4987  */
4988  new_shared.ats_event =
4989  (event & TRIGGER_EVENT_OPMASK) |
4990  (row_trigger ? TRIGGER_EVENT_ROW : 0) |
4991  (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
4992  (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
4993  new_shared.ats_tgoid = trigger->tgoid;
4994  new_shared.ats_relid = RelationGetRelid(rel);
4995  new_shared.ats_firing_id = 0;
4996 
4998  &new_event, &new_shared);
4999  }
5000 
5001  /*
5002  * Finally, spool any foreign tuple(s). The tuplestore squashes them to
5003  * minimal tuples, so this loses any system columns. The executor lost
5004  * those columns before us, for an unrelated reason, so this is fine.
5005  */
5006  if (fdw_tuplestore)
5007  {
5008  if (oldtup != NULL)
5009  tuplestore_puttuple(fdw_tuplestore, oldtup);
5010  if (newtup != NULL)
5011  tuplestore_puttuple(fdw_tuplestore, newtup);
5012  }
5013 }
#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:162
#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:4325
#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:371
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:124
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 4455 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().

4456 {
4457  int my_level = GetCurrentTransactionNestLevel();
4458 
4459  /* If we haven't already done so, initialize our state. */
4460  if (afterTriggers.state == NULL)
4462 
4463  /*
4464  * If in a subtransaction, and we didn't save the current state already,
4465  * save it so it can be restored if the subtransaction aborts.
4466  */
4467  if (my_level > 1 &&
4468  afterTriggers.state_stack[my_level] == NULL)
4469  {
4470  afterTriggers.state_stack[my_level] =
4472  }
4473 
4474  /*
4475  * Handle SET CONSTRAINTS ALL ...
4476  */
4477  if (stmt->constraints == NIL)
4478  {
4479  /*
4480  * Forget any previous SET CONSTRAINTS commands in this transaction.
4481  */
4483 
4484  /*
4485  * Set the per-transaction ALL state to known.
4486  */
4487  afterTriggers.state->all_isset = true;
4489  }
4490  else
4491  {
4492  Relation conrel;
4493  Relation tgrel;
4494  List *conoidlist = NIL;
4495  List *tgoidlist = NIL;
4496  ListCell *lc;
4497 
4498  /*
4499  * Handle SET CONSTRAINTS constraint-name [, ...]
4500  *
4501  * First, identify all the named constraints and make a list of their
4502  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4503  * the same name within a schema, the specifications are not
4504  * necessarily unique. Our strategy is to target all matching
4505  * constraints within the first search-path schema that has any
4506  * matches, but disregard matches in schemas beyond the first match.
4507  * (This is a bit odd but it's the historical behavior.)
4508  */
4510 
4511  foreach(lc, stmt->constraints)
4512  {
4513  RangeVar *constraint = lfirst(lc);
4514  bool found;
4515  List *namespacelist;
4516  ListCell *nslc;
4517 
4518  if (constraint->catalogname)
4519  {
4520  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4521  ereport(ERROR,
4522  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4523  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4524  constraint->catalogname, constraint->schemaname,
4525  constraint->relname)));
4526  }
4527 
4528  /*
4529  * If we're given the schema name with the constraint, look only
4530  * in that schema. If given a bare constraint name, use the
4531  * search path to find the first matching constraint.
4532  */
4533  if (constraint->schemaname)
4534  {
4535  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4536  false);
4537 
4538  namespacelist = list_make1_oid(namespaceId);
4539  }
4540  else
4541  {
4542  namespacelist = fetch_search_path(true);
4543  }
4544 
4545  found = false;
4546  foreach(nslc, namespacelist)
4547  {
4548  Oid namespaceId = lfirst_oid(nslc);
4549  SysScanDesc conscan;
4550  ScanKeyData skey[2];
4551  HeapTuple tup;
4552 
4553  ScanKeyInit(&skey[0],
4555  BTEqualStrategyNumber, F_NAMEEQ,
4556  CStringGetDatum(constraint->relname));
4557  ScanKeyInit(&skey[1],
4559  BTEqualStrategyNumber, F_OIDEQ,
4560  ObjectIdGetDatum(namespaceId));
4561 
4562  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4563  true, NULL, 2, skey);
4564 
4565  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4566  {
4568 
4569  if (con->condeferrable)
4570  conoidlist = lappend_oid(conoidlist,
4571  HeapTupleGetOid(tup));
4572  else if (stmt->deferred)
4573  ereport(ERROR,
4574  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4575  errmsg("constraint \"%s\" is not deferrable",
4576  constraint->relname)));
4577  found = true;
4578  }
4579 
4580  systable_endscan(conscan);
4581 
4582  /*
4583  * Once we've found a matching constraint we do not search
4584  * later parts of the search path.
4585  */
4586  if (found)
4587  break;
4588  }
4589 
4590  list_free(namespacelist);
4591 
4592  /*
4593  * Not found ?
4594  */
4595  if (!found)
4596  ereport(ERROR,
4597  (errcode(ERRCODE_UNDEFINED_OBJECT),
4598  errmsg("constraint \"%s\" does not exist",
4599  constraint->relname)));
4600  }
4601 
4602  heap_close(conrel, AccessShareLock);
4603 
4604  /*
4605  * Now, locate the trigger(s) implementing each of these constraints,
4606  * and make a list of their OIDs.
4607  */
4609 
4610  foreach(lc, conoidlist)
4611  {
4612  Oid conoid = lfirst_oid(lc);
4613  bool found;
4614  ScanKeyData skey;
4615  SysScanDesc tgscan;
4616  HeapTuple htup;
4617 
4618  found = false;
4619 
4620  ScanKeyInit(&skey,
4622  BTEqualStrategyNumber, F_OIDEQ,
4623  ObjectIdGetDatum(conoid));
4624 
4625  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
4626  NULL, 1, &skey);
4627 
4628  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
4629  {
4630  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
4631 
4632  /*
4633  * Silently skip triggers that are marked as non-deferrable in
4634  * pg_trigger. This is not an error condition, since a
4635  * deferrable RI constraint may have some non-deferrable
4636  * actions.
4637  */
4638  if (pg_trigger->tgdeferrable)
4639  tgoidlist = lappend_oid(tgoidlist,
4640  HeapTupleGetOid(htup));
4641 
4642  found = true;
4643  }
4644 
4645  systable_endscan(tgscan);
4646 
4647  /* Safety check: a deferrable constraint should have triggers */
4648  if (!found)
4649  elog(ERROR, "no triggers found for constraint with OID %u",
4650  conoid);
4651  }
4652 
4653  heap_close(tgrel, AccessShareLock);
4654 
4655  /*
4656  * Now we can set the trigger states of individual triggers for this
4657  * xact.
4658  */
4659  foreach(lc, tgoidlist)
4660  {
4661  Oid tgoid = lfirst_oid(lc);
4663  bool found = false;
4664  int i;
4665 
4666  for (i = 0; i < state->numstates; i++)
4667  {
4668  if (state->trigstates[i].sct_tgoid == tgoid)
4669  {
4670  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
4671  found = true;
4672  break;
4673  }
4674  }
4675  if (!found)
4676  {
4678  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
4679  }
4680  }
4681  }
4682 
4683  /*
4684  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
4685  * checks against that constraint must be made when the SET CONSTRAINTS
4686  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
4687  * apply retroactively. We've updated the constraints state, so scan the
4688  * list of previously deferred events to fire any that have now become
4689  * immediate.
4690  *
4691  * Obviously, if this was SET ... DEFERRED then it can't have converted
4692  * any unfired events to immediate, so we need do nothing in that case.
4693  */
4694  if (!stmt->deferred)
4695  {
4697  bool snapshot_set = false;
4698 
4699  while (afterTriggerMarkEvents(events, NULL, true))
4700  {
4701  CommandId firing_id = afterTriggers.firing_counter++;
4702 
4703  /*
4704  * Make sure a snapshot has been established in case trigger
4705  * functions need one. Note that we avoid setting a snapshot if
4706  * we don't find at least one trigger that has to be fired now.
4707  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
4708  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
4709  * at the start of a transaction it's not possible for any trigger
4710  * events to be queued yet.)
4711  */
4712  if (!snapshot_set)
4713  {
4715  snapshot_set = true;
4716  }
4717 
4718  /*
4719  * We can delete fired events if we are at top transaction level,
4720  * but we'd better not if inside a subtransaction, since the
4721  * subtransaction could later get rolled back.
4722  */
4723  if (afterTriggerInvokeEvents(events, firing_id, NULL,
4724  !IsSubTransaction()))
4725  break; /* all fired */
4726  }
4727 
4728  if (snapshot_set)
4730  }
4731 }
#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:656
#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:4425
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3754
void PopActiveSnapshot(void)
Definition: snapmgr.c:766
#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:302
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:687
#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:4380
#define list_make1_oid(x1)
Definition: pg_list.h:145
Oid MyDatabaseId
Definition: globals.c:76
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1286
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:312
#define TriggerRelationId
Definition: pg_trigger.h:34
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:70
bool IsSubTransaction(void)
Definition: xact.c:4368
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:3682
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:695
Definition: pg_list.h:45
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4028
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:4405
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:1820
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:9707
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2727
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:1811
char fk_matchtype
Definition: parsenodes.h:1856
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:1815
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:493
#define strVal(v)
Definition: value.h:54
bool initdeferred
Definition: parsenodes.h:1830
AlterTableType subtype
Definition: parsenodes.h:1541
List * pk_attrs
Definition: parsenodes.h:1855
char * conname
Definition: parsenodes.h:1828
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
DestReceiver * None_Receiver
Definition: dest.c:85
#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:4295
#define list_make1(x1)
Definition: pg_list.h:133
RangeVar * constrrel
Definition: parsenodes.h:2109
void pfree(void *pointer)
Definition: mcxt.c:992
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:1829
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:1461
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:1813
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:1818
void * palloc0(Size size)
Definition: mcxt.c:920
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:1864
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:541
char fk_del_action
Definition: parsenodes.h:1858
#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:1459
int i
RangeVar * relation
Definition: parsenodes.h:2095
ConstrType contype
Definition: parsenodes.h:1825
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:1812
#define lthird(l)
Definition: pg_list.h:118
#define elog
Definition: elog.h:218
RangeVar * pktable
Definition: parsenodes.h:1853
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:1814
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:1863
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:1854
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:1857
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:1165
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:891
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
536  * the 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:656
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:2104
#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:493
#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:4295
#define TriggerRelidNameIndexId
Definition: indexing.h:233
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#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:2109
#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:992
#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:3392
#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:391
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:162
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:2914
#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:1286
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:1314
bool allowSystemTableMods
Definition: globals.c:111
#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:4477
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:4411
#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:1904
static Datum values[MAXATTR]
Definition: bootstrap.c:160
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:150
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:70
#define RELKIND_VIEW
Definition: pg_class.h:160
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4435
int i
RangeVar * relation
Definition: parsenodes.h:2095
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:815
char * nodeToString(const void *obj)
Definition: outfuncs.c:3887
#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:156
#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:371
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:398
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:656
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:391
#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:1286
#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:4477
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:695
#define RelationGetRelid(relation)
Definition: rel.h:371
#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:4807
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:4807
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:4807
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:4807
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:4807
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:4807
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:4807
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:323
Relation ri_RelationDesc
Definition: execnodes.h:328
#define RelationGetDescr(relation)
Definition: rel.h:383
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:250
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
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:96
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:728
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:327
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:95
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:50
NodeTag type
Definition: trigger.h:32