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 3239 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3240 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3238 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

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

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3241 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3301 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 3312 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:3301
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3275
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3253

Definition at line 3314 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:3241
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3239
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3240

Definition at line 3275 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3253 of file trigger.c.

Definition at line 3243 of file trigger.c.

Definition at line 3230 of file trigger.c.

Function Documentation

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

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

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

Definition at line 4150 of file trigger.c.

References AfterTriggersData::query_depth.

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

4151 {
4152  /* Increase the query stack depth */
4154 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
void AfterTriggerBeginSubXact ( void  )

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

4375 {
4376  int my_level = GetCurrentTransactionNestLevel();
4377 
4378  /*
4379  * Allocate more space in the stacks if needed. (Note: because the
4380  * minimum nest level of a subtransaction is 2, we waste the first couple
4381  * entries of each array; not worth the notational effort to avoid it.)
4382  */
4383  while (my_level >= afterTriggers.maxtransdepth)
4384  {
4385  if (afterTriggers.maxtransdepth == 0)
4386  {
4387  MemoryContext old_cxt;
4388 
4390 
4391 #define DEFTRIG_INITALLOC 8
4396  afterTriggers.depth_stack = (int *)
4397  palloc(DEFTRIG_INITALLOC * sizeof(int));
4399  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4401 
4402  MemoryContextSwitchTo(old_cxt);
4403  }
4404  else
4405  {
4406  /* repalloc will keep the stacks in the same context */
4407  int new_alloc = afterTriggers.maxtransdepth * 2;
4408 
4411  new_alloc * sizeof(SetConstraintState));
4414  new_alloc * sizeof(AfterTriggerEventList));
4415  afterTriggers.depth_stack = (int *)
4417  new_alloc * sizeof(int));
4420  new_alloc * sizeof(CommandId));
4421  afterTriggers.maxtransdepth = new_alloc;
4422  }
4423  }
4424 
4425  /*
4426  * Push the current information into the stack. The SET CONSTRAINTS state
4427  * is not saved until/unless changed. Likewise, we don't make a
4428  * per-subtransaction event context until needed.
4429  */
4430  afterTriggers.state_stack[my_level] = NULL;
4434 }
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:3400
SetConstraintState * state_stack
Definition: trigger.c:3397
CommandId firing_counter
Definition: trigger.c:3384
AfterTriggerEventList * events_stack
Definition: trigger.c:3398
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:3386
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
void AfterTriggerBeginXact ( void  )

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

4113 {
4114  /*
4115  * Initialize after-trigger state structure to empty
4116  */
4117  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4119 
4120  /*
4121  * Verify that there is no leftover state remaining. If these assertions
4122  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4123  * up properly.
4124  */
4138 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
CommandId * firing_stack
Definition: trigger.c:3400
SetConstraintState * state_stack
Definition: trigger.c:3397
SetConstraintState state
Definition: trigger.c:3385
CommandId firing_counter
Definition: trigger.c:3384
AfterTriggerEventList * events_stack
Definition: trigger.c:3398
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3306
MemoryContext event_cxt
Definition: trigger.c:3393
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3389
AfterTriggerEventList events
Definition: trigger.c:3386
AfterTriggerEventList * query_stack
Definition: trigger.c:3388
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

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

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

4171 {
4172  AfterTriggerEventList *events;
4173  Tuplestorestate *fdw_tuplestore;
4174  Tuplestorestate *old_tuplestore;
4175  Tuplestorestate *new_tuplestore;
4176 
4177  /* Must be inside a query, too */
4179 
4180  /*
4181  * If we never even got as far as initializing the event stack, there
4182  * certainly won't be any events, so exit quickly.
4183  */
4185  {
4187  return;
4188  }
4189 
4190  /*
4191  * Process all immediate-mode triggers queued by the query, and move the
4192  * deferred ones to the main list of deferred events.
4193  *
4194  * Notice that we decide which ones will be fired, and put the deferred
4195  * ones on the main list, before anything is actually fired. This ensures
4196  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4197  * IMMEDIATE: all events we have decided to defer will be available for it
4198  * to fire.
4199  *
4200  * We loop in case a trigger queues more events at the same query level.
4201  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4202  * will instead fire any triggers in a dedicated query level. Foreign key
4203  * enforcement triggers do add to the current query level, thanks to their
4204  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4205  * C-language triggers might do likewise. Be careful here: firing a
4206  * trigger could result in query_stack being repalloc'd, so we can't save
4207  * its address across afterTriggerInvokeEvents calls.
4208  *
4209  * If we find no firable events, we don't have to increment
4210  * firing_counter.
4211  */
4212  for (;;)
4213  {
4215  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4216  {
4217  CommandId firing_id = afterTriggers.firing_counter++;
4218 
4219  /* OK to delete the immediate events after processing them */
4220  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4221  break; /* all fired */
4222  }
4223  else
4224  break;
4225  }
4226 
4227  /* Release query-local storage for events, including tuplestore if any */
4229  if (fdw_tuplestore)
4230  {
4231  tuplestore_end(fdw_tuplestore);
4233  }
4235  if (old_tuplestore)
4236  {
4237  tuplestore_end(old_tuplestore);
4239  }
4241  if (new_tuplestore)
4242  {
4243  tuplestore_end(new_tuplestore);
4245  }
4247 
4249 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3967
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3630
CommandId firing_counter
Definition: trigger.c:3384
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:450
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3895
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3389
AfterTriggerEventList events
Definition: trigger.c:3386
AfterTriggerEventList * query_stack
Definition: trigger.c:3388
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
void AfterTriggerEndSubXact ( bool  isCommit)

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

4443 {
4444  int my_level = GetCurrentTransactionNestLevel();
4446  AfterTriggerEvent event;
4447  AfterTriggerEventChunk *chunk;
4448  CommandId subxact_firing_id;
4449 
4450  /*
4451  * Pop the prior state if needed.
4452  */
4453  if (isCommit)
4454  {
4455  Assert(my_level < afterTriggers.maxtransdepth);
4456  /* If we saved a prior state, we don't need it anymore */
4457  state = afterTriggers.state_stack[my_level];
4458  if (state != NULL)
4459  pfree(state);
4460  /* this avoids double pfree if error later: */
4461  afterTriggers.state_stack[my_level] = NULL;
4463  afterTriggers.depth_stack[my_level]);
4464  }
4465  else
4466  {
4467  /*
4468  * Aborting. It is possible subxact start failed before calling
4469  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4470  * stack levels that aren't there.
4471  */
4472  if (my_level >= afterTriggers.maxtransdepth)
4473  return;
4474 
4475  /*
4476  * Release any event lists from queries being aborted, and restore
4477  * query_depth to its pre-subxact value. This assumes that a
4478  * subtransaction will not add events to query levels started in a
4479  * earlier transaction state.
4480  */
4482  {
4484  {
4485  Tuplestorestate *ts;
4486 
4488  if (ts)
4489  {
4490  tuplestore_end(ts);
4492  }
4494  if (ts)
4495  {
4496  tuplestore_end(ts);
4498  }
4500  if (ts)
4501  {
4502  tuplestore_end(ts);
4504  }
4505 
4507  }
4508 
4510  }
4512  afterTriggers.depth_stack[my_level]);
4513 
4514  /*
4515  * Restore the global deferred-event list to its former length,
4516  * discarding any events queued by the subxact.
4517  */
4519  &afterTriggers.events_stack[my_level]);
4520 
4521  /*
4522  * Restore the trigger state. If the saved state is NULL, then this
4523  * subxact didn't save it, so it doesn't need restoring.
4524  */
4525  state = afterTriggers.state_stack[my_level];
4526  if (state != NULL)
4527  {
4529  afterTriggers.state = state;
4530  }
4531  /* this avoids double pfree if error later: */
4532  afterTriggers.state_stack[my_level] = NULL;
4533 
4534  /*
4535  * Scan for any remaining deferred events that were marked DONE or IN
4536  * PROGRESS by this subxact or a child, and un-mark them. We can
4537  * recognize such events because they have a firing ID greater than or
4538  * equal to the firing_counter value we saved at subtransaction start.
4539  * (This essentially assumes that the current subxact includes all
4540  * subxacts started after it.)
4541  */
4542  subxact_firing_id = afterTriggers.firing_stack[my_level];
4544  {
4545  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4546 
4547  if (event->ate_flags &
4549  {
4550  if (evtshared->ats_firing_id >= subxact_firing_id)
4551  event->ate_flags &=
4553  }
4554  }
4555  }
4556 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
TriggerFlags ate_flags
Definition: trigger.c:3257
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3234
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3319
CommandId * firing_stack
Definition: trigger.c:3400
#define GetTriggerSharedData(evt)
Definition: trigger.c:3282
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3397
SetConstraintState state
Definition: trigger.c:3385
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3630
AfterTriggerEventList * events_stack
Definition: trigger.c:3398
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:450
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3653
CommandId ats_firing_id
Definition: trigger.c:3250
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3235
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3389
AfterTriggerEventList events
Definition: trigger.c:3386
AfterTriggerEventList * query_stack
Definition: trigger.c:3388
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
void AfterTriggerEndXact ( bool  isCommit)

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

4321 {
4322  /*
4323  * Forget the pending-events list.
4324  *
4325  * Since all the info is in TopTransactionContext or children thereof, we
4326  * don't really need to do anything to reclaim memory. However, the
4327  * pending-events list could be large, and so it's useful to discard it as
4328  * soon as possible --- especially if we are aborting because we ran out
4329  * of memory for the list!
4330  */
4332  {
4338  }
4339 
4340  /*
4341  * Forget any subtransaction state as well. Since this can't be very
4342  * large, we let the eventual reset of TopTransactionContext free the
4343  * memory instead of doing it here.
4344  */
4350 
4351 
4352  /*
4353  * Forget the query stack and constraint-related state information. As
4354  * with the subtransaction state information, we don't bother freeing the
4355  * memory here.
4356  */
4363 
4364  /* No more afterTriggers manipulation until next transaction starts. */
4366 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3307
CommandId * firing_stack
Definition: trigger.c:3400
SetConstraintState * state_stack
Definition: trigger.c:3397
SetConstraintState state
Definition: trigger.c:3385
AfterTriggerEventList * events_stack
Definition: trigger.c:3398
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3306
MemoryContext event_cxt
Definition: trigger.c:3393
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3389
AfterTriggerEventList events
Definition: trigger.c:3386
AfterTriggerEventList * query_stack
Definition: trigger.c:3388
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
static void AfterTriggerEnlargeQueryState ( void  )
static

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

4569 {
4570  int init_depth = afterTriggers.maxquerydepth;
4571 
4573 
4574  if (afterTriggers.maxquerydepth == 0)
4575  {
4576  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4577 
4580  new_alloc * sizeof(AfterTriggerEventList));
4583  new_alloc * sizeof(Tuplestorestate *));
4586  new_alloc * sizeof(Tuplestorestate *));
4589  new_alloc * sizeof(Tuplestorestate *));
4590  afterTriggers.maxquerydepth = new_alloc;
4591  }
4592  else
4593  {
4594  /* repalloc will keep the stack in the same context */
4595  int old_alloc = afterTriggers.maxquerydepth;
4596  int new_alloc = Max(afterTriggers.query_depth + 1,
4597  old_alloc * 2);
4598 
4601  new_alloc * sizeof(AfterTriggerEventList));
4604  new_alloc * sizeof(Tuplestorestate *));
4607  new_alloc * sizeof(Tuplestorestate *));
4610  new_alloc * sizeof(Tuplestorestate *));
4611  /* Clear newly-allocated slots for subsequent lazy initialization. */
4612  memset(afterTriggers.fdw_tuplestores + old_alloc,
4613  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4614  memset(afterTriggers.old_tuplestores + old_alloc,
4615  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4616  memset(afterTriggers.new_tuplestores + old_alloc,
4617  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4618  afterTriggers.maxquerydepth = new_alloc;
4619  }
4620 
4621  /* Initialize new query lists to empty */
4622  while (init_depth < afterTriggers.maxquerydepth)
4623  {
4624  AfterTriggerEventList *events;
4625 
4626  events = &afterTriggers.query_stack[init_depth];
4627  events->head = NULL;
4628  events->tail = NULL;
4629  events->tailfree = NULL;
4630 
4631  ++init_depth;
4632  }
4633 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3307
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:3306
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3389
AfterTriggerEventList * query_stack
Definition: trigger.c:3388
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
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 3708 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().

3714 {
3715  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3716  Oid tgoid = evtshared->ats_tgoid;
3717  TriggerData LocTriggerData;
3718  HeapTupleData tuple1;
3719  HeapTupleData tuple2;
3720  HeapTuple rettuple;
3721  Buffer buffer1 = InvalidBuffer;
3722  Buffer buffer2 = InvalidBuffer;
3723  int tgindx;
3724 
3725  /*
3726  * Locate trigger in trigdesc.
3727  */
3728  LocTriggerData.tg_trigger = NULL;
3729  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3730  {
3731  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3732  {
3733  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3734  break;
3735  }
3736  }
3737  if (LocTriggerData.tg_trigger == NULL)
3738  elog(ERROR, "could not find trigger %u", tgoid);
3739 
3740  /*
3741  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3742  * to include time spent re-fetching tuples in the trigger cost.
3743  */
3744  if (instr)
3745  InstrStartNode(instr + tgindx);
3746 
3747  /*
3748  * Fetch the required tuple(s).
3749  */
3750  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3751  {
3753  {
3754  Tuplestorestate *fdw_tuplestore =
3757 
3758  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3759  trig_tuple_slot1))
3760  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3761 
3762  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3764  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3765  trig_tuple_slot2))
3766  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3767  }
3768  /* fall through */
3770 
3771  /*
3772  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3773  * ensures that tg_trigtuple does not reference tuplestore memory.
3774  * (It is formally possible for the trigger function to queue
3775  * trigger events that add to the same tuplestore, which can push
3776  * other tuples out of memory.) The distinction is academic,
3777  * because we start with a minimal tuple that ExecFetchSlotTuple()
3778  * must materialize anyway.
3779  */
3780  LocTriggerData.tg_trigtuple =
3781  ExecMaterializeSlot(trig_tuple_slot1);
3782  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3783 
3784  LocTriggerData.tg_newtuple =
3785  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3787  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3788  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3789 
3790  break;
3791 
3792  default:
3793  if (ItemPointerIsValid(&(event->ate_ctid1)))
3794  {
3795  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3796  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3797  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3798  LocTriggerData.tg_trigtuple = &tuple1;
3799  LocTriggerData.tg_trigtuplebuf = buffer1;
3800  }
3801  else
3802  {
3803  LocTriggerData.tg_trigtuple = NULL;
3804  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3805  }
3806 
3807  /* don't touch ctid2 if not there */
3808  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3810  ItemPointerIsValid(&(event->ate_ctid2)))
3811  {
3812  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3813  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3814  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3815  LocTriggerData.tg_newtuple = &tuple2;
3816  LocTriggerData.tg_newtuplebuf = buffer2;
3817  }
3818  else
3819  {
3820  LocTriggerData.tg_newtuple = NULL;
3821  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3822  }
3823  }
3824 
3825  /*
3826  * Set up the tuplestore information.
3827  */
3828  if (LocTriggerData.tg_trigger->tgoldtable)
3829  LocTriggerData.tg_oldtable =
3831  else
3832  LocTriggerData.tg_oldtable = NULL;
3833  if (LocTriggerData.tg_trigger->tgnewtable)
3834  LocTriggerData.tg_newtable =
3836  else
3837  LocTriggerData.tg_newtable = NULL;
3838 
3839  /*
3840  * Setup the remaining trigger information
3841  */
3842  LocTriggerData.type = T_TriggerData;
3843  LocTriggerData.tg_event =
3845  LocTriggerData.tg_relation = rel;
3846 
3847  MemoryContextReset(per_tuple_context);
3848 
3849  /*
3850  * Call the trigger and throw away any possibly returned updated tuple.
3851  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3852  */
3853  rettuple = ExecCallTriggerFunc(&LocTriggerData,
3854  tgindx,
3855  finfo,
3856  NULL,
3857  per_tuple_context);
3858  if (rettuple != NULL &&
3859  rettuple != LocTriggerData.tg_trigtuple &&
3860  rettuple != LocTriggerData.tg_newtuple)
3861  heap_freetuple(rettuple);
3862 
3863  /*
3864  * Release buffers
3865  */
3866  if (buffer1 != InvalidBuffer)
3867  ReleaseBuffer(buffer1);
3868  if (buffer2 != InvalidBuffer)
3869  ReleaseBuffer(buffer2);
3870 
3871  /*
3872  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3873  * one "tuple returned" (really the number of firings).
3874  */
3875  if (instr)
3876  InstrStopNode(instr + tgindx, 1);
3877 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TriggerEvent ats_event
Definition: trigger.c:3247
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3390
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3237
ItemPointerData ate_ctid2
Definition: trigger.c:3259
TriggerFlags ate_flags
Definition: trigger.c:3257
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:1865
Oid tgoid
Definition: reltrigger.h:25
#define AFTER_TRIGGER_TUP_BITS
Definition: trigger.c:3241
#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:3282
#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:3240
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:1061
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3425
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3238
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:3389
#define elog
Definition: elog.h:219
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2017
ItemPointerData ate_ctid1
Definition: trigger.c:3258
char * tgoldtable
Definition: reltrigger.h:42
int Buffer
Definition: buf.h:23
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3391
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:120
Relation tg_relation
Definition: trigger.h:34
void AfterTriggerFireDeferred ( void  )

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

4265 {
4266  AfterTriggerEventList *events;
4267  bool snap_pushed = false;
4268 
4269  /* Must not be inside a query */
4271 
4272  /*
4273  * If there are any triggers to fire, make sure we have set a snapshot for
4274  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4275  * can't assume ActiveSnapshot is valid on entry.)
4276  */
4277  events = &afterTriggers.events;
4278  if (events->head != NULL)
4279  {
4281  snap_pushed = true;
4282  }
4283 
4284  /*
4285  * Run all the remaining triggers. Loop until they are all gone, in case
4286  * some trigger queues more for us to do.
4287  */
4288  while (afterTriggerMarkEvents(events, NULL, false))
4289  {
4290  CommandId firing_id = afterTriggers.firing_counter++;
4291 
4292  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4293  break; /* all fired */
4294  }
4295 
4296  /*
4297  * We don't bother freeing the event list, since it will go away anyway
4298  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4299  */
4300 
4301  if (snap_pushed)
4303 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3967
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:3384
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3306
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3895
AfterTriggerEventList events
Definition: trigger.c:3386
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3630 of file trigger.c.

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

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

3631 {
3632  AfterTriggerEventChunk *chunk;
3633  AfterTriggerEventChunk *next_chunk;
3634 
3635  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3636  {
3637  next_chunk = chunk->next;
3638  pfree(chunk);
3639  }
3640  events->head = NULL;
3641  events->tail = NULL;
3642  events->tailfree = NULL;
3643 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3307
struct AfterTriggerEventChunk * next
Definition: trigger.c:3294
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3306
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

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

3971 {
3972  bool all_fired = true;
3973  AfterTriggerEventChunk *chunk;
3974  MemoryContext per_tuple_context;
3975  bool local_estate = false;
3976  Relation rel = NULL;
3977  TriggerDesc *trigdesc = NULL;
3978  FmgrInfo *finfo = NULL;
3979  Instrumentation *instr = NULL;
3980  TupleTableSlot *slot1 = NULL,
3981  *slot2 = NULL;
3982 
3983  /* Make a local EState if need be */
3984  if (estate == NULL)
3985  {
3986  estate = CreateExecutorState();
3987  local_estate = true;
3988  }
3989 
3990  /* Make a per-tuple memory context for trigger function calls */
3991  per_tuple_context =
3993  "AfterTriggerTupleContext",
3995 
3996  for_each_chunk(chunk, *events)
3997  {
3998  AfterTriggerEvent event;
3999  bool all_fired_in_chunk = true;
4000 
4001  for_each_event(event, chunk)
4002  {
4003  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4004 
4005  /*
4006  * Is it one for me to fire?
4007  */
4008  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
4009  evtshared->ats_firing_id == firing_id)
4010  {
4011  /*
4012  * So let's fire it... but first, find the correct relation if
4013  * this is not the same relation as before.
4014  */
4015  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
4016  {
4017  ResultRelInfo *rInfo;
4018 
4019  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
4020  rel = rInfo->ri_RelationDesc;
4021  trigdesc = rInfo->ri_TrigDesc;
4022  finfo = rInfo->ri_TrigFunctions;
4023  instr = rInfo->ri_TrigInstrument;
4024  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4025  {
4026  if (slot1 != NULL)
4027  {
4030  }
4031  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
4032  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
4033  }
4034  if (trigdesc == NULL) /* should not happen */
4035  elog(ERROR, "relation %u has no triggers",
4036  evtshared->ats_relid);
4037  }
4038 
4039  /*
4040  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
4041  * still set, so recursive examinations of the event list
4042  * won't try to re-fire it.
4043  */
4044  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
4045  per_tuple_context, slot1, slot2);
4046 
4047  /*
4048  * Mark the event as done.
4049  */
4050  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4051  event->ate_flags |= AFTER_TRIGGER_DONE;
4052  }
4053  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
4054  {
4055  /* something remains to be done */
4056  all_fired = all_fired_in_chunk = false;
4057  }
4058  }
4059 
4060  /* Clear the chunk if delete_ok and nothing left of interest */
4061  if (delete_ok && all_fired_in_chunk)
4062  {
4063  chunk->freeptr = CHUNK_DATA_START(chunk);
4064  chunk->endfree = chunk->endptr;
4065 
4066  /*
4067  * If it's last chunk, must sync event list's tailfree too. Note
4068  * that delete_ok must NOT be passed as true if there could be
4069  * stacked AfterTriggerEventList values pointing at this event
4070  * list, since we'd fail to fix their copies of tailfree.
4071  */
4072  if (chunk == events->tail)
4073  events->tailfree = chunk->freeptr;
4074  }
4075  }
4076  if (slot1 != NULL)
4077  {
4080  }
4081 
4082  /* Release working resources */
4083  MemoryContextDelete(per_tuple_context);
4084 
4085  if (local_estate)
4086  {
4087  ListCell *l;
4088 
4089  foreach(l, estate->es_trig_target_relations)
4090  {
4091  ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
4092 
4093  /* Close indices and then the relation itself */
4094  ExecCloseIndices(resultRelInfo);
4095  heap_close(resultRelInfo->ri_RelationDesc, NoLock);
4096  }
4097  FreeExecutorState(estate);
4098  }
4099 
4100  return all_fired;
4101 }
Definition: fmgr.h:53
Relation ri_RelationDesc
Definition: execnodes.h:337
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
TriggerFlags ate_flags
Definition: trigger.c:3257
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3234
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3301
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:344
AfterTriggerEventChunk * tail
Definition: trigger.c:3307
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
#define GetTriggerSharedData(evt)
Definition: trigger.c:3282
#define for_each_event(eptr, cptr)
Definition: trigger.c:3314
void FreeExecutorState(EState *estate)
Definition: execUtils.c:169
#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:341
EState * CreateExecutorState(void)
Definition: execUtils.c:73
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid)
Definition: execMain.c:1350
List * es_trig_target_relations
Definition: execnodes.h:389
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:3312
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
CommandId ats_firing_id
Definition: trigger.c:3250
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3235
#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:3708
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:342
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

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

3898 {
3899  bool found = false;
3900  AfterTriggerEvent event;
3901  AfterTriggerEventChunk *chunk;
3902 
3903  for_each_event_chunk(event, chunk, *events)
3904  {
3905  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3906  bool defer_it = false;
3907 
3908  if (!(event->ate_flags &
3910  {
3911  /*
3912  * This trigger hasn't been called or scheduled yet. Check if we
3913  * should call it now.
3914  */
3915  if (immediate_only && afterTriggerCheckState(evtshared))
3916  {
3917  defer_it = true;
3918  }
3919  else
3920  {
3921  /*
3922  * Mark it as to be fired in this firing cycle.
3923  */
3925  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3926  found = true;
3927  }
3928  }
3929 
3930  /*
3931  * If it's deferred, move it to move_list, if requested.
3932  */
3933  if (defer_it && move_list != NULL)
3934  {
3935  /* add it to move_list */
3936  afterTriggerAddEvent(move_list, event, evtshared);
3937  /* mark original copy "done" so we don't do it again */
3938  event->ate_flags |= AFTER_TRIGGER_DONE;
3939  }
3940  }
3941 
3942  return found;
3943 }
TriggerFlags ate_flags
Definition: trigger.c:3257
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3234
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3319
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3469
#define GetTriggerSharedData(evt)
Definition: trigger.c:3282
CommandId firing_counter
Definition: trigger.c:3384
#define NULL
Definition: c.h:229
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3515
CommandId ats_firing_id
Definition: trigger.c:3250
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3235
static AfterTriggersData afterTriggers
Definition: trigger.c:3404
bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

Definition at line 3653 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

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

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

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

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

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

935 {
936  static List *info_list = NIL;
937 
938  static const char *const funcdescr[3] = {
939  gettext_noop("Found referenced table's UPDATE trigger."),
940  gettext_noop("Found referenced table's DELETE trigger."),
941  gettext_noop("Found referencing table's trigger.")
942  };
943 
944  char *constr_name;
945  char *fk_table_name;
946  char *pk_table_name;
947  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
948  List *fk_attrs = NIL;
949  List *pk_attrs = NIL;
951  int funcnum;
952  OldTriggerInfo *info = NULL;
953  ListCell *l;
954  int i;
955 
956  /* Parse out the trigger arguments */
957  constr_name = strVal(linitial(stmt->args));
958  fk_table_name = strVal(lsecond(stmt->args));
959  pk_table_name = strVal(lthird(stmt->args));
960  i = 0;
961  foreach(l, stmt->args)
962  {
963  Value *arg = (Value *) lfirst(l);
964 
965  i++;
966  if (i < 4) /* skip constraint and table names */
967  continue;
968  if (i == 4) /* handle match type */
969  {
970  if (strcmp(strVal(arg), "FULL") == 0)
971  fk_matchtype = FKCONSTR_MATCH_FULL;
972  else
973  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
974  continue;
975  }
976  if (i % 2)
977  fk_attrs = lappend(fk_attrs, arg);
978  else
979  pk_attrs = lappend(pk_attrs, arg);
980  }
981 
982  /* Prepare description of constraint for use in messages */
983  initStringInfo(&buf);
984  appendStringInfo(&buf, "FOREIGN KEY %s(",
985  quote_identifier(fk_table_name));
986  i = 0;
987  foreach(l, fk_attrs)
988  {
989  Value *arg = (Value *) lfirst(l);
990 
991  if (i++ > 0)
992  appendStringInfoChar(&buf, ',');
994  }
995  appendStringInfo(&buf, ") REFERENCES %s(",
996  quote_identifier(pk_table_name));
997  i = 0;
998  foreach(l, pk_attrs)
999  {
1000  Value *arg = (Value *) lfirst(l);
1001 
1002  if (i++ > 0)
1003  appendStringInfoChar(&buf, ',');
1005  }
1006  appendStringInfoChar(&buf, ')');
1007 
1008  /* Identify class of trigger --- update, delete, or referencing-table */
1009  switch (funcoid)
1010  {
1011  case F_RI_FKEY_CASCADE_UPD:
1012  case F_RI_FKEY_RESTRICT_UPD:
1013  case F_RI_FKEY_SETNULL_UPD:
1014  case F_RI_FKEY_SETDEFAULT_UPD:
1015  case F_RI_FKEY_NOACTION_UPD:
1016  funcnum = 0;
1017  break;
1018 
1019  case F_RI_FKEY_CASCADE_DEL:
1020  case F_RI_FKEY_RESTRICT_DEL:
1021  case F_RI_FKEY_SETNULL_DEL:
1022  case F_RI_FKEY_SETDEFAULT_DEL:
1023  case F_RI_FKEY_NOACTION_DEL:
1024  funcnum = 1;
1025  break;
1026 
1027  default:
1028  funcnum = 2;
1029  break;
1030  }
1031 
1032  /* See if we have a match to this trigger */
1033  foreach(l, info_list)
1034  {
1035  info = (OldTriggerInfo *) lfirst(l);
1036  if (info->funcoids[funcnum] == InvalidOid &&
1037  equal(info->args, stmt->args))
1038  {
1039  info->funcoids[funcnum] = funcoid;
1040  break;
1041  }
1042  }
1043 
1044  if (l == NULL)
1045  {
1046  /* First trigger of set, so create a new list entry */
1047  MemoryContext oldContext;
1048 
1049  ereport(NOTICE,
1050  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1051  constr_name, buf.data),
1052  errdetail_internal("%s", _(funcdescr[funcnum]))));
1054  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
1055  info->args = copyObject(stmt->args);
1056  info->funcoids[funcnum] = funcoid;
1057  info_list = lappend(info_list, info);
1058  MemoryContextSwitchTo(oldContext);
1059  }
1060  else if (info->funcoids[0] == InvalidOid ||
1061  info->funcoids[1] == InvalidOid ||
1062  info->funcoids[2] == InvalidOid)
1063  {
1064  /* Second trigger of set */
1065  ereport(NOTICE,
1066  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1067  constr_name, buf.data),
1068  errdetail_internal("%s", _(funcdescr[funcnum]))));
1069  }
1070  else
1071  {
1072  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
1075  Constraint *fkcon = makeNode(Constraint);
1076  PlannedStmt *wrapper = makeNode(PlannedStmt);
1077 
1078  ereport(NOTICE,
1079  (errmsg("converting trigger group into constraint \"%s\" %s",
1080  constr_name, buf.data),
1081  errdetail_internal("%s", _(funcdescr[funcnum]))));
1082  fkcon->contype = CONSTR_FOREIGN;
1083  fkcon->location = -1;
1084  if (funcnum == 2)
1085  {
1086  /* This trigger is on the FK table */
1087  atstmt->relation = stmt->relation;
1088  if (stmt->constrrel)
1089  fkcon->pktable = stmt->constrrel;
1090  else
1091  {
1092  /* Work around ancient pg_dump bug that omitted constrrel */
1093  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
1094  }
1095  }
1096  else
1097  {
1098  /* This trigger is on the PK table */
1099  fkcon->pktable = stmt->relation;
1100  if (stmt->constrrel)
1101  atstmt->relation = stmt->constrrel;
1102  else
1103  {
1104  /* Work around ancient pg_dump bug that omitted constrrel */
1105  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1106  }
1107  }
1108  atstmt->cmds = list_make1(atcmd);
1109  atstmt->relkind = OBJECT_TABLE;
1110  atcmd->subtype = AT_AddConstraint;
1111  atcmd->def = (Node *) fkcon;
1112  if (strcmp(constr_name, "<unnamed>") == 0)
1113  fkcon->conname = NULL;
1114  else
1115  fkcon->conname = constr_name;
1116  fkcon->fk_attrs = fk_attrs;
1117  fkcon->pk_attrs = pk_attrs;
1118  fkcon->fk_matchtype = fk_matchtype;
1119  switch (info->funcoids[0])
1120  {
1121  case F_RI_FKEY_NOACTION_UPD:
1123  break;
1124  case F_RI_FKEY_CASCADE_UPD:
1126  break;
1127  case F_RI_FKEY_RESTRICT_UPD:
1129  break;
1130  case F_RI_FKEY_SETNULL_UPD:
1132  break;
1133  case F_RI_FKEY_SETDEFAULT_UPD:
1135  break;
1136  default:
1137  /* can't get here because of earlier checks */
1138  elog(ERROR, "confused about RI update function");
1139  }
1140  switch (info->funcoids[1])
1141  {
1142  case F_RI_FKEY_NOACTION_DEL:
1144  break;
1145  case F_RI_FKEY_CASCADE_DEL:
1147  break;
1148  case F_RI_FKEY_RESTRICT_DEL:
1150  break;
1151  case F_RI_FKEY_SETNULL_DEL:
1153  break;
1154  case F_RI_FKEY_SETDEFAULT_DEL:
1156  break;
1157  default:
1158  /* can't get here because of earlier checks */
1159  elog(ERROR, "confused about RI delete function");
1160  }
1161  fkcon->deferrable = stmt->deferrable;
1162  fkcon->initdeferred = stmt->initdeferred;
1163  fkcon->skip_validation = false;
1164  fkcon->initially_valid = true;
1165 
1166  /* finally, wrap it in a dummy PlannedStmt */
1167  wrapper->commandType = CMD_UTILITY;
1168  wrapper->canSetTag = false;
1169  wrapper->utilityStmt = (Node *) atstmt;
1170  wrapper->stmt_location = -1;
1171  wrapper->stmt_len = -1;
1172 
1173  /* ... and execute it */
1174  ProcessUtility(wrapper,
1175  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1177  None_Receiver, NULL);
1178 
1179  /* Remove the matched item from the list */
1180  info_list = list_delete_ptr(info_list, info);
1181  pfree(info);
1182  /* We leak the copied args ... not worth worrying about */
1183  }
1184 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2020
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10195
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2946
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2011
char fk_matchtype
Definition: parsenodes.h:2056
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2015
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:522
#define strVal(v)
Definition: value.h:54
bool initdeferred
Definition: parsenodes.h:2030
AlterTableType subtype
Definition: parsenodes.h:1725
List * pk_attrs
Definition: parsenodes.h:2055
char * conname
Definition: parsenodes.h:2028
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:87
#define lsecond(l)
Definition: pg_list.h:114
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#define list_make1(x1)
Definition: pg_list.h:133
RangeVar * constrrel
Definition: parsenodes.h:2313
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:110
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2029
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
int stmt_location
Definition: plannodes.h:86
static char * buf
Definition: pg_test_fsync.c:65
Node * utilityStmt
Definition: plannodes.h:83
Oid funcoids[3]
Definition: trigger.c:929
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1643
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2013
List * lappend(List *list, void *datum)
Definition: list.c:128
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:332
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:2018
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:2064
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:570
char fk_del_action
Definition: parsenodes.h:2058
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:928
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1641
int i
RangeVar * relation
Definition: parsenodes.h:2297
ConstrType contype
Definition: parsenodes.h:2025
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2012
#define lthird(l)
Definition: pg_list.h:118
#define elog
Definition: elog.h:219
RangeVar * pktable
Definition: parsenodes.h:2053
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2014
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:2063
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:2054
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:2057
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1827 {
1828  TriggerDesc *newdesc;
1829  Trigger *trigger;
1830  int i;
1831 
1832  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1833  return NULL;
1834 
1835  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1836  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1837 
1838  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1839  memcpy(trigger, trigdesc->triggers,
1840  trigdesc->numtriggers * sizeof(Trigger));
1841  newdesc->triggers = trigger;
1842 
1843  for (i = 0; i < trigdesc->numtriggers; i++)
1844  {
1845  trigger->tgname = pstrdup(trigger->tgname);
1846  if (trigger->tgnattr > 0)
1847  {
1848  int16 *newattr;
1849 
1850  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1851  memcpy(newattr, trigger->tgattr,
1852  trigger->tgnattr * sizeof(int16));
1853  trigger->tgattr = newattr;
1854  }
1855  if (trigger->tgnargs > 0)
1856  {
1857  char **newargs;
1858  int16 j;
1859 
1860  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1861  for (j = 0; j < trigger->tgnargs; j++)
1862  newargs[j] = pstrdup(trigger->tgargs[j]);
1863  trigger->tgargs = newargs;
1864  }
1865  if (trigger->tgqual)
1866  trigger->tgqual = pstrdup(trigger->tgqual);
1867  if (trigger->tgoldtable)
1868  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1869  if (trigger->tgnewtable)
1870  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1871  trigger++;
1872  }
1873 
1874  return newdesc;
1875 }
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(), castNode, 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, 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 (stmt->timing != TRIGGER_TYPE_AFTER)
358  ereport(ERROR,
359  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
360  errmsg("transition table name can only be specified for an AFTER trigger")));
361 
362  if (tt->isNew)
363  {
364  if (!(TRIGGER_FOR_INSERT(tgtype) ||
365  TRIGGER_FOR_UPDATE(tgtype)))
366  ereport(ERROR,
367  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
368  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
369 
370  if (newtablename != NULL)
371  ereport(ERROR,
372  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
373  errmsg("NEW TABLE cannot be specified multiple times")));
374 
375  newtablename = tt->name;
376  }
377  else
378  {
379  if (!(TRIGGER_FOR_DELETE(tgtype) ||
380  TRIGGER_FOR_UPDATE(tgtype)))
381  ereport(ERROR,
382  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
383  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
384 
385  if (oldtablename != NULL)
386  ereport(ERROR,
387  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
388  errmsg("OLD TABLE cannot be specified multiple times")));
389 
390  oldtablename = tt->name;
391  }
392  }
393 
394  if (newtablename != NULL && oldtablename != NULL &&
395  strcmp(newtablename, oldtablename) == 0)
396  ereport(ERROR,
397  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
398  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
399  }
400 
401  /*
402  * Parse the WHEN clause, if any
403  */
404  if (stmt->whenClause)
405  {
406  ParseState *pstate;
407  RangeTblEntry *rte;
408  List *varList;
409  ListCell *lc;
410 
411  /* Set up a pstate to parse with */
412  pstate = make_parsestate(NULL);
413  pstate->p_sourcetext = queryString;
414 
415  /*
416  * Set up RTEs for OLD and NEW references.
417  *
418  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
419  */
420  rte = addRangeTableEntryForRelation(pstate, rel,
421  makeAlias("old", NIL),
422  false, false);
423  addRTEtoQuery(pstate, rte, false, true, true);
424  rte = addRangeTableEntryForRelation(pstate, rel,
425  makeAlias("new", NIL),
426  false, false);
427  addRTEtoQuery(pstate, rte, false, true, true);
428 
429  /* Transform expression. Copy to be sure we don't modify original */
430  whenClause = transformWhereClause(pstate,
431  copyObject(stmt->whenClause),
433  "WHEN");
434  /* we have to fix its collations too */
435  assign_expr_collations(pstate, whenClause);
436 
437  /*
438  * Check for disallowed references to OLD/NEW.
439  *
440  * NB: pull_var_clause is okay here only because we don't allow
441  * subselects in WHEN clauses; it would fail to examine the contents
442  * of subselects.
443  */
444  varList = pull_var_clause(whenClause, 0);
445  foreach(lc, varList)
446  {
447  Var *var = (Var *) lfirst(lc);
448 
449  switch (var->varno)
450  {
451  case PRS2_OLD_VARNO:
452  if (!TRIGGER_FOR_ROW(tgtype))
453  ereport(ERROR,
454  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
455  errmsg("statement trigger's WHEN condition cannot reference column values"),
456  parser_errposition(pstate, var->location)));
457  if (TRIGGER_FOR_INSERT(tgtype))
458  ereport(ERROR,
459  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
460  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
461  parser_errposition(pstate, var->location)));
462  /* system columns are okay here */
463  break;
464  case PRS2_NEW_VARNO:
465  if (!TRIGGER_FOR_ROW(tgtype))
466  ereport(ERROR,
467  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
468  errmsg("statement trigger's WHEN condition cannot reference column values"),
469  parser_errposition(pstate, var->location)));
470  if (TRIGGER_FOR_DELETE(tgtype))
471  ereport(ERROR,
472  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
473  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
474  parser_errposition(pstate, var->location)));
475  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
476  ereport(ERROR,
477  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
478  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
479  parser_errposition(pstate, var->location)));
480  break;
481  default:
482  /* can't happen without add_missing_from, so just elog */
483  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
484  break;
485  }
486  }
487 
488  /* we'll need the rtable for recordDependencyOnExpr */
489  whenRtable = pstate->p_rtable;
490 
491  qual = nodeToString(whenClause);
492 
493  free_parsestate(pstate);
494  }
495  else
496  {
497  whenClause = NULL;
498  whenRtable = NIL;
499  qual = NULL;
500  }
501 
502  /*
503  * Find and validate the trigger function.
504  */
505  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
506  if (!isInternal)
507  {
508  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
509  if (aclresult != ACLCHECK_OK)
510  aclcheck_error(aclresult, ACL_KIND_PROC,
511  NameListToString(stmt->funcname));
512  }
513  funcrettype = get_func_rettype(funcoid);
514  if (funcrettype != TRIGGEROID)
515  {
516  /*
517  * We allow OPAQUE just so we can load old dump files. When we see a
518  * trigger function declared OPAQUE, change it to TRIGGER.
519  */
520  if (funcrettype == OPAQUEOID)
521  {
523  (errmsg("changing return type of function %s from %s to %s",
524  NameListToString(stmt->funcname),
525  "opaque", "trigger")));
527  }
528  else
529  ereport(ERROR,
530  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
531  errmsg("function %s must return type %s",
532  NameListToString(stmt->funcname), "trigger")));
533  }
534 
535  /*
536  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
537  * references one of the built-in RI_FKey trigger functions, assume it is
538  * from a dump of a pre-7.3 foreign key constraint, and take steps to
539  * convert this legacy representation into a regular foreign key
540  * constraint. Ugly, but necessary for loading old dump files.
541  */
542  if (stmt->isconstraint && !isInternal &&
543  list_length(stmt->args) >= 6 &&
544  (list_length(stmt->args) % 2) == 0 &&
546  {
547  /* Keep lock on target rel until end of xact */
548  heap_close(rel, NoLock);
549 
550  ConvertTriggerToFK(stmt, funcoid);
551 
552  return InvalidObjectAddress;
553  }
554 
555  /*
556  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
557  * corresponding pg_constraint entry.
558  */
559  if (stmt->isconstraint && !OidIsValid(constraintOid))
560  {
561  /* Internal callers should have made their own constraints */
562  Assert(!isInternal);
563  constraintOid = CreateConstraintEntry(stmt->trigname,
566  stmt->deferrable,
567  stmt->initdeferred,
568  true,
569  RelationGetRelid(rel),
570  NULL, /* no conkey */
571  0,
572  InvalidOid, /* no domain */
573  InvalidOid, /* no index */
574  InvalidOid, /* no foreign key */
575  NULL,
576  NULL,
577  NULL,
578  NULL,
579  0,
580  ' ',
581  ' ',
582  ' ',
583  NULL, /* no exclusion */
584  NULL, /* no check constraint */
585  NULL,
586  NULL,
587  true, /* islocal */
588  0, /* inhcount */
589  true, /* isnoinherit */
590  isInternal); /* is_internal */
591  }
592 
593  /*
594  * Generate the trigger's OID now, so that we can use it in the name if
595  * needed.
596  */
598 
599  trigoid = GetNewOid(tgrel);
600 
601  /*
602  * If trigger is internally generated, modify the provided trigger name to
603  * ensure uniqueness by appending the trigger OID. (Callers will usually
604  * supply a simple constant trigger name in these cases.)
605  */
606  if (isInternal)
607  {
608  snprintf(internaltrigname, sizeof(internaltrigname),
609  "%s_%u", stmt->trigname, trigoid);
610  trigname = internaltrigname;
611  }
612  else
613  {
614  /* user-defined trigger; use the specified trigger name as-is */
615  trigname = stmt->trigname;
616  }
617 
618  /*
619  * Scan pg_trigger for existing triggers on relation. We do this only to
620  * give a nice error message if there's already a trigger of the same
621  * name. (The unique index on tgrelid/tgname would complain anyway.) We
622  * can skip this for internally generated triggers, since the name
623  * modification above should be sufficient.
624  *
625  * NOTE that this is cool only because we have ShareRowExclusiveLock on
626  * the relation, so the trigger set won't be changing underneath us.
627  */
628  if (!isInternal)
629  {
630  ScanKeyInit(&key,
632  BTEqualStrategyNumber, F_OIDEQ,
634  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
635  NULL, 1, &key);
636  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
637  {
638  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
639 
640  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
641  ereport(ERROR,
643  errmsg("trigger \"%s\" for relation \"%s\" already exists",
644  trigname, RelationGetRelationName(rel))));
645  }
646  systable_endscan(tgscan);
647  }
648 
649  /*
650  * Build the new pg_trigger tuple.
651  */
652  memset(nulls, false, sizeof(nulls));
653 
656  CStringGetDatum(trigname));
657  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
658  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
660  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
661  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
662  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
663  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
666 
667  if (stmt->args)
668  {
669  ListCell *le;
670  char *args;
671  int16 nargs = list_length(stmt->args);
672  int len = 0;
673 
674  foreach(le, stmt->args)
675  {
676  char *ar = strVal(lfirst(le));
677 
678  len += strlen(ar) + 4;
679  for (; *ar; ar++)
680  {
681  if (*ar == '\\')
682  len++;
683  }
684  }
685  args = (char *) palloc(len + 1);
686  args[0] = '\0';
687  foreach(le, stmt->args)
688  {
689  char *s = strVal(lfirst(le));
690  char *d = args + strlen(args);
691 
692  while (*s)
693  {
694  if (*s == '\\')
695  *d++ = '\\';
696  *d++ = *s++;
697  }
698  strcpy(d, "\\000");
699  }
700  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
702  CStringGetDatum(args));
703  }
704  else
705  {
706  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
708  CStringGetDatum(""));
709  }
710 
711  /* build column number array if it's a column-specific trigger */
712  ncolumns = list_length(stmt->columns);
713  if (ncolumns == 0)
714  columns = NULL;
715  else
716  {
717  ListCell *cell;
718  int i = 0;
719 
720  columns = (int16 *) palloc(ncolumns * sizeof(int16));
721  foreach(cell, stmt->columns)
722  {
723  char *name = strVal(lfirst(cell));
724  int16 attnum;
725  int j;
726 
727  /* Lookup column name. System columns are not allowed */
728  attnum = attnameAttNum(rel, name, false);
729  if (attnum == InvalidAttrNumber)
730  ereport(ERROR,
731  (errcode(ERRCODE_UNDEFINED_COLUMN),
732  errmsg("column \"%s\" of relation \"%s\" does not exist",
733  name, RelationGetRelationName(rel))));
734 
735  /* Check for duplicates */
736  for (j = i - 1; j >= 0; j--)
737  {
738  if (columns[j] == attnum)
739  ereport(ERROR,
740  (errcode(ERRCODE_DUPLICATE_COLUMN),
741  errmsg("column \"%s\" specified more than once",
742  name)));
743  }
744 
745  columns[i++] = attnum;
746  }
747  }
748  tgattr = buildint2vector(columns, ncolumns);
749  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
750 
751  /* set tgqual if trigger has WHEN clause */
752  if (qual)
753  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
754  else
755  nulls[Anum_pg_trigger_tgqual - 1] = true;
756 
757  if (oldtablename)
759  CStringGetDatum(oldtablename));
760  else
761  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
762  if (newtablename)
764  CStringGetDatum(newtablename));
765  else
766  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
767 
768  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
769 
770  /* force tuple to have the desired OID */
771  HeapTupleSetOid(tuple, trigoid);
772 
773  /*
774  * Insert tuple into pg_trigger.
775  */
776  CatalogTupleInsert(tgrel, tuple);
777 
778  heap_freetuple(tuple);
780 
784  if (oldtablename)
786  if (newtablename)
788 
789  /*
790  * Update relation's pg_class entry. Crucial side-effect: other backends
791  * (and this one too!) are sent SI message to make them rebuild relcache
792  * entries.
793  */
795  tuple = SearchSysCacheCopy1(RELOID,
797  if (!HeapTupleIsValid(tuple))
798  elog(ERROR, "cache lookup failed for relation %u",
799  RelationGetRelid(rel));
800 
801  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
802 
803  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
804 
805  heap_freetuple(tuple);
807 
808  /*
809  * We used to try to update the rel's relcache entry here, but that's
810  * fairly pointless since it will happen as a byproduct of the upcoming
811  * CommandCounterIncrement...
812  */
813 
814  /*
815  * Record dependencies for trigger. Always place a normal dependency on
816  * the function.
817  */
818  myself.classId = TriggerRelationId;
819  myself.objectId = trigoid;
820  myself.objectSubId = 0;
821 
822  referenced.classId = ProcedureRelationId;
823  referenced.objectId = funcoid;
824  referenced.objectSubId = 0;
825  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
826 
827  if (isInternal && OidIsValid(constraintOid))
828  {
829  /*
830  * Internally-generated trigger for a constraint, so make it an
831  * internal dependency of the constraint. We can skip depending on
832  * the relation(s), as there'll be an indirect dependency via the
833  * constraint.
834  */
835  referenced.classId = ConstraintRelationId;
836  referenced.objectId = constraintOid;
837  referenced.objectSubId = 0;
838  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
839  }
840  else
841  {
842  /*
843  * User CREATE TRIGGER, so place dependencies. We make trigger be
844  * auto-dropped if its relation is dropped or if the FK relation is
845  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
846  */
847  referenced.classId = RelationRelationId;
848  referenced.objectId = RelationGetRelid(rel);
849  referenced.objectSubId = 0;
850  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
851  if (OidIsValid(constrrelid))
852  {
853  referenced.classId = RelationRelationId;
854  referenced.objectId = constrrelid;
855  referenced.objectSubId = 0;
856  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
857  }
858  /* Not possible to have an index dependency in this case */
859  Assert(!OidIsValid(indexOid));
860 
861  /*
862  * If it's a user-specified constraint trigger, make the constraint
863  * internally dependent on the trigger instead of vice versa.
864  */
865  if (OidIsValid(constraintOid))
866  {
867  referenced.classId = ConstraintRelationId;
868  referenced.objectId = constraintOid;
869  referenced.objectSubId = 0;
870  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
871  }
872  }
873 
874  /* If column-specific trigger, add normal dependencies on columns */
875  if (columns != NULL)
876  {
877  int i;
878 
879  referenced.classId = RelationRelationId;
880  referenced.objectId = RelationGetRelid(rel);
881  for (i = 0; i < ncolumns; i++)
882  {
883  referenced.objectSubId = columns[i];
884  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
885  }
886  }
887 
888  /*
889  * If it has a WHEN clause, add dependencies on objects mentioned in the
890  * expression (eg, functions, as well as any columns used).
891  */
892  if (whenClause != NULL)
893  recordDependencyOnExpr(&myself, whenClause, whenRtable,
895 
896  /* Post creation hook for new trigger */
898  isInternal);
899 
900  /* Keep lock on target rel until end of xact */
901  heap_close(rel, NoLock);
902 
903  return myself;
904 }
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 castNode(_type_, nodeptr)
Definition: nodes.h:591
#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:2306
#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:522
#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:576
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:1427
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#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:2313
#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:696
#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:688
ItemPointerData t_self
Definition: htup.h:65
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:255
#define ACL_TRIGGER
Definition: parsenodes.h:71
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:3382
#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:167
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:934
List * transitionRels
Definition: parsenodes.h:2309
#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:1287
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:1315
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:109
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:4405
#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:162
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:72
#define RELKIND_VIEW
Definition: pg_class.h:164
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4429
int i
RangeVar * relation
Definition: parsenodes.h:2297
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:4154
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define CONSTRAINT_TRIGGER
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:75
#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:1694
#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:168
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

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

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

2451 {
2452  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2453 
2454  if (trigdesc &&
2455  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2456  {
2457  HeapTuple trigtuple;
2458 
2459  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2460  if (fdw_trigtuple == NULL)
2461  trigtuple = GetTupleForTrigger(estate,
2462  NULL,
2463  relinfo,
2464  tupleid,
2466  NULL);
2467  else
2468  trigtuple = fdw_trigtuple;
2469 
2471  true, trigtuple, NULL, NIL, NULL);
2472  if (trigtuple != fdw_trigtuple)
2473  heap_freetuple(trigtuple);
2474  }
2475 }
#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:5073
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:341
#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:2870
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

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

2241 {
2242  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2243 
2244  if (trigdesc &&
2245  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2247  true, NULL, trigtuple, recheckIndexes, NULL);
2248 }
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:5073
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:341
#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 2708 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().

2713 {
2714  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2715 
2716  if (trigdesc && (trigdesc->trig_update_after_row ||
2717  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2718  {
2719  HeapTuple trigtuple;
2720 
2721  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2722  if (fdw_trigtuple == NULL)
2723  trigtuple = GetTupleForTrigger(estate,
2724  NULL,
2725  relinfo,
2726  tupleid,
2728  NULL);
2729  else
2730  trigtuple = fdw_trigtuple;
2731 
2733  true, trigtuple, newtuple, recheckIndexes,
2734  GetUpdatedColumns(relinfo, estate));
2735  if (trigtuple != fdw_trigtuple)
2736  heap_freetuple(trigtuple);
2737  }
2738 }
#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:5073
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:341
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:2870
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2369 of file trigger.c.

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

Referenced by fireASTriggers().

2370 {
2371  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2372 
2373  if (trigdesc && trigdesc->trig_delete_after_statement)
2375  false, NULL, NULL, NIL, NULL);
2376 }
#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:5073
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:341
#define NULL
Definition: c.h:229
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2164 {
2165  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2166 
2167  if (trigdesc && trigdesc->trig_insert_after_statement)
2169  false, NULL, NULL, NIL, NULL);
2170 }
#define NIL
Definition: pg_list.h:69
bool trig_insert_after_statement
Definition: reltrigger.h:59