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

Go to the source code of this file.

Data Structures

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

Macros

#define GetUpdatedColumns(relinfo, estate)   (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
 
#define AFTER_TRIGGER_OFFSET   0x0FFFFFFF /* must be low-order bits */
 
#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, TransitionCaptureState *transition_capture)
 
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)
 
const char * FindTriggerIncompatibleWithInheritance (TriggerDesc *trigdesc)
 
TransitionCaptureStateMakeTransitionCaptureState (TriggerDesc *trigdesc)
 
void DestroyTransitionCaptureState (TransitionCaptureState *tcs)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
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, TransitionCaptureState *transition_capture)
 
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, TransitionCaptureState *transition_capture)
 
static SetConstraintState SetConstraintStateCreate (int numalloc)
 
static SetConstraintState SetConstraintStateCopy (SetConstraintState state)
 
static SetConstraintState SetConstraintStateAddItem (SetConstraintState state, Oid tgoid, bool tgisdeferred)
 
static TuplestorestateGetTriggerTransitionTuplestore (Tuplestorestate **tss)
 
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 3424 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3425 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3423 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3422 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

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

Definition at line 3418 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3426 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3487 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 3498 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:3487
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3461
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3439

Definition at line 3500 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:3426
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3424
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3425

Definition at line 3461 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3439 of file trigger.c.

Definition at line 3428 of file trigger.c.

Definition at line 3416 of file trigger.c.

Function Documentation

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

Definition at line 3696 of file trigger.c.

References AFTER_TRIGGER_OFFSET, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Assert, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, AfterTriggerSharedData::ats_tgoid, AfterTriggerSharedData::ats_transition_capture, 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().

3698 {
3699  Size eventsize = SizeofTriggerEvent(event);
3700  Size needed = eventsize + sizeof(AfterTriggerSharedData);
3701  AfterTriggerEventChunk *chunk;
3702  AfterTriggerShared newshared;
3703  AfterTriggerEvent newevent;
3704 
3705  /*
3706  * If empty list or not enough room in the tail chunk, make a new chunk.
3707  * We assume here that a new shared record will always be needed.
3708  */
3709  chunk = events->tail;
3710  if (chunk == NULL ||
3711  chunk->endfree - chunk->freeptr < needed)
3712  {
3713  Size chunksize;
3714 
3715  /* Create event context if we didn't already */
3716  if (afterTriggers.event_cxt == NULL)
3719  "AfterTriggerEvents",
3721 
3722  /*
3723  * Chunk size starts at 1KB and is allowed to increase up to 1MB.
3724  * These numbers are fairly arbitrary, though there is a hard limit at
3725  * AFTER_TRIGGER_OFFSET; else we couldn't link event records to their
3726  * shared records using the available space in ate_flags. Another
3727  * constraint is that if the chunk size gets too huge, the search loop
3728  * below would get slow given a (not too common) usage pattern with
3729  * many distinct event types in a chunk. Therefore, we double the
3730  * preceding chunk size only if there weren't too many shared records
3731  * in the preceding chunk; otherwise we halve it. This gives us some
3732  * ability to adapt to the actual usage pattern of the current query
3733  * while still having large chunk sizes in typical usage. All chunk
3734  * sizes used should be MAXALIGN multiples, to ensure that the shared
3735  * records will be aligned safely.
3736  */
3737 #define MIN_CHUNK_SIZE 1024
3738 #define MAX_CHUNK_SIZE (1024*1024)
3739 
3740 #if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
3741 #error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
3742 #endif
3743 
3744  if (chunk == NULL)
3745  chunksize = MIN_CHUNK_SIZE;
3746  else
3747  {
3748  /* preceding chunk size... */
3749  chunksize = chunk->endptr - (char *) chunk;
3750  /* check number of shared records in preceding chunk */
3751  if ((chunk->endptr - chunk->endfree) <=
3752  (100 * sizeof(AfterTriggerSharedData)))
3753  chunksize *= 2; /* okay, double it */
3754  else
3755  chunksize /= 2; /* too many shared records */
3756  chunksize = Min(chunksize, MAX_CHUNK_SIZE);
3757  }
3758  chunk = MemoryContextAlloc(afterTriggers.event_cxt, chunksize);
3759  chunk->next = NULL;
3760  chunk->freeptr = CHUNK_DATA_START(chunk);
3761  chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
3762  Assert(chunk->endfree - chunk->freeptr >= needed);
3763 
3764  if (events->head == NULL)
3765  events->head = chunk;
3766  else
3767  events->tail->next = chunk;
3768  events->tail = chunk;
3769  /* events->tailfree is now out of sync, but we'll fix it below */
3770  }
3771 
3772  /*
3773  * Try to locate a matching shared-data record already in the chunk. If
3774  * none, make a new one.
3775  */
3776  for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
3777  (char *) newshared >= chunk->endfree;
3778  newshared--)
3779  {
3780  if (newshared->ats_tgoid == evtshared->ats_tgoid &&
3781  newshared->ats_relid == evtshared->ats_relid &&
3782  newshared->ats_event == evtshared->ats_event &&
3783  newshared->ats_transition_capture == evtshared->ats_transition_capture &&
3784  newshared->ats_firing_id == 0)
3785  break;
3786  }
3787  if ((char *) newshared < chunk->endfree)
3788  {
3789  *newshared = *evtshared;
3790  newshared->ats_firing_id = 0; /* just to be sure */
3791  chunk->endfree = (char *) newshared;
3792  }
3793 
3794  /* Insert the data */
3795  newevent = (AfterTriggerEvent) chunk->freeptr;
3796  memcpy(newevent, event, eventsize);
3797  /* ... and link the new event to its shared record */
3798  newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
3799  newevent->ate_flags |= (char *) newshared - (char *) newevent;
3800 
3801  chunk->freeptr += eventsize;
3802  events->tailfree = chunk->freeptr;
3803 }
TriggerEvent ats_event
Definition: trigger.c:3432
MemoryContext TopTransactionContext
Definition: mcxt.c:48
#define MIN_CHUNK_SIZE
TriggerFlags ate_flags
Definition: trigger.c:3443
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3487
struct AfterTriggerSharedData AfterTriggerSharedData
#define Min(x, y)
Definition: c.h:806
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
struct AfterTriggerEventChunk * next
Definition: trigger.c:3480
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3461
#define AFTER_TRIGGER_OFFSET
Definition: trigger.c:3418
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
TransitionCaptureState * ats_transition_capture
Definition: trigger.c:3436
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
size_t Size
Definition: c.h:356
CommandId ats_firing_id
Definition: trigger.c:3435
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3439
#define MAX_CHUNK_SIZE
AfterTriggerEventChunk * head
Definition: trigger.c:3492
MemoryContext event_cxt
Definition: trigger.c:3575
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerBeginQuery ( void  )

Definition at line 4343 of file trigger.c.

References AfterTriggersData::query_depth.

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

4344 {
4345  /* Increase the query stack depth */
4347 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerBeginSubXact ( void  )

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

4552 {
4553  int my_level = GetCurrentTransactionNestLevel();
4554 
4555  /*
4556  * Allocate more space in the stacks if needed. (Note: because the
4557  * minimum nest level of a subtransaction is 2, we waste the first couple
4558  * entries of each array; not worth the notational effort to avoid it.)
4559  */
4560  while (my_level >= afterTriggers.maxtransdepth)
4561  {
4562  if (afterTriggers.maxtransdepth == 0)
4563  {
4564  MemoryContext old_cxt;
4565 
4567 
4568 #define DEFTRIG_INITALLOC 8
4573  afterTriggers.depth_stack = (int *)
4574  palloc(DEFTRIG_INITALLOC * sizeof(int));
4576  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4578 
4579  MemoryContextSwitchTo(old_cxt);
4580  }
4581  else
4582  {
4583  /* repalloc will keep the stacks in the same context */
4584  int new_alloc = afterTriggers.maxtransdepth * 2;
4585 
4588  new_alloc * sizeof(SetConstraintState));
4591  new_alloc * sizeof(AfterTriggerEventList));
4592  afterTriggers.depth_stack = (int *)
4594  new_alloc * sizeof(int));
4597  new_alloc * sizeof(CommandId));
4598  afterTriggers.maxtransdepth = new_alloc;
4599  }
4600  }
4601 
4602  /*
4603  * Push the current information into the stack. The SET CONSTRAINTS state
4604  * is not saved until/unless changed. Likewise, we don't make a
4605  * per-subtransaction event context until needed.
4606  */
4607  afterTriggers.state_stack[my_level] = NULL;
4611 }
uint32 CommandId
Definition: c.h:411
MemoryContext TopTransactionContext
Definition: mcxt.c:48
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define DEFTRIG_INITALLOC
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
CommandId firing_counter
Definition: trigger.c:3567
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
#define NULL
Definition: c.h:229
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
void * palloc(Size size)
Definition: mcxt.c:849
AfterTriggerEventList events
Definition: trigger.c:3569
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerBeginXact ( void  )

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

4308 {
4309  /*
4310  * Initialize after-trigger state structure to empty
4311  */
4312  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4314 
4315  /*
4316  * Verify that there is no leftover state remaining. If these assertions
4317  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4318  * up properly.
4319  */
4331 }
uint32 CommandId
Definition: c.h:411
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
CommandId firing_counter
Definition: trigger.c:3567
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3492
MemoryContext event_cxt
Definition: trigger.c:3575
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

3651 {
3652  Oid tgoid = evtshared->ats_tgoid;
3654  int i;
3655 
3656  /*
3657  * For not-deferrable triggers (i.e. normal AFTER ROW triggers and
3658  * constraints declared NOT DEFERRABLE), the state is always false.
3659  */
3660  if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
3661  return false;
3662 
3663  /*
3664  * If constraint state exists, SET CONSTRAINTS might have been executed
3665  * either for this trigger or for all triggers.
3666  */
3667  if (state != NULL)
3668  {
3669  /* Check for SET CONSTRAINTS for this specific trigger. */
3670  for (i = 0; i < state->numstates; i++)
3671  {
3672  if (state->trigstates[i].sct_tgoid == tgoid)
3673  return state->trigstates[i].sct_tgisdeferred;
3674  }
3675 
3676  /* Check for SET CONSTRAINTS ALL. */
3677  if (state->all_isset)
3678  return state->all_isdeferred;
3679  }
3680 
3681  /*
3682  * Otherwise return the default state for the trigger.
3683  */
3684  return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
3685 }
TriggerEvent ats_event
Definition: trigger.c:3432
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:113
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:112
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3380
unsigned int Oid
Definition: postgres_ext.h:31
SetConstraintState state
Definition: trigger.c:3568
#define NULL
Definition: c.h:229
Definition: regguts.h:298
int i
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndQuery ( EState estate)

Definition at line 4363 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 apply_handle_delete(), apply_handle_insert(), apply_handle_update(), CopyFrom(), ExecuteTruncate(), and standard_ExecutorFinish().

4364 {
4365  AfterTriggerEventList *events;
4366  Tuplestorestate *fdw_tuplestore;
4367 
4368  /* Must be inside a query, too */
4370 
4371  /*
4372  * If we never even got as far as initializing the event stack, there
4373  * certainly won't be any events, so exit quickly.
4374  */
4376  {
4378  return;
4379  }
4380 
4381  /*
4382  * Process all immediate-mode triggers queued by the query, and move the
4383  * deferred ones to the main list of deferred events.
4384  *
4385  * Notice that we decide which ones will be fired, and put the deferred
4386  * ones on the main list, before anything is actually fired. This ensures
4387  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4388  * IMMEDIATE: all events we have decided to defer will be available for it
4389  * to fire.
4390  *
4391  * We loop in case a trigger queues more events at the same query level.
4392  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4393  * will instead fire any triggers in a dedicated query level. Foreign key
4394  * enforcement triggers do add to the current query level, thanks to their
4395  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4396  * C-language triggers might do likewise. Be careful here: firing a
4397  * trigger could result in query_stack being repalloc'd, so we can't save
4398  * its address across afterTriggerInvokeEvents calls.
4399  *
4400  * If we find no firable events, we don't have to increment
4401  * firing_counter.
4402  */
4403  for (;;)
4404  {
4406  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4407  {
4408  CommandId firing_id = afterTriggers.firing_counter++;
4409 
4410  /* OK to delete the immediate events after processing them */
4411  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4412  break; /* all fired */
4413  }
4414  else
4415  break;
4416  }
4417 
4418  /* Release query-local storage for events, including tuplestore if any */
4420  if (fdw_tuplestore)
4421  {
4422  tuplestore_end(fdw_tuplestore);
4424  }
4426 
4428 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3812
CommandId firing_counter
Definition: trigger.c:3567
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4098
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndSubXact ( bool  isCommit)

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

4620 {
4621  int my_level = GetCurrentTransactionNestLevel();
4623  AfterTriggerEvent event;
4624  AfterTriggerEventChunk *chunk;
4625  CommandId subxact_firing_id;
4626 
4627  /*
4628  * Pop the prior state if needed.
4629  */
4630  if (isCommit)
4631  {
4632  Assert(my_level < afterTriggers.maxtransdepth);
4633  /* If we saved a prior state, we don't need it anymore */
4634  state = afterTriggers.state_stack[my_level];
4635  if (state != NULL)
4636  pfree(state);
4637  /* this avoids double pfree if error later: */
4638  afterTriggers.state_stack[my_level] = NULL;
4640  afterTriggers.depth_stack[my_level]);
4641  }
4642  else
4643  {
4644  /*
4645  * Aborting. It is possible subxact start failed before calling
4646  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4647  * stack levels that aren't there.
4648  */
4649  if (my_level >= afterTriggers.maxtransdepth)
4650  return;
4651 
4652  /*
4653  * Release any event lists from queries being aborted, and restore
4654  * query_depth to its pre-subxact value. This assumes that a
4655  * subtransaction will not add events to query levels started in a
4656  * earlier transaction state.
4657  */
4659  {
4661  {
4662  Tuplestorestate *ts;
4663 
4665  if (ts)
4666  {
4667  tuplestore_end(ts);
4669  }
4670 
4672  }
4673 
4675  }
4677  afterTriggers.depth_stack[my_level]);
4678 
4679  /*
4680  * Restore the global deferred-event list to its former length,
4681  * discarding any events queued by the subxact.
4682  */
4684  &afterTriggers.events_stack[my_level]);
4685 
4686  /*
4687  * Restore the trigger state. If the saved state is NULL, then this
4688  * subxact didn't save it, so it doesn't need restoring.
4689  */
4690  state = afterTriggers.state_stack[my_level];
4691  if (state != NULL)
4692  {
4694  afterTriggers.state = state;
4695  }
4696  /* this avoids double pfree if error later: */
4697  afterTriggers.state_stack[my_level] = NULL;
4698 
4699  /*
4700  * Scan for any remaining deferred events that were marked DONE or IN
4701  * PROGRESS by this subxact or a child, and un-mark them. We can
4702  * recognize such events because they have a firing ID greater than or
4703  * equal to the firing_counter value we saved at subtransaction start.
4704  * (This essentially assumes that the current subxact includes all
4705  * subxacts started after it.)
4706  */
4707  subxact_firing_id = afterTriggers.firing_stack[my_level];
4709  {
4710  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4711 
4712  if (event->ate_flags &
4714  {
4715  if (evtshared->ats_firing_id >= subxact_firing_id)
4716  event->ate_flags &=
4718  }
4719  }
4720  }
4721 }
uint32 CommandId
Definition: c.h:411
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3505
CommandId * firing_stack
Definition: trigger.c:3582
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3812
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Definition: regguts.h:298
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3835
CommandId ats_firing_id
Definition: trigger.c:3435
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3420
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndXact ( bool  isCommit)

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

4500 {
4501  /*
4502  * Forget the pending-events list.
4503  *
4504  * Since all the info is in TopTransactionContext or children thereof, we
4505  * don't really need to do anything to reclaim memory. However, the
4506  * pending-events list could be large, and so it's useful to discard it as
4507  * soon as possible --- especially if we are aborting because we ran out
4508  * of memory for the list!
4509  */
4511  {
4517  }
4518 
4519  /*
4520  * Forget any subtransaction state as well. Since this can't be very
4521  * large, we let the eventual reset of TopTransactionContext free the
4522  * memory instead of doing it here.
4523  */
4529 
4530 
4531  /*
4532  * Forget the query stack and constraint-related state information. As
4533  * with the subtransaction state information, we don't bother freeing the
4534  * memory here.
4535  */
4540 
4541  /* No more afterTriggers manipulation until next transaction starts. */
4543 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3492
MemoryContext event_cxt
Definition: trigger.c:3575
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
static void AfterTriggerEnlargeQueryState ( void  )
static

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

4734 {
4735  int init_depth = afterTriggers.maxquerydepth;
4736 
4738 
4739  if (afterTriggers.maxquerydepth == 0)
4740  {
4741  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4742 
4745  new_alloc * sizeof(AfterTriggerEventList));
4748  new_alloc * sizeof(Tuplestorestate *));
4749  afterTriggers.maxquerydepth = new_alloc;
4750  }
4751  else
4752  {
4753  /* repalloc will keep the stack in the same context */
4754  int old_alloc = afterTriggers.maxquerydepth;
4755  int new_alloc = Max(afterTriggers.query_depth + 1,
4756  old_alloc * 2);
4757 
4760  new_alloc * sizeof(AfterTriggerEventList));
4763  new_alloc * sizeof(Tuplestorestate *));
4764  /* Clear newly-allocated slots for subsequent lazy initialization. */
4765  memset(afterTriggers.fdw_tuplestores + old_alloc,
4766  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4767  afterTriggers.maxquerydepth = new_alloc;
4768  }
4769 
4770  /* Initialize new query lists to empty */
4771  while (init_depth < afterTriggers.maxquerydepth)
4772  {
4773  AfterTriggerEventList *events;
4774 
4775  events = &afterTriggers.query_stack[init_depth];
4776  events->head = NULL;
4777  events->tail = NULL;
4778  events->tailfree = NULL;
4779 
4780  ++init_depth;
4781  }
4782 }
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:742
#define Max(x, y)
Definition: c.h:800
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
AfterTriggerEventChunk * head
Definition: trigger.c:3492
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
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,
TransitionCaptureState transition_capture 
)
static

Definition at line 3890 of file trigger.c.

References AFTER_TRIGGER_2CTID, AFTER_TRIGGER_FDW_FETCH, AFTER_TRIGGER_FDW_REUSE, AFTER_TRIGGER_TUP_BITS, Assert, AfterTriggerEventData::ate_ctid1, AfterTriggerEventData::ate_ctid2, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_tgoid, elog, ERROR, ExecCallTriggerFunc(), ExecMaterializeSlot(), AfterTriggersData::fdw_tuplestores, GetTriggerSharedData, GetTriggerTransitionTuplestore(), heap_fetch(), heap_freetuple(), InstrStartNode(), InstrStopNode(), InvalidBuffer, ItemPointerCopy, ItemPointerIsValid, MemoryContextReset(), NULL, TriggerDesc::numtriggers, ReleaseBuffer(), SnapshotAny, HeapTupleData::t_self, T_TriggerData, TransitionCaptureState::tcs_insert_tuplestore, TransitionCaptureState::tcs_old_tuplestore, TransitionCaptureState::tcs_update_tuplestore, TriggerData::tg_event, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgnewtable, Trigger::tgoid, Trigger::tgoldtable, Trigger::tgtype, TRIGGER_EVENT_OPMASK, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TRIGGER_FOR_INSERT, TRIGGER_FOR_UPDATE, TriggerDesc::triggers, tuplestore_gettupleslot(), and TriggerData::type.

Referenced by afterTriggerInvokeEvents().

3897 {
3898  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3899  Oid tgoid = evtshared->ats_tgoid;
3900  TriggerData LocTriggerData;
3901  HeapTupleData tuple1;
3902  HeapTupleData tuple2;
3903  HeapTuple rettuple;
3904  Buffer buffer1 = InvalidBuffer;
3905  Buffer buffer2 = InvalidBuffer;
3906  int tgindx;
3907 
3908  /*
3909  * Locate trigger in trigdesc.
3910  */
3911  LocTriggerData.tg_trigger = NULL;
3912  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3913  {
3914  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3915  {
3916  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3917  break;
3918  }
3919  }
3920  if (LocTriggerData.tg_trigger == NULL)
3921  elog(ERROR, "could not find trigger %u", tgoid);
3922 
3923  /*
3924  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3925  * to include time spent re-fetching tuples in the trigger cost.
3926  */
3927  if (instr)
3928  InstrStartNode(instr + tgindx);
3929 
3930  /*
3931  * Fetch the required tuple(s).
3932  */
3933  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3934  {
3936  {
3937  Tuplestorestate *fdw_tuplestore =
3940 
3941  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3942  trig_tuple_slot1))
3943  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3944 
3945  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3947  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3948  trig_tuple_slot2))
3949  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3950  }
3951  /* fall through */
3953 
3954  /*
3955  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3956  * ensures that tg_trigtuple does not reference tuplestore memory.
3957  * (It is formally possible for the trigger function to queue
3958  * trigger events that add to the same tuplestore, which can push
3959  * other tuples out of memory.) The distinction is academic,
3960  * because we start with a minimal tuple that ExecFetchSlotTuple()
3961  * must materialize anyway.
3962  */
3963  LocTriggerData.tg_trigtuple =
3964  ExecMaterializeSlot(trig_tuple_slot1);
3965  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3966 
3967  LocTriggerData.tg_newtuple =
3968  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3970  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3971  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3972 
3973  break;
3974 
3975  default:
3976  if (ItemPointerIsValid(&(event->ate_ctid1)))
3977  {
3978  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3979  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3980  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3981  LocTriggerData.tg_trigtuple = &tuple1;
3982  LocTriggerData.tg_trigtuplebuf = buffer1;
3983  }
3984  else
3985  {
3986  LocTriggerData.tg_trigtuple = NULL;
3987  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3988  }
3989 
3990  /* don't touch ctid2 if not there */
3991  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3993  ItemPointerIsValid(&(event->ate_ctid2)))
3994  {
3995  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3996  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3997  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3998  LocTriggerData.tg_newtuple = &tuple2;
3999  LocTriggerData.tg_newtuplebuf = buffer2;
4000  }
4001  else
4002  {
4003  LocTriggerData.tg_newtuple = NULL;
4004  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
4005  }
4006  }
4007 
4008  /*
4009  * Set up the tuplestore information.
4010  */
4011  LocTriggerData.tg_oldtable = LocTriggerData.tg_newtable = NULL;
4012  if (transition_capture != NULL)
4013  {
4014  if (LocTriggerData.tg_trigger->tgoldtable)
4015  LocTriggerData.tg_oldtable = transition_capture->tcs_old_tuplestore;
4016  if (LocTriggerData.tg_trigger->tgnewtable)
4017  {
4018  /*
4019  * Currently a trigger with transition tables may only be defined
4020  * for a single event type (here AFTER INSERT or AFTER UPDATE, but
4021  * not AFTER INSERT OR ...).
4022  */
4023  Assert((TRIGGER_FOR_INSERT(LocTriggerData.tg_trigger->tgtype) != 0) ^
4024  (TRIGGER_FOR_UPDATE(LocTriggerData.tg_trigger->tgtype) != 0));
4025 
4026  /*
4027  * Show either the insert or update new tuple images, depending on
4028  * which event type the trigger was registered for. A single
4029  * statement may have produced both in the case of INSERT ... ON
4030  * CONFLICT ... DO UPDATE, and in that case the event determines
4031  * which tuplestore the trigger sees as the NEW TABLE.
4032  */
4033  if (TRIGGER_FOR_INSERT(LocTriggerData.tg_trigger->tgtype))
4034  LocTriggerData.tg_newtable =
4035  transition_capture->tcs_insert_tuplestore;
4036  else
4037  LocTriggerData.tg_newtable =
4038  transition_capture->tcs_update_tuplestore;
4039  }
4040  }
4041 
4042  /*
4043  * Setup the remaining trigger information
4044  */
4045  LocTriggerData.type = T_TriggerData;
4046  LocTriggerData.tg_event =
4048  LocTriggerData.tg_relation = rel;
4049 
4050  MemoryContextReset(per_tuple_context);
4051 
4052  /*
4053  * Call the trigger and throw away any possibly returned updated tuple.
4054  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
4055  */
4056  rettuple = ExecCallTriggerFunc(&LocTriggerData,
4057  tgindx,
4058  finfo,
4059  NULL,
4060  per_tuple_context);
4061  if (rettuple != NULL &&
4062  rettuple != LocTriggerData.tg_trigtuple &&
4063  rettuple != LocTriggerData.tg_newtuple)
4064  heap_freetuple(rettuple);
4065 
4066  /*
4067  * Release buffers
4068  */
4069  if (buffer1 != InvalidBuffer)
4070  ReleaseBuffer(buffer1);
4071  if (buffer2 != InvalidBuffer)
4072  ReleaseBuffer(buffer2);
4073 
4074  /*
4075  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
4076  * one "tuple returned" (really the number of firings).
4077  */
4078  if (instr)
4079  InstrStopNode(instr + tgindx, 1);
4080 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
TriggerEvent ats_event
Definition: trigger.c:3432
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3422
Tuplestorestate * tcs_update_tuplestore
Definition: trigger.h:86
ItemPointerData ate_ctid2
Definition: trigger.c:3445
TriggerFlags ate_flags
Definition: trigger.c:3443
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:1862
Oid tgoid
Definition: reltrigger.h:25
#define AFTER_TRIGGER_TUP_BITS
Definition: trigger.c:3426
#define InvalidBuffer
Definition: buf.h:25
#define TRIGGER_FOR_UPDATE(type)
Definition: pg_trigger.h:136
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:101
Tuplestorestate * tcs_old_tuplestore
Definition: trigger.h:84
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
#define ERROR
Definition: elog.h:43
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:63
int16 tgtype
Definition: reltrigger.h:29
ItemPointerData t_self
Definition: htup.h:65
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3425
int numtriggers
Definition: reltrigger.h:49
#define SnapshotAny
Definition: tqual.h:28
char * tgnewtable
Definition: reltrigger.h:43
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:1078
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_FOR_INSERT(type)
Definition: pg_trigger.h:134
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3606
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3423
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
Tuplestorestate * tcs_insert_tuplestore
Definition: trigger.h:85
NodeTag type
Definition: trigger.h:32
Tuplestorestate * tg_newtable
Definition: trigger.h:41
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
#define elog
Definition: elog.h:219
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2190
ItemPointerData ate_ctid1
Definition: trigger.c:3444
char * tgoldtable
Definition: reltrigger.h:42
int Buffer
Definition: buf.h:23
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:139
Relation tg_relation
Definition: trigger.h:34
void AfterTriggerFireDeferred ( void  )

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

4444 {
4445  AfterTriggerEventList *events;
4446  bool snap_pushed = false;
4447 
4448  /* Must not be inside a query */
4450 
4451  /*
4452  * If there are any triggers to fire, make sure we have set a snapshot for
4453  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4454  * can't assume ActiveSnapshot is valid on entry.)
4455  */
4456  events = &afterTriggers.events;
4457  if (events->head != NULL)
4458  {
4460  snap_pushed = true;
4461  }
4462 
4463  /*
4464  * Run all the remaining triggers. Loop until they are all gone, in case
4465  * some trigger queues more for us to do.
4466  */
4467  while (afterTriggerMarkEvents(events, NULL, false))
4468  {
4469  CommandId firing_id = afterTriggers.firing_counter++;
4470 
4471  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4472  break; /* all fired */
4473  }
4474 
4475  /*
4476  * We don't bother freeing the event list, since it will go away anyway
4477  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4478  */
4479 
4480  if (snap_pushed)
4482 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
CommandId firing_counter
Definition: trigger.c:3567
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3492
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4098
AfterTriggerEventList events
Definition: trigger.c:3569
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3812 of file trigger.c.

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

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

3813 {
3814  AfterTriggerEventChunk *chunk;
3815  AfterTriggerEventChunk *next_chunk;
3816 
3817  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3818  {
3819  next_chunk = chunk->next;
3820  pfree(chunk);
3821  }
3822  events->head = NULL;
3823  events->tail = NULL;
3824  events->tailfree = NULL;
3825 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
struct AfterTriggerEventChunk * next
Definition: trigger.c:3480
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3492
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

Definition at line 4170 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, AfterTriggerExecute(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, AfterTriggerSharedData::ats_transition_capture, CHUNK_DATA_START, CreateExecutorState(), CurrentMemoryContext, elog, AfterTriggerEventChunk::endfree, AfterTriggerEventChunk::endptr, ERROR, ExecCleanUpTriggerState(), ExecDropSingleTupleTableSlot(), ExecGetTriggerResultRel(), for_each_chunk, for_each_event, FreeExecutorState(), AfterTriggerEventChunk::freeptr, GetTriggerSharedData, MakeSingleTupleTableSlot(), MemoryContextDelete(), 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().

4174 {
4175  bool all_fired = true;
4176  AfterTriggerEventChunk *chunk;
4177  MemoryContext per_tuple_context;
4178  bool local_estate = false;
4179  Relation rel = NULL;
4180  TriggerDesc *trigdesc = NULL;
4181  FmgrInfo *finfo = NULL;
4182  Instrumentation *instr = NULL;
4183  TupleTableSlot *slot1 = NULL,
4184  *slot2 = NULL;
4185 
4186  /* Make a local EState if need be */
4187  if (estate == NULL)
4188  {
4189  estate = CreateExecutorState();
4190  local_estate = true;
4191  }
4192 
4193  /* Make a per-tuple memory context for trigger function calls */
4194  per_tuple_context =
4196  "AfterTriggerTupleContext",
4198 
4199  for_each_chunk(chunk, *events)
4200  {
4201  AfterTriggerEvent event;
4202  bool all_fired_in_chunk = true;
4203 
4204  for_each_event(event, chunk)
4205  {
4206  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4207 
4208  /*
4209  * Is it one for me to fire?
4210  */
4211  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
4212  evtshared->ats_firing_id == firing_id)
4213  {
4214  /*
4215  * So let's fire it... but first, find the correct relation if
4216  * this is not the same relation as before.
4217  */
4218  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
4219  {
4220  ResultRelInfo *rInfo;
4221 
4222  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
4223  rel = rInfo->ri_RelationDesc;
4224  trigdesc = rInfo->ri_TrigDesc;
4225  finfo = rInfo->ri_TrigFunctions;
4226  instr = rInfo->ri_TrigInstrument;
4227  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4228  {
4229  if (slot1 != NULL)
4230  {
4233  }
4234  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
4235  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
4236  }
4237  if (trigdesc == NULL) /* should not happen */
4238  elog(ERROR, "relation %u has no triggers",
4239  evtshared->ats_relid);
4240  }
4241 
4242  /*
4243  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
4244  * still set, so recursive examinations of the event list
4245  * won't try to re-fire it.
4246  */
4247  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
4248  per_tuple_context, slot1, slot2,
4249  evtshared->ats_transition_capture);
4250 
4251  /*
4252  * Mark the event as done.
4253  */
4254  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4255  event->ate_flags |= AFTER_TRIGGER_DONE;
4256  }
4257  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
4258  {
4259  /* something remains to be done */
4260  all_fired = all_fired_in_chunk = false;
4261  }
4262  }
4263 
4264  /* Clear the chunk if delete_ok and nothing left of interest */
4265  if (delete_ok && all_fired_in_chunk)
4266  {
4267  chunk->freeptr = CHUNK_DATA_START(chunk);
4268  chunk->endfree = chunk->endptr;
4269 
4270  /*
4271  * If it's last chunk, must sync event list's tailfree too. Note
4272  * that delete_ok must NOT be passed as true if there could be
4273  * stacked AfterTriggerEventList values pointing at this event
4274  * list, since we'd fail to fix their copies of tailfree.
4275  */
4276  if (chunk == events->tail)
4277  events->tailfree = chunk->freeptr;
4278  }
4279  }
4280  if (slot1 != NULL)
4281  {
4284  }
4285 
4286  /* Release working resources */
4287  MemoryContextDelete(per_tuple_context);
4288 
4289  if (local_estate)
4290  {
4291  ExecCleanUpTriggerState(estate);
4292  FreeExecutorState(estate);
4293  }
4294 
4295  return all_fired;
4296 }
Definition: fmgr.h:56
Relation ri_RelationDesc
Definition: execnodes.h:354
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3487
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
Form_pg_class rd_rel
Definition: rel.h:114
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, TransitionCaptureState *transition_capture)
Definition: trigger.c:3890
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
#define for_each_event(eptr, cptr)
Definition: trigger.c:3500
void FreeExecutorState(EState *estate)
Definition: execUtils.c:178
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
EState * CreateExecutorState(void)
Definition: execUtils.c:80
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid)
Definition: execMain.c:1379
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
TransitionCaptureState * ats_transition_capture
Definition: trigger.c:3436
TupleDesc rd_att
Definition: rel.h:115
#define for_each_chunk(cptr, evtlist)
Definition: trigger.c:3498
#define NULL
Definition: c.h:229
CommandId ats_firing_id
Definition: trigger.c:3435
void ExecCleanUpTriggerState(EState *estate)
Definition: execMain.c:1440
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3420
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:416
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

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

4101 {
4102  bool found = false;
4103  AfterTriggerEvent event;
4104  AfterTriggerEventChunk *chunk;
4105 
4106  for_each_event_chunk(event, chunk, *events)
4107  {
4108  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4109  bool defer_it = false;
4110 
4111  if (!(event->ate_flags &
4113  {
4114  /*
4115  * This trigger hasn't been called or scheduled yet. Check if we
4116  * should call it now.
4117  */
4118  if (immediate_only && afterTriggerCheckState(evtshared))
4119  {
4120  defer_it = true;
4121  }
4122  else
4123  {
4124  /*
4125  * Mark it as to be fired in this firing cycle.
4126  */
4128  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
4129  found = true;
4130  }
4131  }
4132 
4133  /*
4134  * If it's deferred, move it to move_list, if requested.
4135  */
4136  if (defer_it && move_list != NULL)
4137  {
4138  /* add it to move_list */
4139  afterTriggerAddEvent(move_list, event, evtshared);
4140  /* mark original copy "done" so we don't do it again */
4141  event->ate_flags |= AFTER_TRIGGER_DONE;
4142  }
4143  }
4144 
4145  return found;
4146 }
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3505
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3650
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
CommandId firing_counter
Definition: trigger.c:3567
#define NULL
Definition: c.h:229
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3696
CommandId ats_firing_id
Definition: trigger.c:3435
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3420
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
bool AfterTriggerPendingOnRel ( Oid  relid)

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

5158 {
5159  AfterTriggerEvent event;
5160  AfterTriggerEventChunk *chunk;
5161  int depth;
5162 
5163  /* Scan queued events */
5165  {
5166  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5167 
5168  /*
5169  * We can ignore completed events. (Even if a DONE flag is rolled
5170  * back by subxact abort, it's OK because the effects of the TRUNCATE
5171  * or whatever must get rolled back too.)
5172  */
5173  if (event->ate_flags & AFTER_TRIGGER_DONE)
5174  continue;
5175 
5176  if (evtshared->ats_relid == relid)
5177  return true;
5178  }
5179 
5180  /*
5181  * Also scan events queued by incomplete queries. This could only matter
5182  * if TRUNCATE/etc is executed by a function or trigger within an updating
5183  * query on the same relation, which is pretty perverse, but let's check.
5184  */
5185  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5186  {
5187  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
5188  {
5189  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5190 
5191  if (event->ate_flags & AFTER_TRIGGER_DONE)
5192  continue;
5193 
5194  if (evtshared->ats_relid == relid)
5195  return true;
5196  }
5197  }
5198 
5199  return false;
5200 }
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3505
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
static void afterTriggerRestoreEventList ( AfterTriggerEventList events,
const AfterTriggerEventList old_events 
)
static

Definition at line 3835 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

3837 {
3838  AfterTriggerEventChunk *chunk;
3839  AfterTriggerEventChunk *next_chunk;
3840 
3841  if (old_events->tail == NULL)
3842  {
3843  /* restoring to a completely empty state, so free everything */
3844  afterTriggerFreeEventList(events);
3845  }
3846  else
3847  {
3848  *events = *old_events;
3849  /* free any chunks after the last one we want to keep */
3850  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3851  {
3852  next_chunk = chunk->next;
3853  pfree(chunk);
3854  }
3855  /* and clean up the tail chunk to be the right length */
3856  events->tail->next = NULL;
3857  events->tail->freeptr = events->tailfree;
3858 
3859  /*
3860  * We don't make any effort to remove now-unused shared data records.
3861  * They might still be useful, anyway.
3862  */
3863  }
3864 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
struct AfterTriggerEventChunk * next
Definition: trigger.c:3480
void pfree(void *pointer)
Definition: mcxt.c:950
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3812
#define NULL
Definition: c.h:229
static void AfterTriggerSaveEvent ( EState estate,
ResultRelInfo relinfo,
int  event,
bool  row_trigger,
HeapTuple  oldtup,
HeapTuple  newtup,
List recheckIndexes,
Bitmapset modifiedCols,
TransitionCaptureState transition_capture 
)
static

Definition at line 5222 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, AfterTriggerSharedData::ats_transition_capture, do_convert_tuple(), elog, ERROR, AfterTriggersData::fdw_tuplestores, GetTriggerTransitionTuplestore(), i, ItemPointerCopy, ItemPointerSetInvalid, list_member_oid(), AfterTriggersData::maxquerydepth, NULL, TriggerDesc::numtriggers, pfree(), 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, TransitionCaptureState::tcs_delete_old_table, TransitionCaptureState::tcs_insert_new_table, TransitionCaptureState::tcs_insert_tuplestore, TransitionCaptureState::tcs_map, TransitionCaptureState::tcs_old_tuplestore, TransitionCaptureState::tcs_original_insert_tuple, TransitionCaptureState::tcs_update_new_table, TransitionCaptureState::tcs_update_old_table, TransitionCaptureState::tcs_update_tuplestore, Trigger::tgconstrindid, Trigger::tgdeferrable, Trigger::tgfoid, Trigger::tginitdeferred, Trigger::tgoid, Trigger::tgtype, TriggerDesc::trig_delete_after_row, TriggerDesc::trig_insert_after_row, TriggerDesc::trig_update_after_row, 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().

5227 {
5228  Relation rel = relinfo->ri_RelationDesc;
5229  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
5230  AfterTriggerEventData new_event;
5231  AfterTriggerSharedData new_shared;
5232  char relkind = relinfo->ri_RelationDesc->rd_rel->relkind;
5233  int tgtype_event;
5234  int tgtype_level;
5235  int i;
5236  Tuplestorestate *fdw_tuplestore = NULL;
5237 
5238  /*
5239  * Check state. We use a normal test not Assert because it is possible to
5240  * reach here in the wrong state given misconfigured RI triggers, in
5241  * particular deferring a cascade action trigger.
5242  */
5243  if (afterTriggers.query_depth < 0)
5244  elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
5245 
5246  /* Be sure we have enough space to record events at this query depth. */
5249 
5250  /*
5251  * If the directly named relation has any triggers with transition tables,
5252  * then we need to capture transition tuples.
5253  */
5254  if (row_trigger && transition_capture != NULL)
5255  {
5256  HeapTuple original_insert_tuple = transition_capture->tcs_original_insert_tuple;
5257  TupleConversionMap *map = transition_capture->tcs_map;
5258  bool delete_old_table = transition_capture->tcs_delete_old_table;
5259  bool update_old_table = transition_capture->tcs_update_old_table;
5260  bool update_new_table = transition_capture->tcs_update_new_table;
5261  bool insert_new_table = transition_capture->tcs_insert_new_table;;
5262 
5263  if ((event == TRIGGER_EVENT_DELETE && delete_old_table) ||
5264  (event == TRIGGER_EVENT_UPDATE && update_old_table))
5265  {
5266  Tuplestorestate *old_tuplestore;
5267 
5268  Assert(oldtup != NULL);
5269  old_tuplestore = transition_capture->tcs_old_tuplestore;
5270 
5271  if (map != NULL)
5272  {
5273  HeapTuple converted = do_convert_tuple(oldtup, map);
5274 
5275  tuplestore_puttuple(old_tuplestore, converted);
5276  pfree(converted);
5277  }
5278  else
5279  tuplestore_puttuple(old_tuplestore, oldtup);
5280  }
5281  if ((event == TRIGGER_EVENT_INSERT && insert_new_table) ||
5282  (event == TRIGGER_EVENT_UPDATE && update_new_table))
5283  {
5284  Tuplestorestate *new_tuplestore;
5285 
5286  Assert(newtup != NULL);
5287  if (event == TRIGGER_EVENT_INSERT)
5288  new_tuplestore = transition_capture->tcs_insert_tuplestore;
5289  else
5290  new_tuplestore = transition_capture->tcs_update_tuplestore;
5291 
5292  if (original_insert_tuple != NULL)
5293  tuplestore_puttuple(new_tuplestore, original_insert_tuple);
5294  else if (map != NULL)
5295  {
5296  HeapTuple converted = do_convert_tuple(newtup, map);
5297 
5298  tuplestore_puttuple(new_tuplestore, converted);
5299  pfree(converted);
5300  }
5301  else
5302  tuplestore_puttuple(new_tuplestore, newtup);
5303  }
5304 
5305  /* If transition tables are the only reason we're here, return. */
5306  if (trigdesc == NULL ||
5307  (event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) ||
5308  (event == TRIGGER_EVENT_INSERT && !trigdesc->trig_insert_after_row) ||
5309  (event == TRIGGER_EVENT_UPDATE && !trigdesc->trig_update_after_row))
5310  return;
5311  }
5312 
5313  /*
5314  * Validate the event code and collect the associated tuple CTIDs.
5315  *
5316  * The event code will be used both as a bitmask and an array offset, so
5317  * validation is important to make sure we don't walk off the edge of our
5318  * arrays.
5319  */
5320  switch (event)
5321  {
5322  case TRIGGER_EVENT_INSERT:
5323  tgtype_event = TRIGGER_TYPE_INSERT;
5324  if (row_trigger)
5325  {
5326  Assert(oldtup == NULL);
5327  Assert(newtup != NULL);
5328  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
5329  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5330  }
5331  else
5332  {
5333  Assert(oldtup == NULL);
5334  Assert(newtup == NULL);
5335  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5336  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5337  }
5338  break;
5339  case TRIGGER_EVENT_DELETE:
5340  tgtype_event = TRIGGER_TYPE_DELETE;
5341  if (row_trigger)
5342  {
5343  Assert(oldtup != NULL);
5344  Assert(newtup == NULL);
5345  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5346  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5347  }
5348  else
5349  {
5350  Assert(oldtup == NULL);
5351  Assert(newtup == NULL);
5352  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5353  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5354  }
5355  break;
5356  case TRIGGER_EVENT_UPDATE:
5357  tgtype_event = TRIGGER_TYPE_UPDATE;
5358  if (row_trigger)
5359  {
5360  Assert(oldtup != NULL);
5361  Assert(newtup != NULL);
5362  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5363  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
5364  }
5365  else
5366  {
5367  Assert(oldtup == NULL);
5368  Assert(newtup == NULL);
5369  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5370  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5371  }
5372  break;
5374  tgtype_event = TRIGGER_TYPE_TRUNCATE;
5375  Assert(oldtup == NULL);
5376  Assert(newtup == NULL);
5377  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5378  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5379  break;
5380  default:
5381  elog(ERROR, "invalid after-trigger event code: %d", event);
5382  tgtype_event = 0; /* keep compiler quiet */
5383  break;
5384  }
5385 
5386  if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
5387  new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
5389  /* else, we'll initialize ate_flags for each trigger */
5390 
5391  tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
5392 
5393  for (i = 0; i < trigdesc->numtriggers; i++)
5394  {
5395  Trigger *trigger = &trigdesc->triggers[i];
5396 
5397  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
5398  tgtype_level,
5400  tgtype_event))
5401  continue;
5402  if (!TriggerEnabled(estate, relinfo, trigger, event,
5403  modifiedCols, oldtup, newtup))
5404  continue;
5405 
5406  if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
5407  {
5408  if (fdw_tuplestore == NULL)
5409  {
5410  fdw_tuplestore =
5413  new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
5414  }
5415  else
5416  /* subsequent event for the same tuple */
5417  new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
5418  }
5419 
5420  /*
5421  * If the trigger is a foreign key enforcement trigger, there are
5422  * certain cases where we can skip queueing the event because we can
5423  * tell by inspection that the FK constraint will still pass.
5424  */
5425  if (TRIGGER_FIRED_BY_UPDATE(event))
5426  {
5427  switch (RI_FKey_trigger_type(trigger->tgfoid))
5428  {
5429  case RI_TRIGGER_PK:
5430  /* Update on trigger's PK table */
5431  if (!RI_FKey_pk_upd_check_required(trigger, rel,
5432  oldtup, newtup))
5433  {
5434  /* skip queuing this event */
5435  continue;
5436  }
5437  break;
5438 
5439  case RI_TRIGGER_FK:
5440  /* Update on trigger's FK table */
5441  if (!RI_FKey_fk_upd_check_required(trigger, rel,
5442  oldtup, newtup))
5443  {
5444  /* skip queuing this event */
5445  continue;
5446  }
5447  break;
5448 
5449  case RI_TRIGGER_NONE:
5450  /* Not an FK trigger */
5451  break;
5452  }
5453  }
5454 
5455  /*
5456  * If the trigger is a deferred unique constraint check trigger, only
5457  * queue it if the unique constraint was potentially violated, which
5458  * we know from index insertion time.
5459  */
5460  if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
5461  {
5462  if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
5463  continue; /* Uniqueness definitely not violated */
5464  }
5465 
5466  /*
5467  * Fill in event structure and add it to the current query's queue.
5468  */
5469  new_shared.ats_event =
5470  (event & TRIGGER_EVENT_OPMASK) |
5471  (row_trigger ? TRIGGER_EVENT_ROW : 0) |
5472  (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
5473  (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
5474  new_shared.ats_tgoid = trigger->tgoid;
5475  new_shared.ats_relid = RelationGetRelid(rel);
5476  new_shared.ats_firing_id = 0;
5477  new_shared.ats_transition_capture = transition_capture;
5478 
5480  &new_event, &new_shared);
5481  }
5482 
5483  /*
5484  * Finally, spool any foreign tuple(s). The tuplestore squashes them to
5485  * minimal tuples, so this loses any system columns. The executor lost
5486  * those columns before us, for an unrelated reason, so this is fine.
5487  */
5488  if (fdw_tuplestore)
5489  {
5490  if (oldtup != NULL)
5491  tuplestore_puttuple(fdw_tuplestore, oldtup);
5492  if (newtup != NULL)
5493  tuplestore_puttuple(fdw_tuplestore, newtup);
5494  }
5495 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
TriggerEvent ats_event
Definition: trigger.c:3432
Relation ri_RelationDesc
Definition: execnodes.h:354
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3701
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3422
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:113
Tuplestorestate * tcs_update_tuplestore
Definition: trigger.h:86
ItemPointerData ate_ctid2
Definition: trigger.c:3445
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
Oid tgfoid
Definition: reltrigger.h:28
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:112
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Oid tgoid
Definition: reltrigger.h:25
Form_pg_class rd_rel
Definition: rel.h:114
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:101
Tuplestorestate * tcs_old_tuplestore
Definition: trigger.h:84
HeapTuple tcs_original_insert_tuple
Definition: trigger.h:74
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
TupleConversionMap * tcs_map
Definition: trigger.h:65
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:730
bool trig_delete_after_row
Definition: reltrigger.h:66
Trigger * triggers
Definition: reltrigger.h:48
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
bool trig_insert_after_row
Definition: reltrigger.h:56
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3424
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3425
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
bool trig_update_after_row
Definition: reltrigger.h:61
int numtriggers
Definition: reltrigger.h:49
TransitionCaptureState * ats_transition_capture
Definition: trigger.c:3436
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, HeapTuple old_row, HeapTuple new_row)
Definition: ri_triggers.c:2141
#define TRIGGER_TYPE_TRUNCATE
Definition: pg_trigger.h:103
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:102
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3200
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4733
#define RI_TRIGGER_FK
Definition: trigger.h:265
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3696
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:100
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:2084
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3606
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3423
CommandId ats_firing_id
Definition: trigger.c:3435
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:343
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
Tuplestorestate * tcs_insert_tuplestore
Definition: trigger.h:85
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
#define RI_TRIGGER_PK
Definition: trigger.h:264
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
int i
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
#define elog
Definition: elog.h:219
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
ItemPointerData ate_ctid1
Definition: trigger.c:3444
#define RI_TRIGGER_NONE
Definition: trigger.h:266
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:121
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
#define RelationGetRelid(relation)
Definition: rel.h:416
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:139
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

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

4864 {
4865  int my_level = GetCurrentTransactionNestLevel();
4866 
4867  /* If we haven't already done so, initialize our state. */
4868  if (afterTriggers.state == NULL)
4870 
4871  /*
4872  * If in a subtransaction, and we didn't save the current state already,
4873  * save it so it can be restored if the subtransaction aborts.
4874  */
4875  if (my_level > 1 &&
4876  afterTriggers.state_stack[my_level] == NULL)
4877  {
4878  afterTriggers.state_stack[my_level] =
4880  }
4881 
4882  /*
4883  * Handle SET CONSTRAINTS ALL ...
4884  */
4885  if (stmt->constraints == NIL)
4886  {
4887  /*
4888  * Forget any previous SET CONSTRAINTS commands in this transaction.
4889  */
4891 
4892  /*
4893  * Set the per-transaction ALL state to known.
4894  */
4895  afterTriggers.state->all_isset = true;
4897  }
4898  else
4899  {
4900  Relation conrel;
4901  Relation tgrel;
4902  List *conoidlist = NIL;
4903  List *tgoidlist = NIL;
4904  ListCell *lc;
4905 
4906  /*
4907  * Handle SET CONSTRAINTS constraint-name [, ...]
4908  *
4909  * First, identify all the named constraints and make a list of their
4910  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4911  * the same name within a schema, the specifications are not
4912  * necessarily unique. Our strategy is to target all matching
4913  * constraints within the first search-path schema that has any
4914  * matches, but disregard matches in schemas beyond the first match.
4915  * (This is a bit odd but it's the historical behavior.)
4916  */
4918 
4919  foreach(lc, stmt->constraints)
4920  {
4921  RangeVar *constraint = lfirst(lc);
4922  bool found;
4923  List *namespacelist;
4924  ListCell *nslc;
4925 
4926  if (constraint->catalogname)
4927  {
4928  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4929  ereport(ERROR,
4930  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4931  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4932  constraint->catalogname, constraint->schemaname,
4933  constraint->relname)));
4934  }
4935 
4936  /*
4937  * If we're given the schema name with the constraint, look only
4938  * in that schema. If given a bare constraint name, use the
4939  * search path to find the first matching constraint.
4940  */
4941  if (constraint->schemaname)
4942  {
4943  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4944  false);
4945 
4946  namespacelist = list_make1_oid(namespaceId);
4947  }
4948  else
4949  {
4950  namespacelist = fetch_search_path(true);
4951  }
4952 
4953  found = false;
4954  foreach(nslc, namespacelist)
4955  {
4956  Oid namespaceId = lfirst_oid(nslc);
4957  SysScanDesc conscan;
4958  ScanKeyData skey[2];
4959  HeapTuple tup;
4960 
4961  ScanKeyInit(&skey[0],
4963  BTEqualStrategyNumber, F_NAMEEQ,
4964  CStringGetDatum(constraint->relname));
4965  ScanKeyInit(&skey[1],
4967  BTEqualStrategyNumber, F_OIDEQ,
4968  ObjectIdGetDatum(namespaceId));
4969 
4970  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4971  true, NULL, 2, skey);
4972 
4973  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4974  {
4976 
4977  if (con->condeferrable)
4978  conoidlist = lappend_oid(conoidlist,
4979  HeapTupleGetOid(tup));
4980  else if (stmt->deferred)
4981  ereport(ERROR,
4982  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4983  errmsg("constraint \"%s\" is not deferrable",
4984  constraint->relname)));
4985  found = true;
4986  }
4987 
4988  systable_endscan(conscan);
4989 
4990  /*
4991  * Once we've found a matching constraint we do not search
4992  * later parts of the search path.
4993  */
4994  if (found)
4995  break;
4996  }
4997 
4998  list_free(namespacelist);
4999 
5000  /*
5001  * Not found ?
5002  */
5003  if (!found)
5004  ereport(ERROR,
5005  (errcode(ERRCODE_UNDEFINED_OBJECT),
5006  errmsg("constraint \"%s\" does not exist",
5007  constraint->relname)));
5008  }
5009 
5010  heap_close(conrel, AccessShareLock);
5011 
5012  /*
5013  * Now, locate the trigger(s) implementing each of these constraints,
5014  * and make a list of their OIDs.
5015  */
5017 
5018  foreach(lc, conoidlist)
5019  {
5020  Oid conoid = lfirst_oid(lc);
5021  bool found;
5022  ScanKeyData skey;
5023  SysScanDesc tgscan;
5024  HeapTuple htup;
5025 
5026  found = false;
5027 
5028  ScanKeyInit(&skey,
5030  BTEqualStrategyNumber, F_OIDEQ,
5031  ObjectIdGetDatum(conoid));
5032 
5033  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
5034  NULL, 1, &skey);
5035 
5036  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
5037  {
5038  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
5039 
5040  /*
5041  * Silently skip triggers that are marked as non-deferrable in
5042  * pg_trigger. This is not an error condition, since a
5043  * deferrable RI constraint may have some non-deferrable
5044  * actions.
5045  */
5046  if (pg_trigger->tgdeferrable)
5047  tgoidlist = lappend_oid(tgoidlist,
5048  HeapTupleGetOid(htup));
5049 
5050  found = true;
5051  }
5052 
5053  systable_endscan(tgscan);
5054 
5055  /* Safety check: a deferrable constraint should have triggers */
5056  if (!found)
5057  elog(ERROR, "no triggers found for constraint with OID %u",
5058  conoid);
5059  }
5060 
5061  heap_close(tgrel, AccessShareLock);
5062 
5063  /*
5064  * Now we can set the trigger states of individual triggers for this
5065  * xact.
5066  */
5067  foreach(lc, tgoidlist)
5068  {
5069  Oid tgoid = lfirst_oid(lc);
5071  bool found = false;
5072  int i;
5073 
5074  for (i = 0; i < state->numstates; i++)
5075  {
5076  if (state->trigstates[i].sct_tgoid == tgoid)
5077  {
5078  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5079  found = true;
5080  break;
5081  }
5082  }
5083  if (!found)
5084  {
5086  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
5087  }
5088  }
5089  }
5090 
5091  /*
5092  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
5093  * checks against that constraint must be made when the SET CONSTRAINTS
5094  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
5095  * apply retroactively. We've updated the constraints state, so scan the
5096  * list of previously deferred events to fire any that have now become
5097  * immediate.
5098  *
5099  * Obviously, if this was SET ... DEFERRED then it can't have converted
5100  * any unfired events to immediate, so we need do nothing in that case.
5101  */
5102  if (!stmt->deferred)
5103  {
5105  bool snapshot_set = false;
5106 
5107  while (afterTriggerMarkEvents(events, NULL, true))
5108  {
5109  CommandId firing_id = afterTriggers.firing_counter++;
5110 
5111  /*
5112  * Make sure a snapshot has been established in case trigger
5113  * functions need one. Note that we avoid setting a snapshot if
5114  * we don't find at least one trigger that has to be fired now.
5115  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
5116  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
5117  * at the start of a transaction it's not possible for any trigger
5118  * events to be queued yet.)
5119  */
5120  if (!snapshot_set)
5121  {
5123  snapshot_set = true;
5124  }
5125 
5126  /*
5127  * We can delete fired events if we are at top transaction level,
5128  * but we'd better not if inside a subtransaction, since the
5129  * subtransaction could later get rolled back.
5130  */
5131  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5132  !IsSubTransaction()))
5133  break; /* all fired */
5134  }
5135 
5136  if (snapshot_set)
5138  }
5139 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:411
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2853
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:87
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3380
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
Definition: trigger.c:4833
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_constraint_conname
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
char * schemaname
Definition: primnodes.h:67
char * relname
Definition: primnodes.h:68
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
#define CStringGetDatum(X)
Definition: postgres.h:584
#define TriggerConstraintIndexId
Definition: indexing.h:247
#define ereport(elevel, rest)
Definition: elog.h:122
static SetConstraintState SetConstraintStateCreate(int numalloc)
Definition: trigger.c:4788
#define list_make1_oid(x1)
Definition: pg_list.h:151
Oid MyDatabaseId
Definition: globals.c:77
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
CommandId firing_counter
Definition: trigger.c:3567
#define ConstraintNameNspIndexId
Definition: indexing.h:124
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Definition: regguts.h:298
#define TriggerRelationId
Definition: pg_trigger.h:34
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
bool IsSubTransaction(void)
Definition: xact.c:4377
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
int i
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4098
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3569
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Definition: pg_list.h:45
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4168
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
char * catalogname
Definition: primnodes.h:66
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:4813
static void ConvertTriggerToFK ( CreateTrigStmt stmt,
Oid  funcoid 
)
static

Definition at line 993 of file trigger.c.

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, OldTriggerInfo::args, CreateTrigStmt::args, AT_AddConstraint, buf, PlannedStmt::canSetTag, CMD_UTILITY, AlterTableStmt::cmds, PlannedStmt::commandType, 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, PlannedStmt::stmt_len, PlannedStmt::stmt_location, strVal, AlterTableCmd::subtype, TopMemoryContext, and PlannedStmt::utilityStmt.

Referenced by CreateTrigger().

994 {
995  static List *info_list = NIL;
996 
997  static const char *const funcdescr[3] = {
998  gettext_noop("Found referenced table's UPDATE trigger."),
999  gettext_noop("Found referenced table's DELETE trigger."),
1000  gettext_noop("Found referencing table's trigger.")
1001  };
1002 
1003  char *constr_name;
1004  char *fk_table_name;
1005  char *pk_table_name;
1006  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
1007  List *fk_attrs = NIL;
1008  List *pk_attrs = NIL;
1010  int funcnum;
1011  OldTriggerInfo *info = NULL;
1012  ListCell *l;
1013  int i;
1014 
1015  /* Parse out the trigger arguments */
1016  constr_name = strVal(linitial(stmt->args));
1017  fk_table_name = strVal(lsecond(stmt->args));
1018  pk_table_name = strVal(lthird(stmt->args));
1019  i = 0;
1020  foreach(l, stmt->args)
1021  {
1022  Value *arg = (Value *) lfirst(l);
1023 
1024  i++;
1025  if (i < 4) /* skip constraint and table names */
1026  continue;
1027  if (i == 4) /* handle match type */
1028  {
1029  if (strcmp(strVal(arg), "FULL") == 0)
1030  fk_matchtype = FKCONSTR_MATCH_FULL;
1031  else
1032  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
1033  continue;
1034  }
1035  if (i % 2)
1036  fk_attrs = lappend(fk_attrs, arg);
1037  else
1038  pk_attrs = lappend(pk_attrs, arg);
1039  }
1040 
1041  /* Prepare description of constraint for use in messages */
1042  initStringInfo(&buf);
1043  appendStringInfo(&buf, "FOREIGN KEY %s(",
1044  quote_identifier(fk_table_name));
1045  i = 0;
1046  foreach(l, fk_attrs)
1047  {
1048  Value *arg = (Value *) lfirst(l);
1049 
1050  if (i++ > 0)
1051  appendStringInfoChar(&buf, ',');
1053  }
1054  appendStringInfo(&buf, ") REFERENCES %s(",
1055  quote_identifier(pk_table_name));
1056  i = 0;
1057  foreach(l, pk_attrs)
1058  {
1059  Value *arg = (Value *) lfirst(l);
1060 
1061  if (i++ > 0)
1062  appendStringInfoChar(&buf, ',');
1064  }
1065  appendStringInfoChar(&buf, ')');
1066 
1067  /* Identify class of trigger --- update, delete, or referencing-table */
1068  switch (funcoid)
1069  {
1070  case F_RI_FKEY_CASCADE_UPD:
1071  case F_RI_FKEY_RESTRICT_UPD:
1072  case F_RI_FKEY_SETNULL_UPD:
1073  case F_RI_FKEY_SETDEFAULT_UPD:
1074  case F_RI_FKEY_NOACTION_UPD:
1075  funcnum = 0;
1076  break;
1077 
1078  case F_RI_FKEY_CASCADE_DEL:
1079  case F_RI_FKEY_RESTRICT_DEL:
1080  case F_RI_FKEY_SETNULL_DEL:
1081  case F_RI_FKEY_SETDEFAULT_DEL:
1082  case F_RI_FKEY_NOACTION_DEL:
1083  funcnum = 1;
1084  break;
1085 
1086  default:
1087  funcnum = 2;
1088  break;
1089  }
1090 
1091  /* See if we have a match to this trigger */
1092  foreach(l, info_list)
1093  {
1094  info = (OldTriggerInfo *) lfirst(l);
1095  if (info->funcoids[funcnum] == InvalidOid &&
1096  equal(info->args, stmt->args))
1097  {
1098  info->funcoids[funcnum] = funcoid;
1099  break;
1100  }
1101  }
1102 
1103  if (l == NULL)
1104  {
1105  /* First trigger of set, so create a new list entry */
1106  MemoryContext oldContext;
1107 
1108  ereport(NOTICE,
1109  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1110  constr_name, buf.data),
1111  errdetail_internal("%s", _(funcdescr[funcnum]))));
1113  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
1114  info->args = copyObject(stmt->args);
1115  info->funcoids[funcnum] = funcoid;
1116  info_list = lappend(info_list, info);
1117  MemoryContextSwitchTo(oldContext);
1118  }
1119  else if (info->funcoids[0] == InvalidOid ||
1120  info->funcoids[1] == InvalidOid ||
1121  info->funcoids[2] == InvalidOid)
1122  {
1123  /* Second trigger of set */
1124  ereport(NOTICE,
1125  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1126  constr_name, buf.data),
1127  errdetail_internal("%s", _(funcdescr[funcnum]))));
1128  }
1129  else
1130  {
1131  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
1134  Constraint *fkcon = makeNode(Constraint);
1135  PlannedStmt *wrapper = makeNode(PlannedStmt);
1136 
1137  ereport(NOTICE,
1138  (errmsg("converting trigger group into constraint \"%s\" %s",
1139  constr_name, buf.data),
1140  errdetail_internal("%s", _(funcdescr[funcnum]))));
1141  fkcon->contype = CONSTR_FOREIGN;
1142  fkcon->location = -1;
1143  if (funcnum == 2)
1144  {
1145  /* This trigger is on the FK table */
1146  atstmt->relation = stmt->relation;
1147  if (stmt->constrrel)
1148  fkcon->pktable = stmt->constrrel;
1149  else
1150  {
1151  /* Work around ancient pg_dump bug that omitted constrrel */
1152  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
1153  }
1154  }
1155  else
1156  {
1157  /* This trigger is on the PK table */
1158  fkcon->pktable = stmt->relation;
1159  if (stmt->constrrel)
1160  atstmt->relation = stmt->constrrel;
1161  else
1162  {
1163  /* Work around ancient pg_dump bug that omitted constrrel */
1164  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1165  }
1166  }
1167  atstmt->cmds = list_make1(atcmd);
1168  atstmt->relkind = OBJECT_TABLE;
1169  atcmd->subtype = AT_AddConstraint;
1170  atcmd->def = (Node *) fkcon;
1171  if (strcmp(constr_name, "<unnamed>") == 0)
1172  fkcon->conname = NULL;
1173  else
1174  fkcon->conname = constr_name;
1175  fkcon->fk_attrs = fk_attrs;
1176  fkcon->pk_attrs = pk_attrs;
1177  fkcon->fk_matchtype = fk_matchtype;
1178  switch (info->funcoids[0])
1179  {
1180  case F_RI_FKEY_NOACTION_UPD:
1182  break;
1183  case F_RI_FKEY_CASCADE_UPD:
1185  break;
1186  case F_RI_FKEY_RESTRICT_UPD:
1188  break;
1189  case F_RI_FKEY_SETNULL_UPD:
1191  break;
1192  case F_RI_FKEY_SETDEFAULT_UPD:
1194  break;
1195  default:
1196  /* can't get here because of earlier checks */
1197  elog(ERROR, "confused about RI update function");
1198  }
1199  switch (info->funcoids[1])
1200  {
1201  case F_RI_FKEY_NOACTION_DEL:
1203  break;
1204  case F_RI_FKEY_CASCADE_DEL:
1206  break;
1207  case F_RI_FKEY_RESTRICT_DEL:
1209  break;
1210  case F_RI_FKEY_SETNULL_DEL:
1212  break;
1213  case F_RI_FKEY_SETDEFAULT_DEL:
1215  break;
1216  default:
1217  /* can't get here because of earlier checks */
1218  elog(ERROR, "confused about RI delete function");
1219  }
1220  fkcon->deferrable = stmt->deferrable;
1221  fkcon->initdeferred = stmt->initdeferred;
1222  fkcon->skip_validation = false;
1223  fkcon->initially_valid = true;
1224 
1225  /* finally, wrap it in a dummy PlannedStmt */
1226  wrapper->commandType = CMD_UTILITY;
1227  wrapper->canSetTag = false;
1228  wrapper->utilityStmt = (Node *) atstmt;
1229  wrapper->stmt_location = -1;
1230  wrapper->stmt_len = -1;
1231 
1232  /* ... and execute it */
1233  ProcessUtility(wrapper,
1234  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1236  None_Receiver, NULL);
1237 
1238  /* Remove the matched item from the list */
1239  info_list = list_delete_ptr(info_list, info);
1240  pfree(info);
1241  /* We leak the copied args ... not worth worrying about */
1242  }
1243 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2068
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10404
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2059
char fk_matchtype
Definition: parsenodes.h:2105
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2063
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:509
#define strVal(v)
Definition: value.h:54
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:335
bool initdeferred
Definition: parsenodes.h:2078
AlterTableType subtype
Definition: parsenodes.h:1772
List * pk_attrs
Definition: parsenodes.h:2104
char * conname
Definition: parsenodes.h:2076
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
DestReceiver * None_Receiver
Definition: dest.c:91
int stmt_len
Definition: plannodes.h:98
#define lsecond(l)
Definition: pg_list.h:116
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
#define list_make1(x1)
Definition: pg_list.h:139
RangeVar * constrrel
Definition: parsenodes.h:2363
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2077
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int stmt_location
Definition: plannodes.h:97
static char * buf
Definition: pg_test_fsync.c:66
Node * utilityStmt
Definition: plannodes.h:94
Oid funcoids[3]
Definition: trigger.c:988
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1687
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2061
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2066
bool canSetTag
Definition: plannodes.h:53
void * palloc0(Size size)
Definition: mcxt.c:878
CmdType commandType
Definition: plannodes.h:45
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2114
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:557
char fk_del_action
Definition: parsenodes.h:2107
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:987
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1685
int i
RangeVar * relation
Definition: parsenodes.h:2347
ConstrType contype
Definition: parsenodes.h:2073
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2060
#define lthird(l)
Definition: pg_list.h:121
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
RangeVar * pktable
Definition: parsenodes.h:2102
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2062
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:2113
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:2103
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:2106
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1885 of file trigger.c.

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

Referenced by InitResultRelInfo(), and RelationBuildTriggers().

1886 {
1887  TriggerDesc *newdesc;
1888  Trigger *trigger;
1889  int i;
1890 
1891  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1892  return NULL;
1893 
1894  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1895  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1896 
1897  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1898  memcpy(trigger, trigdesc->triggers,
1899  trigdesc->numtriggers * sizeof(Trigger));
1900  newdesc->triggers = trigger;
1901 
1902  for (i = 0; i < trigdesc->numtriggers; i++)
1903  {
1904  trigger->tgname = pstrdup(trigger->tgname);
1905  if (trigger->tgnattr > 0)
1906  {
1907  int16 *newattr;
1908 
1909  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1910  memcpy(newattr, trigger->tgattr,
1911  trigger->tgnattr * sizeof(int16));
1912  trigger->tgattr = newattr;
1913  }
1914  if (trigger->tgnargs > 0)
1915  {
1916  char **newargs;
1917  int16 j;
1918 
1919  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1920  for (j = 0; j < trigger->tgnargs; j++)
1921  newargs[j] = pstrdup(trigger->tgargs[j]);
1922  trigger->tgargs = newargs;
1923  }
1924  if (trigger->tgqual)
1925  trigger->tgqual = pstrdup(trigger->tgqual);
1926  if (trigger->tgoldtable)
1927  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1928  if (trigger->tgnewtable)
1929  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1930  trigger++;
1931  }
1932 
1933  return newdesc;
1934 }
signed short int16
Definition: c.h:255
char * pstrdup(const char *in)
Definition: mcxt.c:1077
char * tgqual
Definition: reltrigger.h:41
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char ** tgargs
Definition: reltrigger.h:40
int16 * tgattr
Definition: reltrigger.h:39
char * tgnewtable
Definition: reltrigger.h:43
#define NULL
Definition: c.h:229
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:849
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42
ObjectAddress CreateTrigger ( CreateTrigStmt stmt,
const char *  queryString,
Oid  relOid,
Oid  refRelOid,
Oid  constraintOid,
Oid  indexOid,
bool  isInternal 
)

Definition at line 140 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_tgnewtable, Anum_pg_trigger_tgoldtable, Anum_pg_trigger_tgqual, Anum_pg_trigger_tgrelid, Anum_pg_trigger_tgtype, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CONSTRAINT_TRIGGER, ConstraintRelationId, CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject, CreateConstraintEntry(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), GetNewOid(), GETSTRUCT, GetUserId(), has_superclass(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleIsValid, HeapTupleSetOid, i, CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, lfirst, lfirst_node, list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), name, TriggerTransition::name, NAMEDATALEN, namein(), NameListToString(), namestrcmp(), Natts_pg_trigger, NIL, nodeToString(), NoLock, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPAQUEOID, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, ProcedureRelationId, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_id, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, snprintf(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, 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_FOR_UPDATE, 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().

143 {
144  int16 tgtype;
145  int ncolumns;
146  int16 *columns;
147  int2vector *tgattr;
148  Node *whenClause;
149  List *whenRtable;
150  char *qual;
152  bool nulls[Natts_pg_trigger];
153  Relation rel;
154  AclResult aclresult;
155  Relation tgrel;
156  SysScanDesc tgscan;
157  ScanKeyData key;
158  Relation pgrel;
159  HeapTuple tuple;
160  Oid fargtypes[1]; /* dummy */
161  Oid funcoid;
162  Oid funcrettype;
163  Oid trigoid;
164  char internaltrigname[NAMEDATALEN];
165  char *trigname;
166  Oid constrrelid = InvalidOid;
167  ObjectAddress myself,
168  referenced;
169  char *oldtablename = NULL;
170  char *newtablename = NULL;
171 
172  if (OidIsValid(relOid))
173  rel = heap_open(relOid, ShareRowExclusiveLock);
174  else
176 
177  /*
178  * Triggers must be on tables or views, and there are additional
179  * relation-type-specific restrictions.
180  */
181  if (rel->rd_rel->relkind == RELKIND_RELATION ||
182  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
183  {
184  /* Tables can't have INSTEAD OF triggers */
185  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
186  stmt->timing != TRIGGER_TYPE_AFTER)
187  ereport(ERROR,
188  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
189  errmsg("\"%s\" is a table",
191  errdetail("Tables cannot have INSTEAD OF triggers.")));
192  /* Disallow ROW triggers on partitioned tables */
193  if (stmt->row && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
194  ereport(ERROR,
195  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
196  errmsg("\"%s\" is a partitioned table",
198  errdetail("Partitioned tables cannot have ROW triggers.")));
199  }
200  else if (rel->rd_rel->relkind == RELKIND_VIEW)
201  {
202  /*
203  * Views can have INSTEAD OF triggers (which we check below are
204  * row-level), or statement-level BEFORE/AFTER triggers.
205  */
206  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
207  ereport(ERROR,
208  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
209  errmsg("\"%s\" is a view",
211  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
212  /* Disallow TRUNCATE triggers on VIEWs */
213  if (TRIGGER_FOR_TRUNCATE(stmt->events))
214  ereport(ERROR,
215  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
216  errmsg("\"%s\" is a view",
218  errdetail("Views cannot have TRUNCATE triggers.")));
219  }
220  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
221  {
222  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
223  stmt->timing != TRIGGER_TYPE_AFTER)
224  ereport(ERROR,
225  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
226  errmsg("\"%s\" is a foreign table",
228  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
229 
230  if (TRIGGER_FOR_TRUNCATE(stmt->events))
231  ereport(ERROR,
232  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
233  errmsg("\"%s\" is a foreign table",
235  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
236 
237  if (stmt->isconstraint)
238  ereport(ERROR,
239  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
240  errmsg("\"%s\" is a foreign table",
242  errdetail("Foreign tables cannot have constraint triggers.")));
243  }
244  else
245  ereport(ERROR,
246  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
247  errmsg("\"%s\" is not a table or view",
248  RelationGetRelationName(rel))));
249 
251  ereport(ERROR,
252  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
253  errmsg("permission denied: \"%s\" is a system catalog",
254  RelationGetRelationName(rel))));
255 
256  if (stmt->isconstraint)
257  {
258  /*
259  * We must take a lock on the target relation to protect against
260  * concurrent drop. It's not clear that AccessShareLock is strong
261  * enough, but we certainly need at least that much... otherwise, we
262  * might end up creating a pg_constraint entry referencing a
263  * nonexistent table.
264  */
265  if (OidIsValid(refRelOid))
266  {
267  LockRelationOid(refRelOid, AccessShareLock);
268  constrrelid = refRelOid;
269  }
270  else if (stmt->constrrel != NULL)
271  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
272  false);
273  }
274 
275  /* permission checks */
276  if (!isInternal)
277  {
278  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
279  ACL_TRIGGER);
280  if (aclresult != ACLCHECK_OK)
281  aclcheck_error(aclresult, ACL_KIND_CLASS,
283 
284  if (OidIsValid(constrrelid))
285  {
286  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
287  ACL_TRIGGER);
288  if (aclresult != ACLCHECK_OK)
289  aclcheck_error(aclresult, ACL_KIND_CLASS,
290  get_rel_name(constrrelid));
291  }
292  }
293 
294  /* Compute tgtype */
295  TRIGGER_CLEAR_TYPE(tgtype);
296  if (stmt->row)
297  TRIGGER_SETT_ROW(tgtype);
298  tgtype |= stmt->timing;
299  tgtype |= stmt->events;
300 
301  /* Disallow ROW-level TRUNCATE triggers */
302  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
303  ereport(ERROR,
304  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
306 
307  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
308  if (TRIGGER_FOR_INSTEAD(tgtype))
309  {
310  if (!TRIGGER_FOR_ROW(tgtype))
311  ereport(ERROR,
312  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
313  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
314  if (stmt->whenClause)
315  ereport(ERROR,
316  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
317  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
318  if (stmt->columns != NIL)
319  ereport(ERROR,
320  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321  errmsg("INSTEAD OF triggers cannot have column lists")));
322  }
323 
324  /*
325  * We don't yet support naming ROW transition variables, but the parser
326  * recognizes the syntax so we can give a nicer message here.
327  *
328  * Per standard, REFERENCING TABLE names are only allowed on AFTER
329  * triggers. Per standard, REFERENCING ROW names are not allowed with FOR
330  * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is
331  * only allowed once. Per standard, OLD may not be specified when
332  * creating a trigger only for INSERT, and NEW may not be specified when
333  * creating a trigger only for DELETE.
334  *
335  * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to
336  * reference both ROW and TABLE transition data.
337  */
338  if (stmt->transitionRels != NIL)
339  {
340  List *varList = stmt->transitionRels;
341  ListCell *lc;
342 
343  foreach(lc, varList)
344  {
346 
347  if (!(tt->isTable))
348  ereport(ERROR,
349  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
350  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
351  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
352 
353  /*
354  * Because of the above test, we omit further ROW-related testing
355  * below. If we later allow naming OLD and NEW ROW variables,
356  * adjustments will be needed below.
357  */
358 
359  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
360  ereport(ERROR,
361  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
362  errmsg("\"%s\" is a foreign table",
364  errdetail("Triggers on foreign tables cannot have transition tables.")));
365 
366  if (rel->rd_rel->relkind == RELKIND_VIEW)
367  ereport(ERROR,
368  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
369  errmsg("\"%s\" is a view",
371  errdetail("Triggers on views cannot have transition tables.")));
372 
373  /*
374  * We currently don't allow row-level triggers with transition
375  * tables on partition or inheritance children. Such triggers
376  * would somehow need to see tuples converted to the format of the
377  * table they're attached to, and it's not clear which subset of
378  * tuples each child should see. See also the prohibitions in
379  * ATExecAttachPartition() and ATExecAddInherit().
380  */
381  if (TRIGGER_FOR_ROW(tgtype) && has_superclass(rel->rd_id))
382  {
383  /* Use appropriate error message. */
384  if (rel->rd_rel->relispartition)
385  ereport(ERROR,
386  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
387  errmsg("ROW triggers with transition tables are not supported on partitions")));
388  else
389  ereport(ERROR,
390  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
391  errmsg("ROW triggers with transition tables are not supported on inheritance children")));
392  }
393 
394  if (stmt->timing != TRIGGER_TYPE_AFTER)
395  ereport(ERROR,
396  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
397  errmsg("transition table name can only be specified for an AFTER trigger")));
398 
399  if (TRIGGER_FOR_TRUNCATE(tgtype))
400  ereport(ERROR,
401  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
402  errmsg("TRUNCATE triggers with transition tables are not supported")));
403 
404  /*
405  * We currently don't allow multi-event triggers ("INSERT OR
406  * UPDATE") with transition tables, because it's not clear how to
407  * handle INSERT ... ON CONFLICT statements which can fire both
408  * INSERT and UPDATE triggers. We show the inserted tuples to
409  * INSERT triggers and the updated tuples to UPDATE triggers, but
410  * it's not yet clear what INSERT OR UPDATE trigger should see.
411  * This restriction could be lifted if we can decide on the right
412  * semantics in a later release.
413  */
414  if (((TRIGGER_FOR_INSERT(tgtype) ? 1 : 0) +
415  (TRIGGER_FOR_UPDATE(tgtype) ? 1 : 0) +
416  (TRIGGER_FOR_DELETE(tgtype) ? 1 : 0)) != 1)
417  ereport(ERROR,
418  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
419  errmsg("Transition tables cannot be specified for triggers with more than one event")));
420 
421  if (tt->isNew)
422  {
423  if (!(TRIGGER_FOR_INSERT(tgtype) ||
424  TRIGGER_FOR_UPDATE(tgtype)))
425  ereport(ERROR,
426  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
427  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
428 
429  if (newtablename != NULL)
430  ereport(ERROR,
431  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
432  errmsg("NEW TABLE cannot be specified multiple times")));
433 
434  newtablename = tt->name;
435  }
436  else
437  {
438  if (!(TRIGGER_FOR_DELETE(tgtype) ||
439  TRIGGER_FOR_UPDATE(tgtype)))
440  ereport(ERROR,
441  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
442  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
443 
444  if (oldtablename != NULL)
445  ereport(ERROR,
446  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
447  errmsg("OLD TABLE cannot be specified multiple times")));
448 
449  oldtablename = tt->name;
450  }
451  }
452 
453  if (newtablename != NULL && oldtablename != NULL &&
454  strcmp(newtablename, oldtablename) == 0)
455  ereport(ERROR,
456  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
457  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
458  }
459 
460  /*
461  * Parse the WHEN clause, if any
462  */
463  if (stmt->whenClause)
464  {
465  ParseState *pstate;
466  RangeTblEntry *rte;
467  List *varList;
468  ListCell *lc;
469 
470  /* Set up a pstate to parse with */
471  pstate = make_parsestate(NULL);
472  pstate->p_sourcetext = queryString;
473 
474  /*
475  * Set up RTEs for OLD and NEW references.
476  *
477  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
478  */
479  rte = addRangeTableEntryForRelation(pstate, rel,
480  makeAlias("old", NIL),
481  false, false);
482  addRTEtoQuery(pstate, rte, false, true, true);
483  rte = addRangeTableEntryForRelation(pstate, rel,
484  makeAlias("new", NIL),
485  false, false);
486  addRTEtoQuery(pstate, rte, false, true, true);
487 
488  /* Transform expression. Copy to be sure we don't modify original */
489  whenClause = transformWhereClause(pstate,
490  copyObject(stmt->whenClause),
492  "WHEN");
493  /* we have to fix its collations too */
494  assign_expr_collations(pstate, whenClause);
495 
496  /*
497  * Check for disallowed references to OLD/NEW.
498  *
499  * NB: pull_var_clause is okay here only because we don't allow
500  * subselects in WHEN clauses; it would fail to examine the contents
501  * of subselects.
502  */
503  varList = pull_var_clause(whenClause, 0);
504  foreach(lc, varList)
505  {
506  Var *var = (Var *) lfirst(lc);
507 
508  switch (var->varno)
509  {
510  case PRS2_OLD_VARNO:
511  if (!TRIGGER_FOR_ROW(tgtype))
512  ereport(ERROR,
513  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
514  errmsg("statement trigger's WHEN condition cannot reference column values"),
515  parser_errposition(pstate, var->location)));
516  if (TRIGGER_FOR_INSERT(tgtype))
517  ereport(ERROR,
518  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
519  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
520  parser_errposition(pstate, var->location)));
521  /* system columns are okay here */
522  break;
523  case PRS2_NEW_VARNO:
524  if (!TRIGGER_FOR_ROW(tgtype))
525  ereport(ERROR,
526  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
527  errmsg("statement trigger's WHEN condition cannot reference column values"),
528  parser_errposition(pstate, var->location)));
529  if (TRIGGER_FOR_DELETE(tgtype))
530  ereport(ERROR,
531  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
532  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
533  parser_errposition(pstate, var->location)));
534  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
535  ereport(ERROR,
536  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
537  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
538  parser_errposition(pstate, var->location)));
539  break;
540  default:
541  /* can't happen without add_missing_from, so just elog */
542  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
543  break;
544  }
545  }
546 
547  /* we'll need the rtable for recordDependencyOnExpr */
548  whenRtable = pstate->p_rtable;
549 
550  qual = nodeToString(whenClause);
551 
552  free_parsestate(pstate);
553  }
554  else
555  {
556  whenClause = NULL;
557  whenRtable = NIL;
558  qual = NULL;
559  }
560 
561  /*
562  * Find and validate the trigger function.
563  */
564  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
565  if (!isInternal)
566  {
567  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
568  if (aclresult != ACLCHECK_OK)
569  aclcheck_error(aclresult, ACL_KIND_PROC,
570  NameListToString(stmt->funcname));
571  }
572  funcrettype = get_func_rettype(funcoid);
573  if (funcrettype != TRIGGEROID)
574  {
575  /*
576  * We allow OPAQUE just so we can load old dump files. When we see a
577  * trigger function declared OPAQUE, change it to TRIGGER.
578  */
579  if (funcrettype == OPAQUEOID)
580  {
582  (errmsg("changing return type of function %s from %s to %s",
583  NameListToString(stmt->funcname),
584  "opaque", "trigger")));
586  }
587  else
588  ereport(ERROR,
589  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
590  errmsg("function %s must return type %s",
591  NameListToString(stmt->funcname), "trigger")));
592  }
593 
594  /*
595  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
596  * references one of the built-in RI_FKey trigger functions, assume it is
597  * from a dump of a pre-7.3 foreign key constraint, and take steps to
598  * convert this legacy representation into a regular foreign key
599  * constraint. Ugly, but necessary for loading old dump files.
600  */
601  if (stmt->isconstraint && !isInternal &&
602  list_length(stmt->args) >= 6 &&
603  (list_length(stmt->args) % 2) == 0 &&
605  {
606  /* Keep lock on target rel until end of xact */
607  heap_close(rel, NoLock);
608 
609  ConvertTriggerToFK(stmt, funcoid);
610 
611  return InvalidObjectAddress;
612  }
613 
614  /*
615  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
616  * corresponding pg_constraint entry.
617  */
618  if (stmt->isconstraint && !OidIsValid(constraintOid))
619  {
620  /* Internal callers should have made their own constraints */
621  Assert(!isInternal);
622  constraintOid = CreateConstraintEntry(stmt->trigname,
625  stmt->deferrable,
626  stmt->initdeferred,
627  true,
628  RelationGetRelid(rel),
629  NULL, /* no conkey */
630  0,
631  InvalidOid, /* no domain */
632  InvalidOid, /* no index */
633  InvalidOid, /* no foreign key */
634  NULL,
635  NULL,
636  NULL,
637  NULL,
638  0,
639  ' ',
640  ' ',
641  ' ',
642  NULL, /* no exclusion */
643  NULL, /* no check constraint */
644  NULL,
645  NULL,
646  true, /* islocal */
647  0, /* inhcount */
648  true, /* isnoinherit */
649  isInternal); /* is_internal */
650  }
651 
652  /*
653  * Generate the trigger's OID now, so that we can use it in the name if
654  * needed.
655  */
657 
658  trigoid = GetNewOid(tgrel);
659 
660  /*
661  * If trigger is internally generated, modify the provided trigger name to
662  * ensure uniqueness by appending the trigger OID. (Callers will usually
663  * supply a simple constant trigger name in these cases.)
664  */
665  if (isInternal)
666  {
667  snprintf(internaltrigname, sizeof(internaltrigname),
668  "%s_%u", stmt->trigname, trigoid);
669  trigname = internaltrigname;
670  }
671  else
672  {
673  /* user-defined trigger; use the specified trigger name as-is */
674  trigname = stmt->trigname;
675  }
676 
677  /*
678  * Scan pg_trigger for existing triggers on relation. We do this only to
679  * give a nice error message if there's already a trigger of the same
680  * name. (The unique index on tgrelid/tgname would complain anyway.) We
681  * can skip this for internally generated triggers, since the name
682  * modification above should be sufficient.
683  *
684  * NOTE that this is cool only because we have ShareRowExclusiveLock on
685  * the relation, so the trigger set won't be changing underneath us.
686  */
687  if (!isInternal)
688  {
689  ScanKeyInit(&key,
691  BTEqualStrategyNumber, F_OIDEQ,
693  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
694  NULL, 1, &key);
695  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
696  {
697  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
698 
699  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
700  ereport(ERROR,
702  errmsg("trigger \"%s\" for relation \"%s\" already exists",
703  trigname, RelationGetRelationName(rel))));
704  }
705  systable_endscan(tgscan);
706  }
707 
708  /*
709  * Build the new pg_trigger tuple.
710  */
711  memset(nulls, false, sizeof(nulls));
712 
715  CStringGetDatum(trigname));
716  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
717  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
719  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
720  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
721  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
722  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
725 
726  if (stmt->args)
727  {
728  ListCell *le;
729  char *args;
730  int16 nargs = list_length(stmt->args);
731  int len = 0;
732 
733  foreach(le, stmt->args)
734  {
735  char *ar = strVal(lfirst(le));
736 
737  len += strlen(ar) + 4;
738  for (; *ar; ar++)
739  {
740  if (*ar == '\\')
741  len++;
742  }
743  }
744  args = (char *) palloc(len + 1);
745  args[0] = '\0';
746  foreach(le, stmt->args)
747  {
748  char *s = strVal(lfirst(le));
749  char *d = args + strlen(args);
750 
751  while (*s)
752  {
753  if (*s == '\\')
754  *d++ = '\\';
755  *d++ = *s++;
756  }
757  strcpy(d, "\\000");
758  }
759  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
761  CStringGetDatum(args));
762  }
763  else
764  {
765  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
767  CStringGetDatum(""));
768  }
769 
770  /* build column number array if it's a column-specific trigger */
771  ncolumns = list_length(stmt->columns);
772  if (ncolumns == 0)
773  columns = NULL;
774  else
775  {
776  ListCell *cell;
777  int i = 0;
778 
779  columns = (int16 *) palloc(ncolumns * sizeof(int16));
780  foreach(cell, stmt->columns)
781  {
782  char *name = strVal(lfirst(cell));
783  int16 attnum;
784  int j;
785 
786  /* Lookup column name. System columns are not allowed */
787  attnum = attnameAttNum(rel, name, false);
788  if (attnum == InvalidAttrNumber)
789  ereport(ERROR,
790  (errcode(ERRCODE_UNDEFINED_COLUMN),
791  errmsg("column \"%s\" of relation \"%s\" does not exist",
792  name, RelationGetRelationName(rel))));
793 
794  /* Check for duplicates */
795  for (j = i - 1; j >= 0; j--)
796  {
797  if (columns[j] == attnum)
798  ereport(ERROR,
799  (errcode(ERRCODE_DUPLICATE_COLUMN),
800  errmsg("column \"%s\" specified more than once",
801  name)));
802  }
803 
804  columns[i++] = attnum;
805  }
806  }
807  tgattr = buildint2vector(columns, ncolumns);
808  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
809 
810  /* set tgqual if trigger has WHEN clause */
811  if (qual)
812  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
813  else
814  nulls[Anum_pg_trigger_tgqual - 1] = true;
815 
816  if (oldtablename)
818  CStringGetDatum(oldtablename));
819  else
820  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
821  if (newtablename)
823  CStringGetDatum(newtablename));
824  else
825  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
826 
827  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
828 
829  /* force tuple to have the desired OID */
830  HeapTupleSetOid(tuple, trigoid);
831 
832  /*
833  * Insert tuple into pg_trigger.
834  */
835  CatalogTupleInsert(tgrel, tuple);
836 
837  heap_freetuple(tuple);
839 
843  if (oldtablename)
845  if (newtablename)
847 
848  /*
849  * Update relation's pg_class entry. Crucial side-effect: other backends
850  * (and this one too!) are sent SI message to make them rebuild relcache
851  * entries.
852  */
854  tuple = SearchSysCacheCopy1(RELOID,
856  if (!HeapTupleIsValid(tuple))
857  elog(ERROR, "cache lookup failed for relation %u",
858  RelationGetRelid(rel));
859 
860  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
861 
862  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
863 
864  heap_freetuple(tuple);
866 
867  /*
868  * We used to try to update the rel's relcache entry here, but that's
869  * fairly pointless since it will happen as a byproduct of the upcoming
870  * CommandCounterIncrement...
871  */
872 
873  /*
874  * Record dependencies for trigger. Always place a normal dependency on
875  * the function.
876  */
877  myself.classId = TriggerRelationId;
878  myself.objectId = trigoid;
879  myself.objectSubId = 0;
880 
881  referenced.classId = ProcedureRelationId;
882  referenced.objectId = funcoid;
883  referenced.objectSubId = 0;
884  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
885 
886  if (isInternal && OidIsValid(constraintOid))
887  {
888  /*
889  * Internally-generated trigger for a constraint, so make it an
890  * internal dependency of the constraint. We can skip depending on
891  * the relation(s), as there'll be an indirect dependency via the
892  * constraint.
893  */
894  referenced.classId = ConstraintRelationId;
895  referenced.objectId = constraintOid;
896  referenced.objectSubId = 0;
897  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
898  }
899  else
900  {
901  /*
902  * User CREATE TRIGGER, so place dependencies. We make trigger be
903  * auto-dropped if its relation is dropped or if the FK relation is
904  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
905  */
906  referenced.classId = RelationRelationId;
907  referenced.objectId = RelationGetRelid(rel);
908  referenced.objectSubId = 0;
909  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
910  if (OidIsValid(constrrelid))
911  {
912  referenced.classId = RelationRelationId;
913  referenced.objectId = constrrelid;
914  referenced.objectSubId = 0;
915  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
916  }
917  /* Not possible to have an index dependency in this case */
918  Assert(!OidIsValid(indexOid));
919 
920  /*
921  * If it's a user-specified constraint trigger, make the constraint
922  * internally dependent on the trigger instead of vice versa.
923  */
924  if (OidIsValid(constraintOid))
925  {
926  referenced.classId = ConstraintRelationId;
927  referenced.objectId = constraintOid;
928  referenced.objectSubId = 0;
929  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
930  }
931  }
932 
933  /* If column-specific trigger, add normal dependencies on columns */
934  if (columns != NULL)
935  {
936  int i;
937 
938  referenced.classId = RelationRelationId;
939  referenced.objectId = RelationGetRelid(rel);
940  for (i = 0; i < ncolumns; i++)
941  {
942  referenced.objectSubId = columns[i];
943  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
944  }
945  }
946 
947  /*
948  * If it has a WHEN clause, add dependencies on objects mentioned in the
949  * expression (eg, functions, as well as any columns used).
950  */
951  if (whenClause != NULL)
952  recordDependencyOnExpr(&myself, whenClause, whenRtable,
954 
955  /* Post creation hook for new trigger */
957  isInternal);
958 
959  /* Keep lock on target rel until end of xact */
960  heap_close(rel, NoLock);
961 
962  return myself;
963 }
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
#define Anum_pg_trigger_tgdeferrable
Definition: pg_trigger.h:88
#define TRIGGER_FOR_DELETE(type)
Definition: pg_trigger.h:135
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3701
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
int errhint(const char *fmt,...)
Definition: elog.c:987
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
Oid GetUserId(void)
Definition: miscinit.c:284
#define PointerGetDatum(X)
Definition: postgres.h:562
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:87
#define ProcedureRelationId
Definition: pg_proc.h:33
Node * whenClause
Definition: parsenodes.h:2356
#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:93
#define TRIGGER_CLEAR_TYPE(type)
Definition: pg_trigger.h:118
#define Int16GetDatum(X)
Definition: postgres.h:457
#define Anum_pg_trigger_tgtype
Definition: pg_trigger.h:82
#define AccessShareLock
Definition: lockdefs.h:36
#define Anum_pg_trigger_tgnargs
Definition: pg_trigger.h:90
Definition: nodes.h:509
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
int namestrcmp(Name name, const char *str)
Definition: name.c:247
#define TRIGGER_FOR_UPDATE(type)
Definition: pg_trigger.h:136
AttrNumber varattno
Definition: primnodes.h:168
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:163
#define Anum_pg_trigger_tgisinternal
Definition: pg_trigger.h:84
#define OidIsValid(objectId)
Definition: c.h:538
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:154
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1459
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define TriggerRelidNameIndexId
Definition: indexing.h:249
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#define NAMEDATALEN
void assign_expr_collations(ParseState *pstate, Node *expr)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:384
RangeVar * constrrel
Definition: parsenodes.h:2363
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define TRIGGER_FOR_ROW(type)
Definition: pg_trigger.h:130
void pfree(void *pointer)
Definition: mcxt.c:950
#define OPAQUEOID
Definition: pg_type.h:700
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
#define TRIGGEROID
Definition: pg_type.h:692
ItemPointerData t_self
Definition: htup.h:65
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:282
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:255
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define ACL_TRIGGER
Definition: parsenodes.h:78
int location
Definition: primnodes.h:178
#define NoLock
Definition: lockdefs.h:34
#define TRIGGER_SETT_ROW(type)
Definition: pg_trigger.h:120
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define CStringGetDatum(X)
Definition: postgres.h:584
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1351
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
const char * p_sourcetext
Definition: parse_node.h:171
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:993
List * transitionRels
Definition: parsenodes.h:2359
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid rd_id
Definition: rel.h:116
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:166
char * NameListToString(List *names)
Definition: namespace.c:3063
#define Anum_pg_trigger_tgnewtable
Definition: pg_trigger.h:95
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Definition: c.h:467
#define Anum_pg_trigger_tgconstrindid
Definition: pg_trigger.h:86
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:372
#define Anum_pg_trigger_tgenabled
Definition: pg_trigger.h:83
Oid GetNewOid(Relation relation)
Definition: catalog.c:289
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
void SetFunctionReturnType(Oid funcOid, Oid newRetType)
#define TRIGGER_FOR_TRUNCATE(type)
Definition: pg_trigger.h:137
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
TupleDesc rd_att
Definition: rel.h:115
#define BoolGetDatum(X)
Definition: postgres.h:408
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1312
bool allowSystemTableMods
Definition: globals.c:112
#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:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define Anum_pg_trigger_tgargs
Definition: pg_trigger.h:92
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
#define Anum_pg_trigger_tgconstrrelid
Definition: pg_trigger.h:85
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
#define TRIGGER_FOR_INSERT(type)
Definition: pg_trigger.h:134
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
#define CharGetDatum(X)
Definition: postgres.h:422
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4422
#define DatumGetPointer(X)
Definition: postgres.h:555
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1929
#define Anum_pg_trigger_tgoldtable
Definition: pg_trigger.h:94
static Datum values[MAXATTR]
Definition: bootstrap.c:163
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:79
#define RELKIND_VIEW
Definition: pg_class.h:164
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
RangeVar * relation
Definition: parsenodes.h:2347
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:91
char * nodeToString(const void *obj)
Definition: outfuncs.c:4252
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define CONSTRAINT_TRIGGER
#define copyObject(obj)
Definition: nodes.h:622
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RI_TRIGGER_NONE
Definition: trigger.h:266
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define RelationGetRelid(relation)
Definition: rel.h:416
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define Anum_pg_trigger_tgfoid
Definition: pg_trigger.h:81
#define Anum_pg_trigger_tginitdeferred
Definition: pg_trigger.h:89
#define Anum_pg_trigger_tgattr
Definition: pg_trigger.h:91
#define Natts_pg_trigger
Definition: pg_trigger.h:78
#define TRIGGER_FOR_INSTEAD(type)
Definition: pg_trigger.h:133
#define RelationGetNamespace(relation)
Definition: rel.h:443
List * p_rtable
Definition: parse_node.h:172
void DestroyTransitionCaptureState ( TransitionCaptureState tcs)

Definition at line 2167 of file trigger.c.

References NULL, pfree(), TransitionCaptureState::tcs_insert_tuplestore, TransitionCaptureState::tcs_old_tuplestore, TransitionCaptureState::tcs_update_tuplestore, and tuplestore_end().

Referenced by ExecEndModifyTable().

2168 {
2169  if (tcs->tcs_insert_tuplestore != NULL)
2171  if (tcs->tcs_update_tuplestore != NULL)
2173  if (tcs->tcs_old_tuplestore != NULL)
2175  pfree(tcs);
2176 }
Tuplestorestate * tcs_update_tuplestore
Definition: trigger.h:86
Tuplestorestate * tcs_old_tuplestore
Definition: trigger.h:84
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Tuplestorestate * tcs_insert_tuplestore
Definition: trigger.h:85
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

Definition at line 1555 of file trigger.c.

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

Referenced by ATExecEnableDisableTrigger().

1557 {
1558  Relation tgrel;
1559  int nkeys;
1560  ScanKeyData keys[2];
1561  SysScanDesc tgscan;
1562  HeapTuple tuple;
1563  bool found;
1564  bool changed;
1565 
1566  /* Scan the relevant entries in pg_triggers */
1568 
1569  ScanKeyInit(&keys[0],
1571  BTEqualStrategyNumber, F_OIDEQ,
1573  if (tgname)
1574  {
1575  ScanKeyInit(&keys[1],
1577  BTEqualStrategyNumber, F_NAMEEQ,
1578  CStringGetDatum(tgname));
1579  nkeys = 2;
1580  }
1581  else
1582  nkeys = 1;
1583 
1584  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1585  NULL, nkeys, keys);
1586 
1587  found = changed = false;
1588 
1589  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1590  {
1591  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1592 
1593  if (oldtrig->tgisinternal)
1594  {
1595  /* system trigger ... ok to process? */
1596  if (skip_system)
1597  continue;
1598  if (!superuser())
1599  ereport(ERROR,
1600  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1601  errmsg("permission denied: \"%s\" is a system trigger",
1602  NameStr(oldtrig->tgname))));
1603  }
1604 
1605  found = true;
1606 
1607  if (oldtrig->tgenabled != fires_when)
1608  {
1609  /* need to change this one ... make a copy to scribble on */
1610  HeapTuple newtup = heap_copytuple(tuple);
1611  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1612 
1613  newtrig->tgenabled = fires_when;
1614 
1615  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1616 
1617  heap_freetuple(newtup);
1618 
1619  changed = true;
1620  }
1621 
1623  HeapTupleGetOid(tuple), 0);
1624  }
1625 
1626  systable_endscan(tgscan);
1627 
1628  heap_close(tgrel, RowExclusiveLock);
1629 
1630  if (tgname && !found)
1631  ereport(ERROR,
1632  (errcode(ERRCODE_UNDEFINED_OBJECT),
1633  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1634  tgname, RelationGetRelationName(rel))));
1635 
1636  /*
1637  * If we changed anything, broadcast a SI inval message to force each
1638  * backend (including our own!) to rebuild relation's relcache entry.
1639  * Otherwise they will fail to apply the change promptly.
1640  */
1641  if (changed)
1643 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define TriggerRelidNameIndexId
Definition: indexing.h:249
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:584
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define RelationGetRelid(relation)
Definition: rel.h:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TransitionCaptureState transition_capture 
)

Definition at line 2626 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2630 {
2631  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2632 
2633  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2634  (transition_capture && transition_capture->tcs_delete_old_table))
2635  {
2636  HeapTuple trigtuple;
2637 
2638  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2639  if (fdw_trigtuple == NULL)
2640  trigtuple = GetTupleForTrigger(estate,
2641  NULL,
2642  relinfo,
2643  tupleid,
2645  NULL);
2646  else
2647  trigtuple = fdw_trigtuple;
2648 
2650  true, trigtuple, NULL, NIL, NULL,
2651  transition_capture);
2652  if (trigtuple != fdw_trigtuple)
2653  heap_freetuple(trigtuple);
2654  }
2655 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5222
bool trig_delete_after_row
Definition: reltrigger.h:66
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3056
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2413 of file trigger.c.

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

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

2416 {
2417  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2418 
2419  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2420  (transition_capture && transition_capture->tcs_insert_new_table))
2422  true, NULL, trigtuple,
2423  recheckIndexes, NULL,
2424  transition_capture);
2425 }
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5222
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2890 of file trigger.c.

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

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2896 {
2897  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2898 
2899  if ((trigdesc && trigdesc->trig_update_after_row) ||
2900  (transition_capture &&
2901  (transition_capture->tcs_update_old_table ||
2902  transition_capture->tcs_update_new_table)))
2903  {
2904  HeapTuple trigtuple;
2905 
2906