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_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 ()
 
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 3050 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3051 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3049 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3048 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 3043 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3052 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3112 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 3123 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:3112
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3086
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3064

Definition at line 3125 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:3052
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3050
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3051

Definition at line 3086 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3064 of file trigger.c.

Definition at line 3054 of file trigger.c.

Definition at line 3041 of file trigger.c.

Function Documentation

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

Definition at line 3319 of file trigger.c.

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

Referenced by afterTriggerMarkEvents(), and AfterTriggerSaveEvent().

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

Definition at line 3940 of file trigger.c.

References AfterTriggersData::query_depth.

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

3941 {
3942  /* Increase the query stack depth */
3944 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3210
void AfterTriggerBeginSubXact ( void  )

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

4149 {
4150  int my_level = GetCurrentTransactionNestLevel();
4151 
4152  /*
4153  * Allocate more space in the stacks if needed. (Note: because the
4154  * minimum nest level of a subtransaction is 2, we waste the first couple
4155  * entries of each array; not worth the notational effort to avoid it.)
4156  */
4157  while (my_level >= afterTriggers.maxtransdepth)
4158  {
4159  if (afterTriggers.maxtransdepth == 0)
4160  {
4161  MemoryContext old_cxt;
4162 
4164 
4165 #define DEFTRIG_INITALLOC 8
4170  afterTriggers.depth_stack = (int *)
4171  palloc(DEFTRIG_INITALLOC * sizeof(int));
4173  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4175 
4176  MemoryContextSwitchTo(old_cxt);
4177  }
4178  else
4179  {
4180  /* repalloc will keep the stacks in the same context */
4181  int new_alloc = afterTriggers.maxtransdepth * 2;
4182 
4185  new_alloc * sizeof(SetConstraintState));
4188  new_alloc * sizeof(AfterTriggerEventList));
4189  afterTriggers.depth_stack = (int *)
4191  new_alloc * sizeof(int));
4194  new_alloc * sizeof(CommandId));
4195  afterTriggers.maxtransdepth = new_alloc;
4196  }
4197  }
4198 
4199  /*
4200  * Push the current information into the stack. The SET CONSTRAINTS state
4201  * is not saved until/unless changed. Likewise, we don't make a
4202  * per-subtransaction event context until needed.
4203  */
4204  afterTriggers.state_stack[my_level] = NULL;
4208 }
uint32 CommandId
Definition: c.h:388
MemoryContext TopTransactionContext
Definition: mcxt.c:51
#define DEFTRIG_INITALLOC
CommandId * firing_stack
Definition: trigger.c:3206
SetConstraintState * state_stack
Definition: trigger.c:3203
MemoryContext MemoryContextSwitchTo(MemoryContext context)
CommandId firing_counter
Definition: trigger.c:3192
AfterTriggerEventList * events_stack
Definition: trigger.c:3204
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:758
#define NULL
Definition: c.h:202
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:942
void * palloc(Size size)
Definition: mcxt.c:812
AfterTriggerEventList events
Definition: trigger.c:3194
static AfterTriggersData afterTriggers
Definition: trigger.c:3210
void AfterTriggerBeginXact ( void  )

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

3905 {
3906  /*
3907  * Initialize after-trigger state structure to empty
3908  */
3909  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
3911 
3912  /*
3913  * Verify that there is no leftover state remaining. If these assertions
3914  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
3915  * up properly.
3916  */
3928 }
uint32 CommandId
Definition: c.h:388
CommandId * firing_stack
Definition: trigger.c:3206
SetConstraintState * state_stack
Definition: trigger.c:3203
SetConstraintState state
Definition: trigger.c:3193
CommandId firing_counter
Definition: trigger.c:3192
AfterTriggerEventList * events_stack
Definition: trigger.c:3204
#define NULL
Definition: c.h:202
#define Assert(condition)
Definition: c.h:648
AfterTriggerEventChunk * head
Definition: trigger.c:3117
MemoryContext event_cxt
Definition: trigger.c:3199
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3197
AfterTriggerEventList events
Definition: trigger.c:3194
AfterTriggerEventList * query_stack
Definition: trigger.c:3196
static AfterTriggersData afterTriggers
Definition: trigger.c:3210
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

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

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

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

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

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

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

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

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

4331 {
4332  int init_depth = afterTriggers.maxquerydepth;
4333 
4335 
4336  if (afterTriggers.maxquerydepth == 0)
4337  {
4338  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4339 
4342  new_alloc * sizeof(AfterTriggerEventList));
4345  new_alloc * sizeof(Tuplestorestate *));
4346  afterTriggers.maxquerydepth = new_alloc;
4347  }
4348  else
4349  {
4350  /* repalloc will keep the stack in the same context */
4351  int old_alloc = afterTriggers.maxquerydepth;
4352  int new_alloc = Max(afterTriggers.query_depth + 1,
4353  old_alloc * 2);
4354 
4357  new_alloc * sizeof(AfterTriggerEventList));
4360  new_alloc * sizeof(Tuplestorestate *));
4361  /* Clear newly-allocated slots for subsequent lazy initialization. */
4362  memset(afterTriggers.fdw_tuplestores + old_alloc,
4363  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4364  afterTriggers.maxquerydepth = new_alloc;
4365  }
4366 
4367  /* Initialize new query lists to empty */
4368  while (init_depth < afterTriggers.maxquerydepth)
4369  {
4370  AfterTriggerEventList *events;
4371 
4372  events = &afterTriggers.query_stack[init_depth];
4373  events->head = NULL;
4374  events->tail = NULL;
4375  events->tailfree = NULL;
4376 
4377  ++init_depth;
4378  }
4379 }
MemoryContext TopTransactionContext
Definition: mcxt.c:51
AfterTriggerEventChunk * tail
Definition: trigger.c:3118
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:705
#define Max(x, y)
Definition: c.h:773
#define NULL
Definition: c.h:202
#define Assert(condition)
Definition: c.h:648
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:942
AfterTriggerEventChunk * head
Definition: trigger.c:3117
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:670
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3197
AfterTriggerEventList * query_stack
Definition: trigger.c:3196
static AfterTriggersData afterTriggers
Definition: trigger.c:3210
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 3514 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().

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

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

Definition at line 3436 of file trigger.c.

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

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

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

Definition at line 3757 of file trigger.c.

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

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

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

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

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

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

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

Definition at line 3459 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

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

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

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

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

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

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

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

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

1693 {
1694  TriggerDesc *newdesc;
1695  Trigger *trigger;
1696  int i;
1697 
1698  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1699  return NULL;
1700 
1701  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1702  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1703 
1704  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1705  memcpy(trigger, trigdesc->triggers,
1706  trigdesc->numtriggers * sizeof(Trigger));
1707  newdesc->triggers = trigger;
1708 
1709  for (i = 0; i < trigdesc->numtriggers; i++)
1710  {
1711  trigger->tgname = pstrdup(trigger->tgname);
1712  if (trigger->tgnattr > 0)
1713  {
1714  int16 *newattr;
1715 
1716  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1717  memcpy(newattr, trigger->tgattr,
1718  trigger->tgnattr * sizeof(int16));
1719  trigger->tgattr = newattr;
1720  }
1721  if (trigger->tgnargs > 0)
1722  {
1723  char **newargs;
1724  int16 j;
1725 
1726  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1727  for (j = 0; j < trigger->tgnargs; j++)
1728  newargs[j] = pstrdup(trigger->tgargs[j]);
1729  trigger->tgargs = newargs;
1730  }
1731  if (trigger->tgqual)
1732  trigger->tgqual = pstrdup(trigger->tgqual);
1733  trigger++;
1734  }
1735 
1736  return newdesc;
1737 }
signed short int16
Definition: c.h:228
char * pstrdup(const char *in)
Definition: mcxt.c:1080
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:202
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:812
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 137 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, 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(), 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(), PVC_REJECT_AGGREGATES, PVC_REJECT_PLACEHOLDERS, 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().

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

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

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

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

2274 {
2275  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2276 
2277  if (trigdesc && trigdesc->trig_delete_after_row)
2278  {
2279  HeapTuple trigtuple;
2280 
2281  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2282  if (fdw_trigtuple == NULL)
2283  trigtuple = GetTupleForTrigger(estate,
2284  NULL,
2285  relinfo,
2286  tupleid,
2288  NULL);
2289  else
2290  trigtuple = fdw_trigtuple;
2291 
2293  true, trigtuple, NULL, NIL, NULL);
2294  if (trigtuple != fdw_trigtuple)
2295  heap_freetuple(trigtuple);
2296  }
2297 }
#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:1417
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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:202
#define Assert(condition)
Definition: c.h:648
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2681
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

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

2071 {
2072  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2073 
2074  if (trigdesc && trigdesc->trig_insert_after_row)
2076  true, NULL, trigtuple, recheckIndexes, NULL);
2077 }
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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define NULL
Definition: c.h:202
#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 2524 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().

2529 {
2530  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2531 
2532  if (trigdesc && trigdesc->trig_update_after_row)
2533  {
2534  HeapTuple trigtuple;
2535 
2536  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2537  if (fdw_trigtuple == NULL)
2538  trigtuple = GetTupleForTrigger(estate,
2539  NULL,
2540  relinfo,
2541  tupleid,
2543  NULL);
2544  else
2545  trigtuple = fdw_trigtuple;
2546 
2548  true, trigtuple, newtuple, recheckIndexes,
2549  GetUpdatedColumns(relinfo, estate));
2550  if (trigtuple != fdw_trigtuple)
2551  heap_freetuple(trigtuple);
2552  }
2553 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1417
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
bool trig_update_after_row
Definition: reltrigger.h:59
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:74
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:202
#define Assert(condition)
Definition: c.h:648
#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:2681
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2194 of file trigger.c.

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

Referenced by fireASTriggers().

2195 {
2196  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2197 
2198  if (trigdesc && trigdesc->trig_delete_after_statement)
2200  false, NULL, NULL, NIL, NULL);
2201 }
#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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define NULL
Definition: c.h:202
bool trig_delete_after_statement
Definition: reltrigger.h:67
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

1996 {
1997  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
1998 
1999  if (trigdesc && trigdesc->trig_insert_after_statement)
2001  false, NULL, NULL, NIL, NULL);
2002 }
#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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define NULL
Definition: c.h:202
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:50
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2670 of file trigger.c.

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

Referenced by ExecuteTruncate().

2671 {
2672  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2673 
2674  if (trigdesc && trigdesc->trig_truncate_after_statement)
2676  false, NULL, NULL, NIL, NULL);
2677 }
#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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define NULL
Definition: c.h:202
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:53
void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2398 of file trigger.c.

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

Referenced by fireASTriggers().

2399 {
2400  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2401 
2402  if (trigdesc && trigdesc->trig_update_after_statement)
2404  false, NULL, NULL, NIL,
2405  GetUpdatedColumns(relinfo, estate));
2406 }
#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:4812
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:74
#define NULL
Definition: c.h:202
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:52
bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

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

2208 {
2209  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2210  bool result = true;
2211  TriggerData LocTriggerData;
2212  HeapTuple trigtuple;
2213  HeapTuple newtuple;
2214  TupleTableSlot *newSlot;
2215  int i;
2216 
2217  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2218  if (fdw_trigtuple == NULL)
2219  {
2220  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2221  LockTupleExclusive, &newSlot);
2222  if (trigtuple == NULL)
2223  return false;
2224  }
2225  else
2226  trigtuple = fdw_trigtuple;
2227 
2228  LocTriggerData.type = T_TriggerData;
2229  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2232  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2233  LocTriggerData.tg_newtuple = NULL;
2234  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2235  for (i = 0; i < trigdesc->numtriggers; i++)
2236  {
2237  Trigger *trigger = &trigdesc->triggers[i];
2238 
2239  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2243  continue;
2244  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2245  NULL, trigtuple, NULL))
2246  continue;
2247 
2248  LocTriggerData.tg_trigtuple = trigtuple;
2249  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2250  LocTriggerData.tg_trigger = trigger;
2251  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2252  i,
2253  relinfo->ri_TrigFunctions,
2254  relinfo->ri_TrigInstrument,
2255  GetPerTupleMemoryContext(estate));
2256  if (newtuple == NULL)
2257  {
2258  result = false; /* tell caller to suppress delete */
2259  break;
2260  }
2261  if (newtuple != trigtuple)
2262  heap_freetuple(newtuple);
2263  }
2264  if (trigtuple != fdw_trigtuple)
2265  heap_freetuple(trigtuple);
2266 
2267  return result;
2268 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:63
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
Relation ri_RelationDesc
Definition: execnodes.h:327
#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:334
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1417
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:331
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:2825
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:202
#define Assert(condition)
Definition: c.h:648
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:326
#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:2681
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:1863
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:332
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecBRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

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

2007 {
2008  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2009  HeapTuple slottuple = ExecMaterializeSlot(slot);
2010  HeapTuple newtuple = slottuple;
2011  HeapTuple oldtuple;
2012  TriggerData LocTriggerData;
2013  int i;
2014 
2015  LocTriggerData.type = T_TriggerData;
2016  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2019  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2020  LocTriggerData.tg_newtuple = NULL;
2021  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2022  for (i = 0; i < trigdesc->numtriggers; i++)
2023  {
2024  Trigger *trigger = &trigdesc->triggers[i];
2025 
2026  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2030  continue;
2031  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2032  NULL, NULL, newtuple))
2033  continue;
2034 
2035  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2036  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2037  LocTriggerData.tg_trigger = trigger;
2038  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2039  i,
2040  relinfo->ri_TrigFunctions,
2041  relinfo->ri_TrigInstrument,
2042  GetPerTupleMemoryContext(estate));
2043  if (oldtuple != newtuple && oldtuple != slottuple)
2044  heap_freetuple(oldtuple);
2045  if (newtuple == NULL)
2046  return NULL; /* "do nothing" */
2047  }
2048 
2049  if (newtuple != slottuple)
2050  {
2051  /*
2052  * Return the modified tuple using the es_trig_tuple_slot. We assume
2053  * the tuple was allocated in per-tuple memory context, and therefore
2054  * will go away by itself. The tuple table slot should not try to
2055  * clear it.
2056  */
2057  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2058  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2059 
2060  if (newslot->tts_tupleDescriptor != tupdesc)
2061  ExecSetSlotDescriptor(newslot, tupdesc);
2062  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2063  slot = newslot;
2064  }
2065  return slot;
2066 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:56
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:324
Relation ri_RelationDesc
Definition: execnodes.h:327
#define RelationGetDescr(relation)
Definition: rel.h:357
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:334
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1417
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:375
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:331
int numtriggers
Definition: reltrigger.h:47
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:251
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36