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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static void ConvertTriggerToFK (CreateTrigStmt *stmt, Oid funcoid)
 
static void SetTriggerFlags (TriggerDesc *trigdesc, Trigger *trigger)
 
static HeapTuple GetTupleForTrigger (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
 
static bool TriggerEnabled (EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
 
static HeapTuple ExecCallTriggerFunc (TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
 
static void AfterTriggerSaveEvent (EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
 
static void AfterTriggerEnlargeQueryState (void)
 
ObjectAddress CreateTrigger (CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, bool isInternal)
 
void RemoveTriggerById (Oid trigOid)
 
Oid get_trigger_oid (Oid relid, const char *trigname, bool missing_ok)
 
static void RangeVarCallbackForRenameTrigger (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renametrig (RenameStmt *stmt)
 
void EnableDisableTrigger (Relation rel, const char *tgname, char fires_when, bool skip_system)
 
void RelationBuildTriggers (Relation relation)
 
TriggerDescCopyTriggerDesc (TriggerDesc *trigdesc)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes)
 
TupleTableSlotExecIRUpdateTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
 
void ExecBSTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
static void AfterTriggerExecute (AfterTriggerEvent event, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
 
static SetConstraintState SetConstraintStateCreate (int numalloc)
 
static SetConstraintState SetConstraintStateCopy (SetConstraintState state)
 
static SetConstraintState SetConstraintStateAddItem (SetConstraintState state, Oid tgoid, bool tgisdeferred)
 
static 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 3246 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3247 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3245 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3244 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

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

Definition at line 3239 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3248 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3308 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 3319 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:3308
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3282
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3260

Definition at line 3321 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:3248
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3246
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3247

Definition at line 3282 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3260 of file trigger.c.

Definition at line 3250 of file trigger.c.

Definition at line 3237 of file trigger.c.

Function Documentation

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

Definition at line 3522 of file trigger.c.

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

Referenced by afterTriggerMarkEvents(), and AfterTriggerSaveEvent().

3524 {
3525  Size eventsize = SizeofTriggerEvent(event);
3526  Size needed = eventsize + sizeof(AfterTriggerSharedData);
3527  AfterTriggerEventChunk *chunk;
3528  AfterTriggerShared newshared;
3529  AfterTriggerEvent newevent;
3530 
3531  /*
3532  * If empty list or not enough room in the tail chunk, make a new chunk.
3533  * We assume here that a new shared record will always be needed.
3534  */
3535  chunk = events->tail;
3536  if (chunk == NULL ||
3537  chunk->endfree - chunk->freeptr < needed)
3538  {
3539  Size chunksize;
3540 
3541  /* Create event context if we didn't already */
3542  if (afterTriggers.event_cxt == NULL)
3545  "AfterTriggerEvents",
3547 
3548  /*
3549  * Chunk size starts at 1KB and is allowed to increase up to 1MB.
3550  * These numbers are fairly arbitrary, though there is a hard limit at
3551  * AFTER_TRIGGER_OFFSET; else we couldn't link event records to their
3552  * shared records using the available space in ate_flags. Another
3553  * constraint is that if the chunk size gets too huge, the search loop
3554  * below would get slow given a (not too common) usage pattern with
3555  * many distinct event types in a chunk. Therefore, we double the
3556  * preceding chunk size only if there weren't too many shared records
3557  * in the preceding chunk; otherwise we halve it. This gives us some
3558  * ability to adapt to the actual usage pattern of the current query
3559  * while still having large chunk sizes in typical usage. All chunk
3560  * sizes used should be MAXALIGN multiples, to ensure that the shared
3561  * records will be aligned safely.
3562  */
3563 #define MIN_CHUNK_SIZE 1024
3564 #define MAX_CHUNK_SIZE (1024*1024)
3565 
3566 #if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
3567 #error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
3568 #endif
3569 
3570  if (chunk == NULL)
3571  chunksize = MIN_CHUNK_SIZE;
3572  else
3573  {
3574  /* preceding chunk size... */
3575  chunksize = chunk->endptr - (char *) chunk;
3576  /* check number of shared records in preceding chunk */
3577  if ((chunk->endptr - chunk->endfree) <=
3578  (100 * sizeof(AfterTriggerSharedData)))
3579  chunksize *= 2; /* okay, double it */
3580  else
3581  chunksize /= 2; /* too many shared records */
3582  chunksize = Min(chunksize, MAX_CHUNK_SIZE);
3583  }
3584  chunk = MemoryContextAlloc(afterTriggers.event_cxt, chunksize);
3585  chunk->next = NULL;
3586  chunk->freeptr = CHUNK_DATA_START(chunk);
3587  chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
3588  Assert(chunk->endfree - chunk->freeptr >= needed);
3589 
3590  if (events->head == NULL)
3591  events->head = chunk;
3592  else
3593  events->tail->next = chunk;
3594  events->tail = chunk;
3595  /* events->tailfree is now out of sync, but we'll fix it below */
3596  }
3597 
3598  /*
3599  * Try to locate a matching shared-data record already in the chunk. If
3600  * none, make a new one.
3601  */
3602  for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
3603  (char *) newshared >= chunk->endfree;
3604  newshared--)
3605  {
3606  if (newshared->ats_tgoid == evtshared->ats_tgoid &&
3607  newshared->ats_relid == evtshared->ats_relid &&
3608  newshared->ats_event == evtshared->ats_event &&
3609  newshared->ats_firing_id == 0)
3610  break;
3611  }
3612  if ((char *) newshared < chunk->endfree)
3613  {
3614  *newshared = *evtshared;
3615  newshared->ats_firing_id = 0; /* just to be sure */
3616  chunk->endfree = (char *) newshared;
3617  }
3618 
3619  /* Insert the data */
3620  newevent = (AfterTriggerEvent) chunk->freeptr;
3621  memcpy(newevent, event, eventsize);
3622  /* ... and link the new event to its shared record */
3623  newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
3624  newevent->ate_flags |= (char *) newshared - (char *) newevent;
3625 
3626  chunk->freeptr += eventsize;
3627  events->tailfree = chunk->freeptr;
3628 }
TriggerEvent ats_event
Definition: trigger.c:3254
MemoryContext TopTransactionContext
Definition: mcxt.c:48
#define MIN_CHUNK_SIZE
TriggerFlags ate_flags
Definition: trigger.c:3264
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3308
struct AfterTriggerSharedData AfterTriggerSharedData
#define Min(x, y)
Definition: c.h:806
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
struct AfterTriggerEventChunk * next
Definition: trigger.c:3301
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3282
#define AFTER_TRIGGER_OFFSET
Definition: trigger.c:3239
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#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:3257
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3260
#define MAX_CHUNK_SIZE
AfterTriggerEventChunk * head
Definition: trigger.c:3313
MemoryContext event_cxt
Definition: trigger.c:3400
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
void AfterTriggerBeginQuery ( void  )

Definition at line 4157 of file trigger.c.

References AfterTriggersData::query_depth.

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

4158 {
4159  /* Increase the query stack depth */
4161 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
void AfterTriggerBeginSubXact ( void  )

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

4382 {
4383  int my_level = GetCurrentTransactionNestLevel();
4384 
4385  /*
4386  * Allocate more space in the stacks if needed. (Note: because the
4387  * minimum nest level of a subtransaction is 2, we waste the first couple
4388  * entries of each array; not worth the notational effort to avoid it.)
4389  */
4390  while (my_level >= afterTriggers.maxtransdepth)
4391  {
4392  if (afterTriggers.maxtransdepth == 0)
4393  {
4394  MemoryContext old_cxt;
4395 
4397 
4398 #define DEFTRIG_INITALLOC 8
4403  afterTriggers.depth_stack = (int *)
4404  palloc(DEFTRIG_INITALLOC * sizeof(int));
4406  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4408 
4409  MemoryContextSwitchTo(old_cxt);
4410  }
4411  else
4412  {
4413  /* repalloc will keep the stacks in the same context */
4414  int new_alloc = afterTriggers.maxtransdepth * 2;
4415 
4418  new_alloc * sizeof(SetConstraintState));
4421  new_alloc * sizeof(AfterTriggerEventList));
4422  afterTriggers.depth_stack = (int *)
4424  new_alloc * sizeof(int));
4427  new_alloc * sizeof(CommandId));
4428  afterTriggers.maxtransdepth = new_alloc;
4429  }
4430  }
4431 
4432  /*
4433  * Push the current information into the stack. The SET CONSTRAINTS state
4434  * is not saved until/unless changed. Likewise, we don't make a
4435  * per-subtransaction event context until needed.
4436  */
4437  afterTriggers.state_stack[my_level] = NULL;
4441 }
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:3407
SetConstraintState * state_stack
Definition: trigger.c:3404
CommandId firing_counter
Definition: trigger.c:3391
AfterTriggerEventList * events_stack
Definition: trigger.c:3405
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:3393
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
void AfterTriggerBeginXact ( void  )

Definition at line 4119 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, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, and AfterTriggersData::state_stack.

Referenced by StartTransaction().

4120 {
4121  /*
4122  * Initialize after-trigger state structure to empty
4123  */
4124  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4126 
4127  /*
4128  * Verify that there is no leftover state remaining. If these assertions
4129  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4130  * up properly.
4131  */
4145 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
CommandId * firing_stack
Definition: trigger.c:3407
SetConstraintState * state_stack
Definition: trigger.c:3404
SetConstraintState state
Definition: trigger.c:3392
CommandId firing_counter
Definition: trigger.c:3391
AfterTriggerEventList * events_stack
Definition: trigger.c:3405
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3313
MemoryContext event_cxt
Definition: trigger.c:3400
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList events
Definition: trigger.c:3393
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

3477 {
3478  Oid tgoid = evtshared->ats_tgoid;
3480  int i;
3481 
3482  /*
3483  * For not-deferrable triggers (i.e. normal AFTER ROW triggers and
3484  * constraints declared NOT DEFERRABLE), the state is always false.
3485  */
3486  if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
3487  return false;
3488 
3489  /*
3490  * If constraint state exists, SET CONSTRAINTS might have been executed
3491  * either for this trigger or for all triggers.
3492  */
3493  if (state != NULL)
3494  {
3495  /* Check for SET CONSTRAINTS for this specific trigger. */
3496  for (i = 0; i < state->numstates; i++)
3497  {
3498  if (state->trigstates[i].sct_tgoid == tgoid)
3499  return state->trigstates[i].sct_tgisdeferred;
3500  }
3501 
3502  /* Check for SET CONSTRAINTS ALL. */
3503  if (state->all_isset)
3504  return state->all_isdeferred;
3505  }
3506 
3507  /*
3508  * Otherwise return the default state for the trigger.
3509  */
3510  return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
3511 }
TriggerEvent ats_event
Definition: trigger.c:3254
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:68
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:67
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3201
unsigned int Oid
Definition: postgres_ext.h:31
SetConstraintState state
Definition: trigger.c:3392
#define NULL
Definition: c.h:229
Definition: regguts.h:298
int i
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
void AfterTriggerEndQuery ( EState estate)

Definition at line 4177 of file trigger.c.

References afterTriggerFreeEventList(), afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::maxquerydepth, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, 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().

4178 {
4179  AfterTriggerEventList *events;
4180  Tuplestorestate *fdw_tuplestore;
4181  Tuplestorestate *old_tuplestore;
4182  Tuplestorestate *new_tuplestore;
4183 
4184  /* Must be inside a query, too */
4186 
4187  /*
4188  * If we never even got as far as initializing the event stack, there
4189  * certainly won't be any events, so exit quickly.
4190  */
4192  {
4194  return;
4195  }
4196 
4197  /*
4198  * Process all immediate-mode triggers queued by the query, and move the
4199  * deferred ones to the main list of deferred events.
4200  *
4201  * Notice that we decide which ones will be fired, and put the deferred
4202  * ones on the main list, before anything is actually fired. This ensures
4203  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4204  * IMMEDIATE: all events we have decided to defer will be available for it
4205  * to fire.
4206  *
4207  * We loop in case a trigger queues more events at the same query level.
4208  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4209  * will instead fire any triggers in a dedicated query level. Foreign key
4210  * enforcement triggers do add to the current query level, thanks to their
4211  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4212  * C-language triggers might do likewise. Be careful here: firing a
4213  * trigger could result in query_stack being repalloc'd, so we can't save
4214  * its address across afterTriggerInvokeEvents calls.
4215  *
4216  * If we find no firable events, we don't have to increment
4217  * firing_counter.
4218  */
4219  for (;;)
4220  {
4222  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4223  {
4224  CommandId firing_id = afterTriggers.firing_counter++;
4225 
4226  /* OK to delete the immediate events after processing them */
4227  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4228  break; /* all fired */
4229  }
4230  else
4231  break;
4232  }
4233 
4234  /* Release query-local storage for events, including tuplestore if any */
4236  if (fdw_tuplestore)
4237  {
4238  tuplestore_end(fdw_tuplestore);
4240  }
4242  if (old_tuplestore)
4243  {
4244  tuplestore_end(old_tuplestore);
4246  }
4248  if (new_tuplestore)
4249  {
4250  tuplestore_end(new_tuplestore);
4252  }
4254 
4256 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3974
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3637
CommandId firing_counter
Definition: trigger.c:3391
#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:3902
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList events
Definition: trigger.c:3393
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
void AfterTriggerEndSubXact ( bool  isCommit)

Definition at line 4449 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, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, pfree(), AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, and tuplestore_end().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

4450 {
4451  int my_level = GetCurrentTransactionNestLevel();
4453  AfterTriggerEvent event;
4454  AfterTriggerEventChunk *chunk;
4455  CommandId subxact_firing_id;
4456 
4457  /*
4458  * Pop the prior state if needed.
4459  */
4460  if (isCommit)
4461  {
4462  Assert(my_level < afterTriggers.maxtransdepth);
4463  /* If we saved a prior state, we don't need it anymore */
4464  state = afterTriggers.state_stack[my_level];
4465  if (state != NULL)
4466  pfree(state);
4467  /* this avoids double pfree if error later: */
4468  afterTriggers.state_stack[my_level] = NULL;
4470  afterTriggers.depth_stack[my_level]);
4471  }
4472  else
4473  {
4474  /*
4475  * Aborting. It is possible subxact start failed before calling
4476  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4477  * stack levels that aren't there.
4478  */
4479  if (my_level >= afterTriggers.maxtransdepth)
4480  return;
4481 
4482  /*
4483  * Release any event lists from queries being aborted, and restore
4484  * query_depth to its pre-subxact value. This assumes that a
4485  * subtransaction will not add events to query levels started in a
4486  * earlier transaction state.
4487  */
4489  {
4491  {
4492  Tuplestorestate *ts;
4493 
4495  if (ts)
4496  {
4497  tuplestore_end(ts);
4499  }
4501  if (ts)
4502  {
4503  tuplestore_end(ts);
4505  }
4507  if (ts)
4508  {
4509  tuplestore_end(ts);
4511  }
4512 
4514  }
4515 
4517  }
4519  afterTriggers.depth_stack[my_level]);
4520 
4521  /*
4522  * Restore the global deferred-event list to its former length,
4523  * discarding any events queued by the subxact.
4524  */
4526  &afterTriggers.events_stack[my_level]);
4527 
4528  /*
4529  * Restore the trigger state. If the saved state is NULL, then this
4530  * subxact didn't save it, so it doesn't need restoring.
4531  */
4532  state = afterTriggers.state_stack[my_level];
4533  if (state != NULL)
4534  {
4536  afterTriggers.state = state;
4537  }
4538  /* this avoids double pfree if error later: */
4539  afterTriggers.state_stack[my_level] = NULL;
4540 
4541  /*
4542  * Scan for any remaining deferred events that were marked DONE or IN
4543  * PROGRESS by this subxact or a child, and un-mark them. We can
4544  * recognize such events because they have a firing ID greater than or
4545  * equal to the firing_counter value we saved at subtransaction start.
4546  * (This essentially assumes that the current subxact includes all
4547  * subxacts started after it.)
4548  */
4549  subxact_firing_id = afterTriggers.firing_stack[my_level];
4551  {
4552  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4553 
4554  if (event->ate_flags &
4556  {
4557  if (evtshared->ats_firing_id >= subxact_firing_id)
4558  event->ate_flags &=
4560  }
4561  }
4562  }
4563 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
TriggerFlags ate_flags
Definition: trigger.c:3264
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3241
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3326
CommandId * firing_stack
Definition: trigger.c:3407
#define GetTriggerSharedData(evt)
Definition: trigger.c:3289
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3404
SetConstraintState state
Definition: trigger.c:3392
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3637
AfterTriggerEventList * events_stack
Definition: trigger.c:3405
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:3660
CommandId ats_firing_id
Definition: trigger.c:3257
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3242
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList events
Definition: trigger.c:3393
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
void AfterTriggerEndXact ( bool  isCommit)

Definition at line 4327 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(), AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

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

4328 {
4329  /*
4330  * Forget the pending-events list.
4331  *
4332  * Since all the info is in TopTransactionContext or children thereof, we
4333  * don't really need to do anything to reclaim memory. However, the
4334  * pending-events list could be large, and so it's useful to discard it as
4335  * soon as possible --- especially if we are aborting because we ran out
4336  * of memory for the list!
4337  */
4339  {
4345  }
4346 
4347  /*
4348  * Forget any subtransaction state as well. Since this can't be very
4349  * large, we let the eventual reset of TopTransactionContext free the
4350  * memory instead of doing it here.
4351  */
4357 
4358 
4359  /*
4360  * Forget the query stack and constraint-related state information. As
4361  * with the subtransaction state information, we don't bother freeing the
4362  * memory here.
4363  */
4370 
4371  /* No more afterTriggers manipulation until next transaction starts. */
4373 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
CommandId * firing_stack
Definition: trigger.c:3407
SetConstraintState * state_stack
Definition: trigger.c:3404
SetConstraintState state
Definition: trigger.c:3392
AfterTriggerEventList * events_stack
Definition: trigger.c:3405
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3313
MemoryContext event_cxt
Definition: trigger.c:3400
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList events
Definition: trigger.c:3393
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
static void AfterTriggerEnlargeQueryState ( void  )
static

Definition at line 4575 of file trigger.c.

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

Referenced by AfterTriggerSaveEvent().

4576 {
4577  int init_depth = afterTriggers.maxquerydepth;
4578 
4580 
4581  if (afterTriggers.maxquerydepth == 0)
4582  {
4583  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4584 
4587  new_alloc * sizeof(AfterTriggerEventList));
4590  new_alloc * sizeof(Tuplestorestate *));
4593  new_alloc * sizeof(Tuplestorestate *));
4596  new_alloc * sizeof(Tuplestorestate *));
4597  afterTriggers.maxquerydepth = new_alloc;
4598  }
4599  else
4600  {
4601  /* repalloc will keep the stack in the same context */
4602  int old_alloc = afterTriggers.maxquerydepth;
4603  int new_alloc = Max(afterTriggers.query_depth + 1,
4604  old_alloc * 2);
4605 
4608  new_alloc * sizeof(AfterTriggerEventList));
4611  new_alloc * sizeof(Tuplestorestate *));
4614  new_alloc * sizeof(Tuplestorestate *));
4617  new_alloc * sizeof(Tuplestorestate *));
4618  /* Clear newly-allocated slots for subsequent lazy initialization. */
4619  memset(afterTriggers.fdw_tuplestores + old_alloc,
4620  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4621  memset(afterTriggers.old_tuplestores + old_alloc,
4622  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4623  memset(afterTriggers.new_tuplestores + old_alloc,
4624  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4625  afterTriggers.maxquerydepth = new_alloc;
4626  }
4627 
4628  /* Initialize new query lists to empty */
4629  while (init_depth < afterTriggers.maxquerydepth)
4630  {
4631  AfterTriggerEventList *events;
4632 
4633  events = &afterTriggers.query_stack[init_depth];
4634  events->head = NULL;
4635  events->tail = NULL;
4636  events->tailfree = NULL;
4637 
4638  ++init_depth;
4639  }
4640 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
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:3313
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
static void AfterTriggerExecute ( AfterTriggerEvent  event,
Relation  rel,
TriggerDesc trigdesc,
FmgrInfo finfo,
Instrumentation instr,
MemoryContext  per_tuple_context,
TupleTableSlot trig_tuple_slot1,
TupleTableSlot trig_tuple_slot2 
)
static

Definition at line 3715 of file trigger.c.

References AFTER_TRIGGER_2CTID, AFTER_TRIGGER_FDW_FETCH, AFTER_TRIGGER_FDW_REUSE, AFTER_TRIGGER_TUP_BITS, AfterTriggerEventData::ate_ctid1, AfterTriggerEventData::ate_ctid2, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_tgoid, elog, ERROR, ExecCallTriggerFunc(), ExecMaterializeSlot(), AfterTriggersData::fdw_tuplestores, GetTriggerSharedData, GetTriggerTransitionTuplestore(), heap_fetch(), heap_freetuple(), InstrStartNode(), InstrStopNode(), InvalidBuffer, ItemPointerCopy, ItemPointerIsValid, MemoryContextReset(), AfterTriggersData::new_tuplestores, NULL, TriggerDesc::numtriggers, AfterTriggersData::old_tuplestores, ReleaseBuffer(), SnapshotAny, HeapTupleData::t_self, T_TriggerData, 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_EVENT_OPMASK, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerDesc::triggers, tuplestore_gettupleslot(), and TriggerData::type.

Referenced by afterTriggerInvokeEvents().

3721 {
3722  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3723  Oid tgoid = evtshared->ats_tgoid;
3724  TriggerData LocTriggerData;
3725  HeapTupleData tuple1;
3726  HeapTupleData tuple2;
3727  HeapTuple rettuple;
3728  Buffer buffer1 = InvalidBuffer;
3729  Buffer buffer2 = InvalidBuffer;
3730  int tgindx;
3731 
3732  /*
3733  * Locate trigger in trigdesc.
3734  */
3735  LocTriggerData.tg_trigger = NULL;
3736  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3737  {
3738  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3739  {
3740  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3741  break;
3742  }
3743  }
3744  if (LocTriggerData.tg_trigger == NULL)
3745  elog(ERROR, "could not find trigger %u", tgoid);
3746 
3747  /*
3748  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3749  * to include time spent re-fetching tuples in the trigger cost.
3750  */
3751  if (instr)
3752  InstrStartNode(instr + tgindx);
3753 
3754  /*
3755  * Fetch the required tuple(s).
3756  */
3757  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3758  {
3760  {
3761  Tuplestorestate *fdw_tuplestore =
3764 
3765  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3766  trig_tuple_slot1))
3767  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3768 
3769  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3771  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3772  trig_tuple_slot2))
3773  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3774  }
3775  /* fall through */
3777 
3778  /*
3779  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3780  * ensures that tg_trigtuple does not reference tuplestore memory.
3781  * (It is formally possible for the trigger function to queue
3782  * trigger events that add to the same tuplestore, which can push
3783  * other tuples out of memory.) The distinction is academic,
3784  * because we start with a minimal tuple that ExecFetchSlotTuple()
3785  * must materialize anyway.
3786  */
3787  LocTriggerData.tg_trigtuple =
3788  ExecMaterializeSlot(trig_tuple_slot1);
3789  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3790 
3791  LocTriggerData.tg_newtuple =
3792  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3794  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3795  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3796 
3797  break;
3798 
3799  default:
3800  if (ItemPointerIsValid(&(event->ate_ctid1)))
3801  {
3802  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3803  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3804  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3805  LocTriggerData.tg_trigtuple = &tuple1;
3806  LocTriggerData.tg_trigtuplebuf = buffer1;
3807  }
3808  else
3809  {
3810  LocTriggerData.tg_trigtuple = NULL;
3811  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3812  }
3813 
3814  /* don't touch ctid2 if not there */
3815  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3817  ItemPointerIsValid(&(event->ate_ctid2)))
3818  {
3819  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3820  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3821  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3822  LocTriggerData.tg_newtuple = &tuple2;
3823  LocTriggerData.tg_newtuplebuf = buffer2;
3824  }
3825  else
3826  {
3827  LocTriggerData.tg_newtuple = NULL;
3828  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3829  }
3830  }
3831 
3832  /*
3833  * Set up the tuplestore information.
3834  */
3835  if (LocTriggerData.tg_trigger->tgoldtable)
3836  LocTriggerData.tg_oldtable =
3838  else
3839  LocTriggerData.tg_oldtable = NULL;
3840  if (LocTriggerData.tg_trigger->tgnewtable)
3841  LocTriggerData.tg_newtable =
3843  else
3844  LocTriggerData.tg_newtable = NULL;
3845 
3846  /*
3847  * Setup the remaining trigger information
3848  */
3849  LocTriggerData.type = T_TriggerData;
3850  LocTriggerData.tg_event =
3852  LocTriggerData.tg_relation = rel;
3853 
3854  MemoryContextReset(per_tuple_context);
3855 
3856  /*
3857  * Call the trigger and throw away any possibly returned updated tuple.
3858  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3859  */
3860  rettuple = ExecCallTriggerFunc(&LocTriggerData,
3861  tgindx,
3862  finfo,
3863  NULL,
3864  per_tuple_context);
3865  if (rettuple != NULL &&
3866  rettuple != LocTriggerData.tg_trigtuple &&
3867  rettuple != LocTriggerData.tg_newtuple)
3868  heap_freetuple(rettuple);
3869 
3870  /*
3871  * Release buffers
3872  */
3873  if (buffer1 != InvalidBuffer)
3874  ReleaseBuffer(buffer1);
3875  if (buffer2 != InvalidBuffer)
3876  ReleaseBuffer(buffer2);
3877 
3878  /*
3879  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3880  * one "tuple returned" (really the number of firings).
3881  */
3882  if (instr)
3883  InstrStopNode(instr + tgindx, 1);
3884 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TriggerEvent ats_event
Definition: trigger.c:3254
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3244
ItemPointerData ate_ctid2
Definition: trigger.c:3266
TriggerFlags ate_flags
Definition: trigger.c:3264
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:3248
#define InvalidBuffer
Definition: buf.h:25
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:56
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define GetTriggerSharedData(evt)
Definition: trigger.c:3289
#define ERROR
Definition: elog.h:43
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:63
ItemPointerData t_self
Definition: htup.h:65
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3247
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
TriggerEvent tg_event
Definition: trigger.h:33
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3432
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3245
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
NodeTag type
Definition: trigger.h:32
Tuplestorestate * tg_newtable
Definition: trigger.h:41
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
#define elog
Definition: elog.h:219
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2024
ItemPointerData ate_ctid1
Definition: trigger.c:3265
char * tgoldtable
Definition: reltrigger.h:42
int Buffer
Definition: buf.h:23
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:138
Relation tg_relation
Definition: trigger.h:34
void AfterTriggerFireDeferred ( void  )

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

4272 {
4273  AfterTriggerEventList *events;
4274  bool snap_pushed = false;
4275 
4276  /* Must not be inside a query */
4278 
4279  /*
4280  * If there are any triggers to fire, make sure we have set a snapshot for
4281  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4282  * can't assume ActiveSnapshot is valid on entry.)
4283  */
4284  events = &afterTriggers.events;
4285  if (events->head != NULL)
4286  {
4288  snap_pushed = true;
4289  }
4290 
4291  /*
4292  * Run all the remaining triggers. Loop until they are all gone, in case
4293  * some trigger queues more for us to do.
4294  */
4295  while (afterTriggerMarkEvents(events, NULL, false))
4296  {
4297  CommandId firing_id = afterTriggers.firing_counter++;
4298 
4299  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4300  break; /* all fired */
4301  }
4302 
4303  /*
4304  * We don't bother freeing the event list, since it will go away anyway
4305  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4306  */
4307 
4308  if (snap_pushed)
4310 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3974
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
CommandId firing_counter
Definition: trigger.c:3391
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3313
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3902
AfterTriggerEventList events
Definition: trigger.c:3393
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3637 of file trigger.c.

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

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

3638 {
3639  AfterTriggerEventChunk *chunk;
3640  AfterTriggerEventChunk *next_chunk;
3641 
3642  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3643  {
3644  next_chunk = chunk->next;
3645  pfree(chunk);
3646  }
3647  events->head = NULL;
3648  events->tail = NULL;
3649  events->tailfree = NULL;
3650 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
struct AfterTriggerEventChunk * next
Definition: trigger.c:3301
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3313
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

Definition at line 3974 of file trigger.c.

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

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

3978 {
3979  bool all_fired = true;
3980  AfterTriggerEventChunk *chunk;
3981  MemoryContext per_tuple_context;
3982  bool local_estate = false;
3983  Relation rel = NULL;
3984  TriggerDesc *trigdesc = NULL;
3985  FmgrInfo *finfo = NULL;
3986  Instrumentation *instr = NULL;
3987  TupleTableSlot *slot1 = NULL,
3988  *slot2 = NULL;
3989 
3990  /* Make a local EState if need be */
3991  if (estate == NULL)
3992  {
3993  estate = CreateExecutorState();
3994  local_estate = true;
3995  }
3996 
3997  /* Make a per-tuple memory context for trigger function calls */
3998  per_tuple_context =
4000  "AfterTriggerTupleContext",
4002 
4003  for_each_chunk(chunk, *events)
4004  {
4005  AfterTriggerEvent event;
4006  bool all_fired_in_chunk = true;
4007 
4008  for_each_event(event, chunk)
4009  {
4010  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4011 
4012  /*
4013  * Is it one for me to fire?
4014  */
4015  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
4016  evtshared->ats_firing_id == firing_id)
4017  {
4018  /*
4019  * So let's fire it... but first, find the correct relation if
4020  * this is not the same relation as before.
4021  */
4022  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
4023  {
4024  ResultRelInfo *rInfo;
4025 
4026  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
4027  rel = rInfo->ri_RelationDesc;
4028  trigdesc = rInfo->ri_TrigDesc;
4029  finfo = rInfo->ri_TrigFunctions;
4030  instr = rInfo->ri_TrigInstrument;
4031  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4032  {
4033  if (slot1 != NULL)
4034  {
4037  }
4038  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
4039  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
4040  }
4041  if (trigdesc == NULL) /* should not happen */
4042  elog(ERROR, "relation %u has no triggers",
4043  evtshared->ats_relid);
4044  }
4045 
4046  /*
4047  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
4048  * still set, so recursive examinations of the event list
4049  * won't try to re-fire it.
4050  */
4051  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
4052  per_tuple_context, slot1, slot2);
4053 
4054  /*
4055  * Mark the event as done.
4056  */
4057  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4058  event->ate_flags |= AFTER_TRIGGER_DONE;
4059  }
4060  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
4061  {
4062  /* something remains to be done */
4063  all_fired = all_fired_in_chunk = false;
4064  }
4065  }
4066 
4067  /* Clear the chunk if delete_ok and nothing left of interest */
4068  if (delete_ok && all_fired_in_chunk)
4069  {
4070  chunk->freeptr = CHUNK_DATA_START(chunk);
4071  chunk->endfree = chunk->endptr;
4072 
4073  /*
4074  * If it's last chunk, must sync event list's tailfree too. Note
4075  * that delete_ok must NOT be passed as true if there could be
4076  * stacked AfterTriggerEventList values pointing at this event
4077  * list, since we'd fail to fix their copies of tailfree.
4078  */
4079  if (chunk == events->tail)
4080  events->tailfree = chunk->freeptr;
4081  }
4082  }
4083  if (slot1 != NULL)
4084  {
4087  }
4088 
4089  /* Release working resources */
4090  MemoryContextDelete(per_tuple_context);
4091 
4092  if (local_estate)
4093  {
4094  ListCell *l;
4095 
4096  foreach(l, estate->es_trig_target_relations)
4097  {
4098  ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
4099 
4100  /* Close indices and then the relation itself */
4101  ExecCloseIndices(resultRelInfo);
4102  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
4103  }
4104  FreeExecutorState(estate);
4105  }
4106 
4107  return all_fired;
4108 }
Definition: fmgr.h:56
Relation ri_RelationDesc
Definition: execnodes.h:374
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
TriggerFlags ate_flags
Definition: trigger.c:3264
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3241
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3308
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:381
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
#define GetTriggerSharedData(evt)
Definition: trigger.c:3289
#define for_each_event(eptr, cptr)
Definition: trigger.c:3321
void FreeExecutorState(EState *estate)
Definition: execUtils.c:178
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define NoLock
Definition: lockdefs.h:34
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:378
EState * CreateExecutorState(void)
Definition: execUtils.c:80
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid)
Definition: execMain.c:1355
List * es_trig_target_relations
Definition: execnodes.h:426
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
TupleDesc rd_att
Definition: rel.h:115
#define for_each_chunk(cptr, evtlist)
Definition: trigger.c:3319
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
CommandId ats_firing_id
Definition: trigger.c:3257
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3242
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:417
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:224
static void AfterTriggerExecute(AfterTriggerEvent event, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
Definition: trigger.c:3715
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

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

3905 {
3906  bool found = false;
3907  AfterTriggerEvent event;
3908  AfterTriggerEventChunk *chunk;
3909 
3910  for_each_event_chunk(event, chunk, *events)
3911  {
3912  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3913  bool defer_it = false;
3914 
3915  if (!(event->ate_flags &
3917  {
3918  /*
3919  * This trigger hasn't been called or scheduled yet. Check if we
3920  * should call it now.
3921  */
3922  if (immediate_only && afterTriggerCheckState(evtshared))
3923  {
3924  defer_it = true;
3925  }
3926  else
3927  {
3928  /*
3929  * Mark it as to be fired in this firing cycle.
3930  */
3932  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3933  found = true;
3934  }
3935  }
3936 
3937  /*
3938  * If it's deferred, move it to move_list, if requested.
3939  */
3940  if (defer_it && move_list != NULL)
3941  {
3942  /* add it to move_list */
3943  afterTriggerAddEvent(move_list, event, evtshared);
3944  /* mark original copy "done" so we don't do it again */
3945  event->ate_flags |= AFTER_TRIGGER_DONE;
3946  }
3947  }
3948 
3949  return found;
3950 }
TriggerFlags ate_flags
Definition: trigger.c:3264
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3241
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3326
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3476
#define GetTriggerSharedData(evt)
Definition: trigger.c:3289
CommandId firing_counter
Definition: trigger.c:3391
#define NULL
Definition: c.h:229
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3522
CommandId ats_firing_id
Definition: trigger.c:3257
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3242
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
bool AfterTriggerPendingOnRel ( Oid  relid)

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

5016 {
5017  AfterTriggerEvent event;
5018  AfterTriggerEventChunk *chunk;
5019  int depth;
5020 
5021  /* Scan queued events */
5023  {
5024  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5025 
5026  /*
5027  * We can ignore completed events. (Even if a DONE flag is rolled
5028  * back by subxact abort, it's OK because the effects of the TRUNCATE
5029  * or whatever must get rolled back too.)
5030  */
5031  if (event->ate_flags & AFTER_TRIGGER_DONE)
5032  continue;
5033 
5034  if (evtshared->ats_relid == relid)
5035  return true;
5036  }
5037 
5038  /*
5039  * Also scan events queued by incomplete queries. This could only matter
5040  * if TRUNCATE/etc is executed by a function or trigger within an updating
5041  * query on the same relation, which is pretty perverse, but let's check.
5042  */
5043  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5044  {
5045  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
5046  {
5047  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5048 
5049  if (event->ate_flags & AFTER_TRIGGER_DONE)
5050  continue;
5051 
5052  if (evtshared->ats_relid == relid)
5053  return true;
5054  }
5055  }
5056 
5057  return false;
5058 }
TriggerFlags ate_flags
Definition: trigger.c:3264
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3241
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3326
#define GetTriggerSharedData(evt)
Definition: trigger.c:3289
AfterTriggerEventList events
Definition: trigger.c:3393
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
static void afterTriggerRestoreEventList ( AfterTriggerEventList events,
const AfterTriggerEventList old_events 
)
static

Definition at line 3660 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

3662 {
3663  AfterTriggerEventChunk *chunk;
3664  AfterTriggerEventChunk *next_chunk;
3665 
3666  if (old_events->tail == NULL)
3667  {
3668  /* restoring to a completely empty state, so free everything */
3669  afterTriggerFreeEventList(events);
3670  }
3671  else
3672  {
3673  *events = *old_events;
3674  /* free any chunks after the last one we want to keep */
3675  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3676  {
3677  next_chunk = chunk->next;
3678  pfree(chunk);
3679  }
3680  /* and clean up the tail chunk to be the right length */
3681  events->tail->next = NULL;
3682  events->tail->freeptr = events->tailfree;
3683 
3684  /*
3685  * We don't make any effort to remove now-unused shared data records.
3686  * They might still be useful, anyway.
3687  */
3688  }
3689 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3314
struct AfterTriggerEventChunk * next
Definition: trigger.c:3301
void pfree(void *pointer)
Definition: mcxt.c:950
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3637
#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 
)
static

Definition at line 5080 of file trigger.c.

References AFTER_TRIGGER_1CTID, AFTER_TRIGGER_2CTID, AFTER_TRIGGER_DEFERRABLE, AFTER_TRIGGER_FDW_FETCH, AFTER_TRIGGER_FDW_REUSE, AFTER_TRIGGER_INITDEFERRED, afterTriggerAddEvent(), AfterTriggerEnlargeQueryState(), Assert, AfterTriggerEventData::ate_ctid1, AfterTriggerEventData::ate_ctid2, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_event, AfterTriggerSharedData::ats_firing_id, AfterTriggerSharedData::ats_relid, AfterTriggerSharedData::ats_tgoid, elog, ERROR, AfterTriggersData::fdw_tuplestores, GetTriggerTransitionTuplestore(), i, ItemPointerCopy, ItemPointerSetInvalid, list_member_oid(), AfterTriggersData::maxquerydepth, AfterTriggersData::new_tuplestores, NULL, TriggerDesc::numtriggers, AfterTriggersData::old_tuplestores, AfterTriggersData::query_depth, AfterTriggersData::query_stack, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, RI_FKey_fk_upd_check_required(), RI_FKey_pk_upd_check_required(), RI_FKey_trigger_type(), ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, RI_TRIGGER_FK, RI_TRIGGER_NONE, RI_TRIGGER_PK, HeapTupleData::t_self, Trigger::tgconstrindid, Trigger::tgdeferrable, Trigger::tgfoid, Trigger::tginitdeferred, Trigger::tgoid, Trigger::tgtype, TriggerDesc::trig_delete_after_row, TriggerDesc::trig_delete_old_table, TriggerDesc::trig_insert_after_row, TriggerDesc::trig_insert_new_table, TriggerDesc::trig_update_after_row, TriggerDesc::trig_update_new_table, TriggerDesc::trig_update_old_table, 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().

5084 {
5085  Relation rel = relinfo->ri_RelationDesc;
5086  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
5087  AfterTriggerEventData new_event;
5088  AfterTriggerSharedData new_shared;
5089  char relkind = relinfo->ri_RelationDesc->rd_rel->relkind;
5090  int tgtype_event;
5091  int tgtype_level;
5092  int i;
5093  Tuplestorestate *fdw_tuplestore = NULL;
5094 
5095  /*
5096  * Check state. We use a normal test not Assert because it is possible to
5097  * reach here in the wrong state given misconfigured RI triggers, in
5098  * particular deferring a cascade action trigger.
5099  */
5100  if (afterTriggers.query_depth < 0)
5101  elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
5102 
5103  /* Be sure we have enough space to record events at this query depth. */
5106 
5107  /*
5108  * If the relation has AFTER ... FOR EACH ROW triggers, capture rows into
5109  * transition tuplestores for this depth.
5110  */
5111  if (row_trigger)
5112  {
5113  if ((event == TRIGGER_EVENT_DELETE &&
5114  trigdesc->trig_delete_old_table) ||
5115  (event == TRIGGER_EVENT_UPDATE &&
5116  trigdesc->trig_update_old_table))
5117  {
5118  Tuplestorestate *old_tuplestore;
5119 
5120  Assert(oldtup != NULL);
5121  old_tuplestore =
5124  tuplestore_puttuple(old_tuplestore, oldtup);
5125  }
5126  if ((event == TRIGGER_EVENT_INSERT &&
5127  trigdesc->trig_insert_new_table) ||
5128  (event == TRIGGER_EVENT_UPDATE &&
5129  trigdesc->trig_update_new_table))
5130  {
5131  Tuplestorestate *new_tuplestore;
5132 
5133  Assert(newtup != NULL);
5134  new_tuplestore =
5137  tuplestore_puttuple(new_tuplestore, newtup);
5138  }
5139 
5140  /* If transition tables are the only reason we're here, return. */
5141  if ((event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) ||
5142  (event == TRIGGER_EVENT_INSERT && !trigdesc->trig_insert_after_row) ||
5143  (event == TRIGGER_EVENT_UPDATE && !trigdesc->trig_update_after_row))
5144  return;
5145  }
5146 
5147  /*
5148  * Validate the event code and collect the associated tuple CTIDs.
5149  *
5150  * The event code will be used both as a bitmask and an array offset, so
5151  * validation is important to make sure we don't walk off the edge of our
5152  * arrays.
5153  */
5154  switch (event)
5155  {
5156  case TRIGGER_EVENT_INSERT:
5157  tgtype_event = TRIGGER_TYPE_INSERT;
5158  if (row_trigger)
5159  {
5160  Assert(oldtup == NULL);
5161  Assert(newtup != NULL);
5162  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
5163  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5164  }
5165  else
5166  {
5167  Assert(oldtup == NULL);
5168  Assert(newtup == NULL);
5169  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5170  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5171  }
5172  break;
5173  case TRIGGER_EVENT_DELETE:
5174  tgtype_event = TRIGGER_TYPE_DELETE;
5175  if (row_trigger)
5176  {
5177  Assert(oldtup != NULL);
5178  Assert(newtup == NULL);
5179  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5180  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5181  }
5182  else
5183  {
5184  Assert(oldtup == NULL);
5185  Assert(newtup == NULL);
5186  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5187  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5188  }
5189  break;
5190  case TRIGGER_EVENT_UPDATE:
5191  tgtype_event = TRIGGER_TYPE_UPDATE;
5192  if (row_trigger)
5193  {
5194  Assert(oldtup != NULL);
5195  Assert(newtup != NULL);
5196  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5197  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
5198  }
5199  else
5200  {
5201  Assert(oldtup == NULL);
5202  Assert(newtup == NULL);
5203  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5204  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5205  }
5206  break;
5208  tgtype_event = TRIGGER_TYPE_TRUNCATE;
5209  Assert(oldtup == NULL);
5210  Assert(newtup == NULL);
5211  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5212  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5213  break;
5214  default:
5215  elog(ERROR, "invalid after-trigger event code: %d", event);
5216  tgtype_event = 0; /* keep compiler quiet */
5217  break;
5218  }
5219 
5220  if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
5221  new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
5223  /* else, we'll initialize ate_flags for each trigger */
5224 
5225  tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
5226 
5227  for (i = 0; i < trigdesc->numtriggers; i++)
5228  {
5229  Trigger *trigger = &trigdesc->triggers[i];
5230 
5231  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
5232  tgtype_level,
5234  tgtype_event))
5235  continue;
5236  if (!TriggerEnabled(estate, relinfo, trigger, event,
5237  modifiedCols, oldtup, newtup))
5238  continue;
5239 
5240  if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
5241  {
5242  if (fdw_tuplestore == NULL)
5243  {
5244  fdw_tuplestore =
5247  new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
5248  }
5249  else
5250  /* subsequent event for the same tuple */
5251  new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
5252  }
5253 
5254  /*
5255  * If the trigger is a foreign key enforcement trigger, there are
5256  * certain cases where we can skip queueing the event because we can
5257  * tell by inspection that the FK constraint will still pass.
5258  */
5259  if (TRIGGER_FIRED_BY_UPDATE(event))
5260  {
5261  switch (RI_FKey_trigger_type(trigger->tgfoid))
5262  {
5263  case RI_TRIGGER_PK:
5264  /* Update on trigger's PK table */
5265  if (!RI_FKey_pk_upd_check_required(trigger, rel,
5266  oldtup, newtup))
5267  {
5268  /* skip queuing this event */
5269  continue;
5270  }
5271  break;
5272 
5273  case RI_TRIGGER_FK:
5274  /* Update on trigger's FK table */
5275  if (!RI_FKey_fk_upd_check_required(trigger, rel,
5276  oldtup, newtup))
5277  {
5278  /* skip queuing this event */
5279  continue;
5280  }
5281  break;
5282 
5283  case RI_TRIGGER_NONE:
5284  /* Not an FK trigger */
5285  break;
5286  }
5287  }
5288 
5289  /*
5290  * If the trigger is a deferred unique constraint check trigger, only
5291  * queue it if the unique constraint was potentially violated, which
5292  * we know from index insertion time.
5293  */
5294  if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
5295  {
5296  if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
5297  continue; /* Uniqueness definitely not violated */
5298  }
5299 
5300  /*
5301  * Fill in event structure and add it to the current query's queue.
5302  */
5303  new_shared.ats_event =
5304  (event & TRIGGER_EVENT_OPMASK) |
5305  (row_trigger ? TRIGGER_EVENT_ROW : 0) |
5306  (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
5307  (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
5308  new_shared.ats_tgoid = trigger->tgoid;
5309  new_shared.ats_relid = RelationGetRelid(rel);
5310  new_shared.ats_firing_id = 0;
5311 
5313  &new_event, &new_shared);
5314  }
5315 
5316  /*
5317  * Finally, spool any foreign tuple(s). The tuplestore squashes them to
5318  * minimal tuples, so this loses any system columns. The executor lost
5319  * those columns before us, for an unrelated reason, so this is fine.
5320  */
5321  if (fdw_tuplestore)
5322  {
5323  if (oldtup != NULL)
5324  tuplestore_puttuple(fdw_tuplestore, oldtup);
5325  if (newtup != NULL)
5326  tuplestore_puttuple(fdw_tuplestore, newtup);
5327  }
5328 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TriggerEvent ats_event
Definition: trigger.c:3254
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3397
Relation ri_RelationDesc
Definition: execnodes.h:374
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3704
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3244
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:68
ItemPointerData ate_ctid2
Definition: trigger.c:3266
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
Oid tgfoid
Definition: reltrigger.h:28
TriggerFlags ate_flags
Definition: trigger.c:3264
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:67
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Oid tgoid
Definition: reltrigger.h:25
bool trig_update_new_table
Definition: reltrigger.h:76
Form_pg_class rd_rel
Definition: rel.h:114
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:56
bool trig_insert_new_table
Definition: reltrigger.h:74
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
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
bool trig_update_old_table
Definition: reltrigger.h:75
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3246
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3247
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
bool trig_update_after_row
Definition: reltrigger.h:61
int numtriggers
Definition: reltrigger.h:49
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, HeapTuple old_row, HeapTuple new_row)
Definition: ri_triggers.c:2144
#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:3021
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4575
#define RI_TRIGGER_FK
Definition: trigger.h:210
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:3522
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:55
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:2087
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3432
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3245
CommandId ats_firing_id
Definition: trigger.c:3257
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
#define RI_TRIGGER_PK
Definition: trigger.h:209
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:149
int i
bool trig_delete_old_table
Definition: reltrigger.h:77
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3396
AfterTriggerEventList * query_stack
Definition: trigger.c:3395
#define elog
Definition: elog.h:219
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
ItemPointerData ate_ctid1
Definition: trigger.c:3265
#define RI_TRIGGER_NONE
Definition: trigger.h:211
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:76
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
#define RelationGetRelid(relation)
Definition: rel.h:417
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3398
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:138
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

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

4722 {
4723  int my_level = GetCurrentTransactionNestLevel();
4724 
4725  /* If we haven't already done so, initialize our state. */
4726  if (afterTriggers.state == NULL)
4728 
4729  /*
4730  * If in a subtransaction, and we didn't save the current state already,
4731  * save it so it can be restored if the subtransaction aborts.
4732  */
4733  if (my_level > 1 &&
4734  afterTriggers.state_stack[my_level] == NULL)
4735  {
4736  afterTriggers.state_stack[my_level] =
4738  }
4739 
4740  /*
4741  * Handle SET CONSTRAINTS ALL ...
4742  */
4743  if (stmt->constraints == NIL)
4744  {
4745  /*
4746  * Forget any previous SET CONSTRAINTS commands in this transaction.
4747  */
4749 
4750  /*
4751  * Set the per-transaction ALL state to known.
4752  */
4753  afterTriggers.state->all_isset = true;
4755  }
4756  else
4757  {
4758  Relation conrel;
4759  Relation tgrel;
4760  List *conoidlist = NIL;
4761  List *tgoidlist = NIL;
4762  ListCell *lc;
4763 
4764  /*
4765  * Handle SET CONSTRAINTS constraint-name [, ...]
4766  *
4767  * First, identify all the named constraints and make a list of their
4768  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4769  * the same name within a schema, the specifications are not
4770  * necessarily unique. Our strategy is to target all matching
4771  * constraints within the first search-path schema that has any
4772  * matches, but disregard matches in schemas beyond the first match.
4773  * (This is a bit odd but it's the historical behavior.)
4774  */
4776 
4777  foreach(lc, stmt->constraints)
4778  {
4779  RangeVar *constraint = lfirst(lc);
4780  bool found;
4781  List *namespacelist;
4782  ListCell *nslc;
4783 
4784  if (constraint->catalogname)
4785  {
4786  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4787  ereport(ERROR,
4788  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4789  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4790  constraint->catalogname, constraint->schemaname,
4791  constraint->relname)));
4792  }
4793 
4794  /*
4795  * If we're given the schema name with the constraint, look only
4796  * in that schema. If given a bare constraint name, use the
4797  * search path to find the first matching constraint.
4798  */
4799  if (constraint->schemaname)
4800  {
4801  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4802  false);
4803 
4804  namespacelist = list_make1_oid(namespaceId);
4805  }
4806  else
4807  {
4808  namespacelist = fetch_search_path(true);
4809  }
4810 
4811  found = false;
4812  foreach(nslc, namespacelist)
4813  {
4814  Oid namespaceId = lfirst_oid(nslc);
4815  SysScanDesc conscan;
4816  ScanKeyData skey[2];
4817  HeapTuple tup;
4818 
4819  ScanKeyInit(&skey[0],
4821  BTEqualStrategyNumber, F_NAMEEQ,
4822  CStringGetDatum(constraint->relname));
4823  ScanKeyInit(&skey[1],
4825  BTEqualStrategyNumber, F_OIDEQ,
4826  ObjectIdGetDatum(namespaceId));
4827 
4828  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4829  true, NULL, 2, skey);
4830 
4831  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4832  {
4834 
4835  if (con->condeferrable)
4836  conoidlist = lappend_oid(conoidlist,
4837  HeapTupleGetOid(tup));
4838  else if (stmt->deferred)
4839  ereport(ERROR,
4840  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4841  errmsg("constraint \"%s\" is not deferrable",
4842  constraint->relname)));
4843  found = true;
4844  }
4845 
4846  systable_endscan(conscan);
4847 
4848  /*
4849  * Once we've found a matching constraint we do not search
4850  * later parts of the search path.
4851  */
4852  if (found)
4853  break;
4854  }
4855 
4856  list_free(namespacelist);
4857 
4858  /*
4859  * Not found ?
4860  */
4861  if (!found)
4862  ereport(ERROR,
4863  (errcode(ERRCODE_UNDEFINED_OBJECT),
4864  errmsg("constraint \"%s\" does not exist",
4865  constraint->relname)));
4866  }
4867 
4868  heap_close(conrel, AccessShareLock);
4869 
4870  /*
4871  * Now, locate the trigger(s) implementing each of these constraints,
4872  * and make a list of their OIDs.
4873  */
4875 
4876  foreach(lc, conoidlist)
4877  {
4878  Oid conoid = lfirst_oid(lc);
4879  bool found;
4880  ScanKeyData skey;
4881  SysScanDesc tgscan;
4882  HeapTuple htup;
4883 
4884  found = false;
4885 
4886  ScanKeyInit(&skey,
4888  BTEqualStrategyNumber, F_OIDEQ,
4889  ObjectIdGetDatum(conoid));
4890 
4891  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
4892  NULL, 1, &skey);
4893 
4894  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
4895  {
4896  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
4897 
4898  /*
4899  * Silently skip triggers that are marked as non-deferrable in
4900  * pg_trigger. This is not an error condition, since a
4901  * deferrable RI constraint may have some non-deferrable
4902  * actions.
4903  */
4904  if (pg_trigger->tgdeferrable)
4905  tgoidlist = lappend_oid(tgoidlist,
4906  HeapTupleGetOid(htup));
4907 
4908  found = true;
4909  }
4910 
4911  systable_endscan(tgscan);
4912 
4913  /* Safety check: a deferrable constraint should have triggers */
4914  if (!found)
4915  elog(ERROR, "no triggers found for constraint with OID %u",
4916  conoid);
4917  }
4918 
4919  heap_close(tgrel, AccessShareLock);
4920 
4921  /*
4922  * Now we can set the trigger states of individual triggers for this
4923  * xact.
4924  */
4925  foreach(lc, tgoidlist)
4926  {
4927  Oid tgoid = lfirst_oid(lc);
4929  bool found = false;
4930  int i;
4931 
4932  for (i = 0; i < state->numstates; i++)
4933  {
4934  if (state->trigstates[i].sct_tgoid == tgoid)
4935  {
4936  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
4937  found = true;
4938  break;
4939  }
4940  }
4941  if (!found)
4942  {
4944  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
4945  }
4946  }
4947  }
4948 
4949  /*
4950  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
4951  * checks against that constraint must be made when the SET CONSTRAINTS
4952  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
4953  * apply retroactively. We've updated the constraints state, so scan the
4954  * list of previously deferred events to fire any that have now become
4955  * immediate.
4956  *
4957  * Obviously, if this was SET ... DEFERRED then it can't have converted
4958  * any unfired events to immediate, so we need do nothing in that case.
4959  */
4960  if (!stmt->deferred)
4961  {
4963  bool snapshot_set = false;
4964 
4965  while (afterTriggerMarkEvents(events, NULL, true))
4966  {
4967  CommandId firing_id = afterTriggers.firing_counter++;
4968 
4969  /*
4970  * Make sure a snapshot has been established in case trigger
4971  * functions need one. Note that we avoid setting a snapshot if
4972  * we don't find at least one trigger that has to be fired now.
4973  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
4974  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
4975  * at the start of a transaction it's not possible for any trigger
4976  * events to be queued yet.)
4977  */
4978  if (!snapshot_set)
4979  {
4981  snapshot_set = true;
4982  }
4983 
4984  /*
4985  * We can delete fired events if we are at top transaction level,
4986  * but we'd better not if inside a subtransaction, since the
4987  * subtransaction could later get rolled back.
4988  */
4989  if (afterTriggerInvokeEvents(events, firing_id, NULL,
4990  !IsSubTransaction()))
4991  break; /* all fired */
4992  }
4993 
4994  if (snapshot_set)
4996  }
4997 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:411
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2743
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:3201
#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:4691
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3974
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
#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:300
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:3404
SetConstraintState state
Definition: trigger.c:3392
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
#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:4646
#define list_make1_oid(x1)
Definition: pg_list.h:151
Oid MyDatabaseId
Definition: globals.c:76
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
CommandId firing_counter
Definition: trigger.c:3391
#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:4376
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:3902
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3393
#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:4074
static AfterTriggersData afterTriggers
Definition: trigger.c:3411
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:4671
static void ConvertTriggerToFK ( CreateTrigStmt stmt,
Oid  funcoid 
)
static

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

942 {
943  static List *info_list = NIL;
944 
945  static const char *const funcdescr[3] = {
946  gettext_noop("Found referenced table's UPDATE trigger."),
947  gettext_noop("Found referenced table's DELETE trigger."),
948  gettext_noop("Found referencing table's trigger.")
949  };
950 
951  char *constr_name;
952  char *fk_table_name;
953  char *pk_table_name;
954  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
955  List *fk_attrs = NIL;
956  List *pk_attrs = NIL;
958  int funcnum;
959  OldTriggerInfo *info = NULL;
960  ListCell *l;
961  int i;
962 
963  /* Parse out the trigger arguments */
964  constr_name = strVal(linitial(stmt->args));
965  fk_table_name = strVal(lsecond(stmt->args));
966  pk_table_name = strVal(lthird(stmt->args));
967  i = 0;
968  foreach(l, stmt->args)
969  {
970  Value *arg = (Value *) lfirst(l);
971 
972  i++;
973  if (i < 4) /* skip constraint and table names */
974  continue;
975  if (i == 4) /* handle match type */
976  {
977  if (strcmp(strVal(arg), "FULL") == 0)
978  fk_matchtype = FKCONSTR_MATCH_FULL;
979  else
980  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
981  continue;
982  }
983  if (i % 2)
984  fk_attrs = lappend(fk_attrs, arg);
985  else
986  pk_attrs = lappend(pk_attrs, arg);
987  }
988 
989  /* Prepare description of constraint for use in messages */
990  initStringInfo(&buf);
991  appendStringInfo(&buf, "FOREIGN KEY %s(",
992  quote_identifier(fk_table_name));
993  i = 0;
994  foreach(l, fk_attrs)
995  {
996  Value *arg = (Value *) lfirst(l);
997 
998  if (i++ > 0)
999  appendStringInfoChar(&buf, ',');
1001  }
1002  appendStringInfo(&buf, ") REFERENCES %s(",
1003  quote_identifier(pk_table_name));
1004  i = 0;
1005  foreach(l, pk_attrs)
1006  {
1007  Value *arg = (Value *) lfirst(l);
1008 
1009  if (i++ > 0)
1010  appendStringInfoChar(&buf, ',');
1012  }
1013  appendStringInfoChar(&buf, ')');
1014 
1015  /* Identify class of trigger --- update, delete, or referencing-table */
1016  switch (funcoid)
1017  {
1018  case F_RI_FKEY_CASCADE_UPD:
1019  case F_RI_FKEY_RESTRICT_UPD:
1020  case F_RI_FKEY_SETNULL_UPD:
1021  case F_RI_FKEY_SETDEFAULT_UPD:
1022  case F_RI_FKEY_NOACTION_UPD:
1023  funcnum = 0;
1024  break;
1025 
1026  case F_RI_FKEY_CASCADE_DEL:
1027  case F_RI_FKEY_RESTRICT_DEL:
1028  case F_RI_FKEY_SETNULL_DEL:
1029  case F_RI_FKEY_SETDEFAULT_DEL:
1030  case F_RI_FKEY_NOACTION_DEL:
1031  funcnum = 1;
1032  break;
1033 
1034  default:
1035  funcnum = 2;
1036  break;
1037  }
1038 
1039  /* See if we have a match to this trigger */
1040  foreach(l, info_list)
1041  {
1042  info = (OldTriggerInfo *) lfirst(l);
1043  if (info->funcoids[funcnum] == InvalidOid &&
1044  equal(info->args, stmt->args))
1045  {
1046  info->funcoids[funcnum] = funcoid;
1047  break;
1048  }
1049  }
1050 
1051  if (l == NULL)
1052  {
1053  /* First trigger of set, so create a new list entry */
1054  MemoryContext oldContext;
1055 
1056  ereport(NOTICE,
1057  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1058  constr_name, buf.data),
1059  errdetail_internal("%s", _(funcdescr[funcnum]))));
1061  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
1062  info->args = copyObject(stmt->args);
1063  info->funcoids[funcnum] = funcoid;
1064  info_list = lappend(info_list, info);
1065  MemoryContextSwitchTo(oldContext);
1066  }
1067  else if (info->funcoids[0] == InvalidOid ||
1068  info->funcoids[1] == InvalidOid ||
1069  info->funcoids[2] == InvalidOid)
1070  {
1071  /* Second trigger of set */
1072  ereport(NOTICE,
1073  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1074  constr_name, buf.data),
1075  errdetail_internal("%s", _(funcdescr[funcnum]))));
1076  }
1077  else
1078  {
1079  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
1082  Constraint *fkcon = makeNode(Constraint);
1083  PlannedStmt *wrapper = makeNode(PlannedStmt);
1084 
1085  ereport(NOTICE,
1086  (errmsg("converting trigger group into constraint \"%s\" %s",
1087  constr_name, buf.data),
1088  errdetail_internal("%s", _(funcdescr[funcnum]))));
1089  fkcon->contype = CONSTR_FOREIGN;
1090  fkcon->location = -1;
1091  if (funcnum == 2)
1092  {
1093  /* This trigger is on the FK table */
1094  atstmt->relation = stmt->relation;
1095  if (stmt->constrrel)
1096  fkcon->pktable = stmt->constrrel;
1097  else
1098  {
1099  /* Work around ancient pg_dump bug that omitted constrrel */
1100  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
1101  }
1102  }
1103  else
1104  {
1105  /* This trigger is on the PK table */
1106  fkcon->pktable = stmt->relation;
1107  if (stmt->constrrel)
1108  atstmt->relation = stmt->constrrel;
1109  else
1110  {
1111  /* Work around ancient pg_dump bug that omitted constrrel */
1112  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1113  }
1114  }
1115  atstmt->cmds = list_make1(atcmd);
1116  atstmt->relkind = OBJECT_TABLE;
1117  atcmd->subtype = AT_AddConstraint;
1118  atcmd->def = (Node *) fkcon;
1119  if (strcmp(constr_name, "<unnamed>") == 0)
1120  fkcon->conname = NULL;
1121  else
1122  fkcon->conname = constr_name;
1123  fkcon->fk_attrs = fk_attrs;
1124  fkcon->pk_attrs = pk_attrs;
1125  fkcon->fk_matchtype = fk_matchtype;
1126  switch (info->funcoids[0])
1127  {
1128  case F_RI_FKEY_NOACTION_UPD:
1130  break;
1131  case F_RI_FKEY_CASCADE_UPD:
1133  break;
1134  case F_RI_FKEY_RESTRICT_UPD:
1136  break;
1137  case F_RI_FKEY_SETNULL_UPD:
1139  break;
1140  case F_RI_FKEY_SETDEFAULT_UPD:
1142  break;
1143  default:
1144  /* can't get here because of earlier checks */
1145  elog(ERROR, "confused about RI update function");
1146  }
1147  switch (info->funcoids[1])
1148  {
1149  case F_RI_FKEY_NOACTION_DEL:
1151  break;
1152  case F_RI_FKEY_CASCADE_DEL:
1154  break;
1155  case F_RI_FKEY_RESTRICT_DEL:
1157  break;
1158  case F_RI_FKEY_SETNULL_DEL:
1160  break;
1161  case F_RI_FKEY_SETDEFAULT_DEL:
1163  break;
1164  default:
1165  /* can't get here because of earlier checks */
1166  elog(ERROR, "confused about RI delete function");
1167  }
1168  fkcon->deferrable = stmt->deferrable;
1169  fkcon->initdeferred = stmt->initdeferred;
1170  fkcon->skip_validation = false;
1171  fkcon->initially_valid = true;
1172 
1173  /* finally, wrap it in a dummy PlannedStmt */
1174  wrapper->commandType = CMD_UTILITY;
1175  wrapper->canSetTag = false;
1176  wrapper->utilityStmt = (Node *) atstmt;
1177  wrapper->stmt_location = -1;
1178  wrapper->stmt_len = -1;
1179 
1180  /* ... and execute it */
1181  ProcessUtility(wrapper,
1182  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1184  None_Receiver, NULL);
1185 
1186  /* Remove the matched item from the list */
1187  info_list = list_delete_ptr(info_list, info);
1188  pfree(info);
1189  /* We leak the copied args ... not worth worrying about */
1190  }
1191 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2041
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10254
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2032
char fk_matchtype
Definition: parsenodes.h:2078
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2036
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:2051
AlterTableType subtype
Definition: parsenodes.h:1745
List * pk_attrs
Definition: parsenodes.h:2077
char * conname
Definition: parsenodes.h:2049
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:88
#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:2335
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2050
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
int stmt_location
Definition: plannodes.h:87
static char * buf
Definition: pg_test_fsync.c:66
Node * utilityStmt
Definition: plannodes.h:84
Oid funcoids[3]
Definition: trigger.c:936
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1660
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2034
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2039
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:2086
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:557
char fk_del_action
Definition: parsenodes.h:2080
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:935
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1658
int i
RangeVar * relation
Definition: parsenodes.h:2319
ConstrType contype
Definition: parsenodes.h:2046
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2033
#define lthird(l)
Definition: pg_list.h:121
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:621
RangeVar * pktable
Definition: parsenodes.h:2075
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2035
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:2085
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:2076
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:2079
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1834 {
1835  TriggerDesc *newdesc;
1836  Trigger *trigger;
1837  int i;
1838 
1839  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1840  return NULL;
1841 
1842  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1843  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1844 
1845  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1846  memcpy(trigger, trigdesc->triggers,
1847  trigdesc->numtriggers * sizeof(Trigger));
1848  newdesc->triggers = trigger;
1849 
1850  for (i = 0; i < trigdesc->numtriggers; i++)
1851  {
1852  trigger->tgname = pstrdup(trigger->tgname);
1853  if (trigger->tgnattr > 0)
1854  {
1855  int16 *newattr;
1856 
1857  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1858  memcpy(newattr, trigger->tgattr,
1859  trigger->tgnattr * sizeof(int16));
1860  trigger->tgattr = newattr;
1861  }
1862  if (trigger->tgnargs > 0)
1863  {
1864  char **newargs;
1865  int16 j;
1866 
1867  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1868  for (j = 0; j < trigger->tgnargs; j++)
1869  newargs[j] = pstrdup(trigger->tgargs[j]);
1870  trigger->tgargs = newargs;
1871  }
1872  if (trigger->tgqual)
1873  trigger->tgqual = pstrdup(trigger->tgqual);
1874  if (trigger->tgoldtable)
1875  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1876  if (trigger->tgnewtable)
1877  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1878  trigger++;
1879  }
1880 
1881  return newdesc;
1882 }
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 138 of file trigger.c.

References AccessShareLock, ACL_EXECUTE, ACL_KIND_CLASS, ACL_KIND_PROC, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addRangeTableEntryForRelation(), addRTEtoQuery(), allowSystemTableMods, Anum_pg_trigger_tgargs, Anum_pg_trigger_tgattr, Anum_pg_trigger_tgconstraint, Anum_pg_trigger_tgconstrindid, Anum_pg_trigger_tgconstrrelid, Anum_pg_trigger_tgdeferrable, Anum_pg_trigger_tgenabled, Anum_pg_trigger_tgfoid, Anum_pg_trigger_tginitdeferred, Anum_pg_trigger_tgisinternal, Anum_pg_trigger_tgname, Anum_pg_trigger_tgnargs, Anum_pg_trigger_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(), 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_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().

141 {
142  int16 tgtype;
143  int ncolumns;
144  int16 *columns;
145  int2vector *tgattr;
146  Node *whenClause;
147  List *whenRtable;
148  char *qual;
150  bool nulls[Natts_pg_trigger];
151  Relation rel;
152  AclResult aclresult;
153  Relation tgrel;
154  SysScanDesc tgscan;
155  ScanKeyData key;
156  Relation pgrel;
157  HeapTuple tuple;
158  Oid fargtypes[1]; /* dummy */
159  Oid funcoid;
160  Oid funcrettype;
161  Oid trigoid;
162  char internaltrigname[NAMEDATALEN];
163  char *trigname;
164  Oid constrrelid = InvalidOid;
165  ObjectAddress myself,
166  referenced;
167  char *oldtablename = NULL;
168  char *newtablename = NULL;
169 
170  if (OidIsValid(relOid))
171  rel = heap_open(relOid, ShareRowExclusiveLock);
172  else
174 
175  /*
176  * Triggers must be on tables or views, and there are additional
177  * relation-type-specific restrictions.
178  */
179  if (rel->rd_rel->relkind == RELKIND_RELATION ||
180  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
181  {
182  /* Tables can't have INSTEAD OF triggers */
183  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
184  stmt->timing != TRIGGER_TYPE_AFTER)
185  ereport(ERROR,
186  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
187  errmsg("\"%s\" is a table",
189  errdetail("Tables cannot have INSTEAD OF triggers.")));
190  /* Disallow ROW triggers on partitioned tables */
191  if (stmt->row && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
192  ereport(ERROR,
193  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
194  errmsg("\"%s\" is a partitioned table",
196  errdetail("Partitioned tables cannot have ROW triggers.")));
197  }
198  else if (rel->rd_rel->relkind == RELKIND_VIEW)
199  {
200  /*
201  * Views can have INSTEAD OF triggers (which we check below are
202  * row-level), or statement-level BEFORE/AFTER triggers.
203  */
204  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
205  ereport(ERROR,
206  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
207  errmsg("\"%s\" is a view",
209  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
210  /* Disallow TRUNCATE triggers on VIEWs */
211  if (TRIGGER_FOR_TRUNCATE(stmt->events))
212  ereport(ERROR,
213  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
214  errmsg("\"%s\" is a view",
216  errdetail("Views cannot have TRUNCATE triggers.")));
217  }
218  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
219  {
220  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
221  stmt->timing != TRIGGER_TYPE_AFTER)
222  ereport(ERROR,
223  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
224  errmsg("\"%s\" is a foreign table",
226  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
227 
228  if (TRIGGER_FOR_TRUNCATE(stmt->events))
229  ereport(ERROR,
230  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
231  errmsg("\"%s\" is a foreign table",
233  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
234 
235  if (stmt->isconstraint)
236  ereport(ERROR,
237  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
238  errmsg("\"%s\" is a foreign table",
240  errdetail("Foreign tables cannot have constraint triggers.")));
241  }
242  else
243  ereport(ERROR,
244  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
245  errmsg("\"%s\" is not a table or view",
246  RelationGetRelationName(rel))));
247 
249  ereport(ERROR,
250  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
251  errmsg("permission denied: \"%s\" is a system catalog",
252  RelationGetRelationName(rel))));
253 
254  if (stmt->isconstraint)
255  {
256  /*
257  * We must take a lock on the target relation to protect against
258  * concurrent drop. It's not clear that AccessShareLock is strong
259  * enough, but we certainly need at least that much... otherwise, we
260  * might end up creating a pg_constraint entry referencing a
261  * nonexistent table.
262  */
263  if (OidIsValid(refRelOid))
264  {
265  LockRelationOid(refRelOid, AccessShareLock);
266  constrrelid = refRelOid;
267  }
268  else if (stmt->constrrel != NULL)
269  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
270  false);
271  }
272 
273  /* permission checks */
274  if (!isInternal)
275  {
276  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
277  ACL_TRIGGER);
278  if (aclresult != ACLCHECK_OK)
279  aclcheck_error(aclresult, ACL_KIND_CLASS,
281 
282  if (OidIsValid(constrrelid))
283  {
284  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
285  ACL_TRIGGER);
286  if (aclresult != ACLCHECK_OK)
287  aclcheck_error(aclresult, ACL_KIND_CLASS,
288  get_rel_name(constrrelid));
289  }
290  }
291 
292  /* Compute tgtype */
293  TRIGGER_CLEAR_TYPE(tgtype);
294  if (stmt->row)
295  TRIGGER_SETT_ROW(tgtype);
296  tgtype |= stmt->timing;
297  tgtype |= stmt->events;
298 
299  /* Disallow ROW-level TRUNCATE triggers */
300  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
301  ereport(ERROR,
302  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
303  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
304 
305  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
306  if (TRIGGER_FOR_INSTEAD(tgtype))
307  {
308  if (!TRIGGER_FOR_ROW(tgtype))
309  ereport(ERROR,
310  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
311  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
312  if (stmt->whenClause)
313  ereport(ERROR,
314  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
315  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
316  if (stmt->columns != NIL)
317  ereport(ERROR,
318  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
319  errmsg("INSTEAD OF triggers cannot have column lists")));
320  }
321 
322  /*
323  * We don't yet support naming ROW transition variables, but the parser
324  * recognizes the syntax so we can give a nicer message here.
325  *
326  * Per standard, REFERENCING TABLE names are only allowed on AFTER
327  * triggers. Per standard, REFERENCING ROW names are not allowed with FOR
328  * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is
329  * only allowed once. Per standard, OLD may not be specified when
330  * creating a trigger only for INSERT, and NEW may not be specified when
331  * creating a trigger only for DELETE.
332  *
333  * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to
334  * reference both ROW and TABLE transition data.
335  */
336  if (stmt->transitionRels != NIL)
337  {
338  List *varList = stmt->transitionRels;
339  ListCell *lc;
340 
341  foreach(lc, varList)
342  {
344 
345  if (!(tt->isTable))
346  ereport(ERROR,
347  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
348  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
349  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
350 
351  /*
352  * Because of the above test, we omit further ROW-related testing
353  * below. If we later allow naming OLD and NEW ROW variables,
354  * adjustments will be needed below.
355  */
356 
357  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
358  ereport(ERROR,
359  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
360  errmsg("\"%s\" is a partitioned table",
362  errdetail("Triggers on partitioned tables cannot have transition tables.")));
363 
364  if (stmt->timing != TRIGGER_TYPE_AFTER)
365  ereport(ERROR,
366  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
367  errmsg("transition table name can only be specified for an AFTER trigger")));
368 
369  if (tt->isNew)
370  {
371  if (!(TRIGGER_FOR_INSERT(tgtype) ||
372  TRIGGER_FOR_UPDATE(tgtype)))
373  ereport(ERROR,
374  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
375  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
376 
377  if (newtablename != NULL)
378  ereport(ERROR,
379  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
380  errmsg("NEW TABLE cannot be specified multiple times")));
381 
382  newtablename = tt->name;
383  }
384  else
385  {
386  if (!(TRIGGER_FOR_DELETE(tgtype) ||
387  TRIGGER_FOR_UPDATE(tgtype)))
388  ereport(ERROR,
389  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
390  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
391 
392  if (oldtablename != NULL)
393  ereport(ERROR,
394  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
395  errmsg("OLD TABLE cannot be specified multiple times")));
396 
397  oldtablename = tt->name;
398  }
399  }
400 
401  if (newtablename != NULL && oldtablename != NULL &&
402  strcmp(newtablename, oldtablename) == 0)
403  ereport(ERROR,
404  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
405  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
406  }
407 
408  /*
409  * Parse the WHEN clause, if any
410  */
411  if (stmt->whenClause)
412  {
413  ParseState *pstate;
414  RangeTblEntry *rte;
415  List *varList;
416  ListCell *lc;
417 
418  /* Set up a pstate to parse with */
419  pstate = make_parsestate(NULL);
420  pstate->p_sourcetext = queryString;
421 
422  /*
423  * Set up RTEs for OLD and NEW references.
424  *
425  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
426  */
427  rte = addRangeTableEntryForRelation(pstate, rel,
428  makeAlias("old", NIL),
429  false, false);
430  addRTEtoQuery(pstate, rte, false, true, true);
431  rte = addRangeTableEntryForRelation(pstate, rel,
432  makeAlias("new", NIL),
433  false, false);
434  addRTEtoQuery(pstate, rte, false, true, true);
435 
436  /* Transform expression. Copy to be sure we don't modify original */
437  whenClause = transformWhereClause(pstate,
438  copyObject(stmt->whenClause),
440  "WHEN");
441  /* we have to fix its collations too */
442  assign_expr_collations(pstate, whenClause);
443 
444  /*
445  * Check for disallowed references to OLD/NEW.
446  *
447  * NB: pull_var_clause is okay here only because we don't allow
448  * subselects in WHEN clauses; it would fail to examine the contents
449  * of subselects.
450  */
451  varList = pull_var_clause(whenClause, 0);
452  foreach(lc, varList)
453  {
454  Var *var = (Var *) lfirst(lc);
455 
456  switch (var->varno)
457  {
458  case PRS2_OLD_VARNO:
459  if (!TRIGGER_FOR_ROW(tgtype))
460  ereport(ERROR,
461  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
462  errmsg("statement trigger's WHEN condition cannot reference column values"),
463  parser_errposition(pstate, var->location)));
464  if (TRIGGER_FOR_INSERT(tgtype))
465  ereport(ERROR,
466  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
467  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
468  parser_errposition(pstate, var->location)));
469  /* system columns are okay here */
470  break;
471  case PRS2_NEW_VARNO:
472  if (!TRIGGER_FOR_ROW(tgtype))
473  ereport(ERROR,
474  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
475  errmsg("statement trigger's WHEN condition cannot reference column values"),
476  parser_errposition(pstate, var->location)));
477  if (TRIGGER_FOR_DELETE(tgtype))
478  ereport(ERROR,
479  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
480  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
481  parser_errposition(pstate, var->location)));
482  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
483  ereport(ERROR,
484  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
485  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
486  parser_errposition(pstate, var->location)));
487  break;
488  default:
489  /* can't happen without add_missing_from, so just elog */
490  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
491  break;
492  }
493  }
494 
495  /* we'll need the rtable for recordDependencyOnExpr */
496  whenRtable = pstate->p_rtable;
497 
498  qual = nodeToString(whenClause);
499 
500  free_parsestate(pstate);
501  }
502  else
503  {
504  whenClause = NULL;
505  whenRtable = NIL;
506  qual = NULL;
507  }
508 
509  /*
510  * Find and validate the trigger function.
511  */
512  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
513  if (!isInternal)
514  {
515  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
516  if (aclresult != ACLCHECK_OK)
517  aclcheck_error(aclresult, ACL_KIND_PROC,
518  NameListToString(stmt->funcname));
519  }
520  funcrettype = get_func_rettype(funcoid);
521  if (funcrettype != TRIGGEROID)
522  {
523  /*
524  * We allow OPAQUE just so we can load old dump files. When we see a
525  * trigger function declared OPAQUE, change it to TRIGGER.
526  */
527  if (funcrettype == OPAQUEOID)
528  {
530  (errmsg("changing return type of function %s from %s to %s",
531  NameListToString(stmt->funcname),
532  "opaque", "trigger")));
534  }
535  else
536  ereport(ERROR,
537  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
538  errmsg("function %s must return type %s",
539  NameListToString(stmt->funcname), "trigger")));
540  }
541 
542  /*
543  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
544  * references one of the built-in RI_FKey trigger functions, assume it is
545  * from a dump of a pre-7.3 foreign key constraint, and take steps to
546  * convert this legacy representation into a regular foreign key
547  * constraint. Ugly, but necessary for loading old dump files.
548  */
549  if (stmt->isconstraint && !isInternal &&
550  list_length(stmt->args) >= 6 &&
551  (list_length(stmt->args) % 2) == 0 &&
553  {
554  /* Keep lock on target rel until end of xact */
555  heap_close(rel, NoLock);
556 
557  ConvertTriggerToFK(stmt, funcoid);
558 
559  return InvalidObjectAddress;
560  }
561 
562  /*
563  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
564  * corresponding pg_constraint entry.
565  */
566  if (stmt->isconstraint && !OidIsValid(constraintOid))
567  {
568  /* Internal callers should have made their own constraints */
569  Assert(!isInternal);
570  constraintOid = CreateConstraintEntry(stmt->trigname,
573  stmt->deferrable,
574  stmt->initdeferred,
575  true,
576  RelationGetRelid(rel),
577  NULL, /* no conkey */
578  0,
579  InvalidOid, /* no domain */
580  InvalidOid, /* no index */
581  InvalidOid, /* no foreign key */
582  NULL,
583  NULL,
584  NULL,
585  NULL,
586  0,
587  ' ',
588  ' ',
589  ' ',
590  NULL, /* no exclusion */
591  NULL, /* no check constraint */
592  NULL,
593  NULL,
594  true, /* islocal */
595  0, /* inhcount */
596  true, /* isnoinherit */
597  isInternal); /* is_internal */
598  }
599 
600  /*
601  * Generate the trigger's OID now, so that we can use it in the name if
602  * needed.
603  */
605 
606  trigoid = GetNewOid(tgrel);
607 
608  /*
609  * If trigger is internally generated, modify the provided trigger name to
610  * ensure uniqueness by appending the trigger OID. (Callers will usually
611  * supply a simple constant trigger name in these cases.)
612  */
613  if (isInternal)
614  {
615  snprintf(internaltrigname, sizeof(internaltrigname),
616  "%s_%u", stmt->trigname, trigoid);
617  trigname = internaltrigname;
618  }
619  else
620  {
621  /* user-defined trigger; use the specified trigger name as-is */
622  trigname = stmt->trigname;
623  }
624 
625  /*
626  * Scan pg_trigger for existing triggers on relation. We do this only to
627  * give a nice error message if there's already a trigger of the same
628  * name. (The unique index on tgrelid/tgname would complain anyway.) We
629  * can skip this for internally generated triggers, since the name
630  * modification above should be sufficient.
631  *
632  * NOTE that this is cool only because we have ShareRowExclusiveLock on
633  * the relation, so the trigger set won't be changing underneath us.
634  */
635  if (!isInternal)
636  {
637  ScanKeyInit(&key,
639  BTEqualStrategyNumber, F_OIDEQ,
641  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
642  NULL, 1, &key);
643  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
644  {
645  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
646 
647  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
648  ereport(ERROR,
650  errmsg("trigger \"%s\" for relation \"%s\" already exists",
651  trigname, RelationGetRelationName(rel))));
652  }
653  systable_endscan(tgscan);
654  }
655 
656  /*
657  * Build the new pg_trigger tuple.
658  */
659  memset(nulls, false, sizeof(nulls));
660 
663  CStringGetDatum(trigname));
664  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
665  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
667  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
668  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
669  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
670  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
673 
674  if (stmt->args)
675  {
676  ListCell *le;
677  char *args;
678  int16 nargs = list_length(stmt->args);
679  int len = 0;
680 
681  foreach(le, stmt->args)
682  {
683  char *ar = strVal(lfirst(le));
684 
685  len += strlen(ar) + 4;
686  for (; *ar; ar++)
687  {
688  if (*ar == '\\')
689  len++;
690  }
691  }
692  args = (char *) palloc(len + 1);
693  args[0] = '\0';
694  foreach(le, stmt->args)
695  {
696  char *s = strVal(lfirst(le));
697  char *d = args + strlen(args);
698 
699  while (*s)
700  {
701  if (*s == '\\')
702  *d++ = '\\';
703  *d++ = *s++;
704  }
705  strcpy(d, "\\000");
706  }
707  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
709  CStringGetDatum(args));
710  }
711  else
712  {
713  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
715  CStringGetDatum(""));
716  }
717 
718  /* build column number array if it's a column-specific trigger */
719  ncolumns = list_length(stmt->columns);
720  if (ncolumns == 0)
721  columns = NULL;
722  else
723  {
724  ListCell *cell;
725  int i = 0;
726 
727  columns = (int16 *) palloc(ncolumns * sizeof(int16));
728  foreach(cell, stmt->columns)
729  {
730  char *name = strVal(lfirst(cell));
731  int16 attnum;
732  int j;
733 
734  /* Lookup column name. System columns are not allowed */
735  attnum = attnameAttNum(rel, name, false);
736  if (attnum == InvalidAttrNumber)
737  ereport(ERROR,
738  (errcode(ERRCODE_UNDEFINED_COLUMN),
739  errmsg("column \"%s\" of relation \"%s\" does not exist",
740  name, RelationGetRelationName(rel))));
741 
742  /* Check for duplicates */
743  for (j = i - 1; j >= 0; j--)
744  {
745  if (columns[j] == attnum)
746  ereport(ERROR,
747  (errcode(ERRCODE_DUPLICATE_COLUMN),
748  errmsg("column \"%s\" specified more than once",
749  name)));
750  }
751 
752  columns[i++] = attnum;
753  }
754  }
755  tgattr = buildint2vector(columns, ncolumns);
756  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
757 
758  /* set tgqual if trigger has WHEN clause */
759  if (qual)
760  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
761  else
762  nulls[Anum_pg_trigger_tgqual - 1] = true;
763 
764  if (oldtablename)
766  CStringGetDatum(oldtablename));
767  else
768  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
769  if (newtablename)
771  CStringGetDatum(newtablename));
772  else
773  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
774 
775  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
776 
777  /* force tuple to have the desired OID */
778  HeapTupleSetOid(tuple, trigoid);
779 
780  /*
781  * Insert tuple into pg_trigger.
782  */
783  CatalogTupleInsert(tgrel, tuple);
784 
785  heap_freetuple(tuple);
787 
791  if (oldtablename)
793  if (newtablename)
795 
796  /*
797  * Update relation's pg_class entry. Crucial side-effect: other backends
798  * (and this one too!) are sent SI message to make them rebuild relcache
799  * entries.
800  */
802  tuple = SearchSysCacheCopy1(RELOID,
804  if (!HeapTupleIsValid(tuple))
805  elog(ERROR, "cache lookup failed for relation %u",
806  RelationGetRelid(rel));
807 
808  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
809 
810  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
811 
812  heap_freetuple(tuple);
814 
815  /*
816  * We used to try to update the rel's relcache entry here, but that's
817  * fairly pointless since it will happen as a byproduct of the upcoming
818  * CommandCounterIncrement...
819  */
820 
821  /*
822  * Record dependencies for trigger. Always place a normal dependency on
823  * the function.
824  */
825  myself.classId = TriggerRelationId;
826  myself.objectId = trigoid;
827  myself.objectSubId = 0;
828 
829  referenced.classId = ProcedureRelationId;
830  referenced.objectId = funcoid;
831  referenced.objectSubId = 0;
832  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
833 
834  if (isInternal && OidIsValid(constraintOid))
835  {
836  /*
837  * Internally-generated trigger for a constraint, so make it an
838  * internal dependency of the constraint. We can skip depending on
839  * the relation(s), as there'll be an indirect dependency via the
840  * constraint.
841  */
842  referenced.classId = ConstraintRelationId;
843  referenced.objectId = constraintOid;
844  referenced.objectSubId = 0;
845  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
846  }
847  else
848  {
849  /*
850  * User CREATE TRIGGER, so place dependencies. We make trigger be
851  * auto-dropped if its relation is dropped or if the FK relation is
852  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
853  */
854  referenced.classId = RelationRelationId;
855  referenced.objectId = RelationGetRelid(rel);
856  referenced.objectSubId = 0;
857  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
858  if (OidIsValid(constrrelid))
859  {
860  referenced.classId = RelationRelationId;
861  referenced.objectId = constrrelid;
862  referenced.objectSubId = 0;
863  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
864  }
865  /* Not possible to have an index dependency in this case */
866  Assert(!OidIsValid(indexOid));
867 
868  /*
869  * If it's a user-specified constraint trigger, make the constraint
870  * internally dependent on the trigger instead of vice versa.
871  */
872  if (OidIsValid(constraintOid))
873  {
874  referenced.classId = ConstraintRelationId;
875  referenced.objectId = constraintOid;
876  referenced.objectSubId = 0;
877  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
878  }
879  }
880 
881  /* If column-specific trigger, add normal dependencies on columns */
882  if (columns != NULL)
883  {
884  int i;
885 
886  referenced.classId = RelationRelationId;
887  referenced.objectId = RelationGetRelid(rel);
888  for (i = 0; i < ncolumns; i++)
889  {
890  referenced.objectSubId = columns[i];
891  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
892  }
893  }
894 
895  /*
896  * If it has a WHEN clause, add dependencies on objects mentioned in the
897  * expression (eg, functions, as well as any columns used).
898  */
899  if (whenClause != NULL)
900  recordDependencyOnExpr(&myself, whenClause, whenRtable,
902 
903  /* Post creation hook for new trigger */
905  isInternal);
906 
907  /* Keep lock on target rel until end of xact */
908  heap_close(rel, NoLock);
909 
910  return myself;
911 }
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:3704
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:62
Oid GetUserId(void)
Definition: miscinit.c:283
#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:2328
#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:248
#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:1374
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:109
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:2335
#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
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:1338
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
const char * p_sourcetext
Definition: parse_node.h:168
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:941
List * transitionRels
Definition: parsenodes.h:2331
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
#define PRS2_OLD_VARNO
Definition: primnodes.h: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:2953
#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:288
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:111
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define NULL
Definition: c.h: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:1910
#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:161
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:2319
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:4218
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define CONSTRAINT_TRIGGER
#define copyObject(obj)
Definition: nodes.h:621
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:211
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define RelationGetRelid(relation)
Definition: rel.h:417
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:444
List * p_rtable
Definition: parse_node.h:169
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

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

1505 {
1506  Relation tgrel;
1507  int nkeys;
1508  ScanKeyData keys[2];
1509  SysScanDesc tgscan;
1510  HeapTuple tuple;
1511  bool found;
1512  bool changed;
1513 
1514  /* Scan the relevant entries in pg_triggers */
1516 
1517  ScanKeyInit(&keys[0],
1519  BTEqualStrategyNumber, F_OIDEQ,
1521  if (tgname)
1522  {
1523  ScanKeyInit(&keys[1],
1525  BTEqualStrategyNumber, F_NAMEEQ,
1526  CStringGetDatum(tgname));
1527  nkeys = 2;
1528  }
1529  else
1530  nkeys = 1;
1531 
1532  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1533  NULL, nkeys, keys);
1534 
1535  found = changed = false;
1536 
1537  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1538  {
1539  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1540 
1541  if (oldtrig->tgisinternal)
1542  {
1543  /* system trigger ... ok to process? */
1544  if (skip_system)
1545  continue;
1546  if (!superuser())
1547  ereport(ERROR,
1548  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1549  errmsg("permission denied: \"%s\" is a system trigger",
1550  NameStr(oldtrig->tgname))));
1551  }
1552 
1553  found = true;
1554 
1555  if (oldtrig->tgenabled != fires_when)
1556  {
1557  /* need to change this one ... make a copy to scribble on */
1558  HeapTuple newtup = heap_copytuple(tuple);
1559  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1560 
1561  newtrig->tgenabled = fires_when;
1562 
1563  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1564 
1565  heap_freetuple(newtup);
1566 
1567  changed = true;
1568  }
1569 
1571  HeapTupleGetOid(tuple), 0);
1572  }
1573 
1574  systable_endscan(tgscan);
1575 
1576  heap_close(tgrel, RowExclusiveLock);
1577 
1578  if (tgname && !found)
1579  ereport(ERROR,
1580  (errcode(ERRCODE_UNDEFINED_OBJECT),
1581  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1582  tgname, RelationGetRelationName(rel))));
1583 
1584  /*
1585  * If we changed anything, broadcast a SI inval message to force each
1586  * backend (including our own!) to rebuild relation's relcache entry.
1587  * Otherwise they will fail to apply the change promptly.
1588  */
1589  if (changed)
1591 }
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:1374
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:437
#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:1226
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:417
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2455 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2458 {
2459  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2460 
2461  if (trigdesc &&
2462  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2463  {
2464  HeapTuple trigtuple;
2465 
2466  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2467  if (fdw_trigtuple == NULL)
2468  trigtuple = GetTupleForTrigger(estate,
2469  NULL,
2470  relinfo,
2471  tupleid,
2473  NULL);
2474  else
2475  trigtuple = fdw_trigtuple;
2476 
2478  true, trigtuple, NULL, NIL, NULL);
2479  if (trigtuple != fdw_trigtuple)
2480  heap_freetuple(trigtuple);
2481  }
2482 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
bool trig_delete_after_row
Definition: reltrigger.h:66
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5080
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#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:2877
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

Definition at line 2246 of file trigger.c.

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

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

2248 {
2249  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2250 
2251  if (trigdesc &&
2252  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2254  true, NULL, trigtuple, recheckIndexes, NULL);
2255 }
bool trig_insert_new_table
Definition: reltrigger.h:74
bool trig_insert_after_row
Definition: reltrigger.h:56
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5080
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes 
)

Definition at line 2715 of file trigger.c.

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

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2720 {
2721  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2722 
2723  if (trigdesc && (trigdesc->trig_update_after_row ||
2724  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2725  {
2726  HeapTuple trigtuple;
2727 
2728  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2729  if (fdw_trigtuple == NULL)
2730  trigtuple = GetTupleForTrigger(estate,
2731  NULL,
2732  relinfo,
2733  tupleid,
2735  NULL);
2736  else
2737  trigtuple = fdw_trigtuple;
2738 
2740  true, trigtuple, newtuple, recheckIndexes,
2741  GetUpdatedColumns(relinfo, estate));
2742  if (trigtuple != fdw_trigtuple)
2743  heap_freetuple(trigtuple);
2744  }
2745 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
bool trig_update_new_table
Definition: reltrigger.h:76
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
bool trig_update_old_table
Definition: reltrigger.h:75
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5080
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
bool trig_update_after_row
Definition: reltrigger.h:61
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2877
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2376 of file trigger.c.

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

Referenced by fireASTriggers().

2377 {
2378  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2379 
2380  if (trigdesc && trigdesc->trig_delete_after_statement)
2382  false, NULL, NULL, NIL, NULL);
2383 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5080
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2170 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2171 {
2172  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2173 
2174  if (trigdesc && trigdesc->trig_insert_after_statement)
2175