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   0x0FFFFFFF /* must be low-order bits */
 
#define AFTER_TRIGGER_DONE   0x10000000
 
#define AFTER_TRIGGER_IN_PROGRESS   0x20000000
 
#define AFTER_TRIGGER_FDW_REUSE   0x00000000
 
#define AFTER_TRIGGER_FDW_FETCH   0x80000000
 
#define AFTER_TRIGGER_1CTID   0x40000000
 
#define AFTER_TRIGGER_2CTID   0xC0000000
 
#define AFTER_TRIGGER_TUP_BITS   0xC0000000
 
#define SizeofTriggerEvent(evt)
 
#define GetTriggerSharedData(evt)   ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
 
#define CHUNK_DATA_START(cptr)   ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
 
#define for_each_chunk(cptr, evtlist)   for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)
 
#define for_each_event(eptr, cptr)
 
#define for_each_event_chunk(eptr, cptr, evtlist)   for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
 
#define MIN_CHUNK_SIZE   1024
 
#define MAX_CHUNK_SIZE   (1024*1024)
 
#define DEFTRIG_INITALLOC   8
 

Typedefs

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

Functions

static void ConvertTriggerToFK (CreateTrigStmt *stmt, Oid funcoid)
 
static void SetTriggerFlags (TriggerDesc *trigdesc, Trigger *trigger)
 
static HeapTuple GetTupleForTrigger (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
 
static bool TriggerEnabled (EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
 
static HeapTuple ExecCallTriggerFunc (TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
 
static void AfterTriggerSaveEvent (EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
 
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 3264 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3265 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3263 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3262 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

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

Definition at line 3258 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3266 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3326 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 3337 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:3326
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3300
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3278

Definition at line 3339 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:3266
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3264
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3265

Definition at line 3300 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3278 of file trigger.c.

Definition at line 3268 of file trigger.c.

Definition at line 3256 of file trigger.c.

Function Documentation

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

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

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

Definition at line 4167 of file trigger.c.

References AfterTriggersData::query_depth.

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

4168 {
4169  /* Increase the query stack depth */
4171 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
void AfterTriggerBeginSubXact ( void  )

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

4392 {
4393  int my_level = GetCurrentTransactionNestLevel();
4394 
4395  /*
4396  * Allocate more space in the stacks if needed. (Note: because the
4397  * minimum nest level of a subtransaction is 2, we waste the first couple
4398  * entries of each array; not worth the notational effort to avoid it.)
4399  */
4400  while (my_level >= afterTriggers.maxtransdepth)
4401  {
4402  if (afterTriggers.maxtransdepth == 0)
4403  {
4404  MemoryContext old_cxt;
4405 
4407 
4408 #define DEFTRIG_INITALLOC 8
4413  afterTriggers.depth_stack = (int *)
4414  palloc(DEFTRIG_INITALLOC * sizeof(int));
4416  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4418 
4419  MemoryContextSwitchTo(old_cxt);
4420  }
4421  else
4422  {
4423  /* repalloc will keep the stacks in the same context */
4424  int new_alloc = afterTriggers.maxtransdepth * 2;
4425 
4428  new_alloc * sizeof(SetConstraintState));
4431  new_alloc * sizeof(AfterTriggerEventList));
4432  afterTriggers.depth_stack = (int *)
4434  new_alloc * sizeof(int));
4437  new_alloc * sizeof(CommandId));
4438  afterTriggers.maxtransdepth = new_alloc;
4439  }
4440  }
4441 
4442  /*
4443  * Push the current information into the stack. The SET CONSTRAINTS state
4444  * is not saved until/unless changed. Likewise, we don't make a
4445  * per-subtransaction event context until needed.
4446  */
4447  afterTriggers.state_stack[my_level] = NULL;
4451 }
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:3426
SetConstraintState * state_stack
Definition: trigger.c:3423
CommandId firing_counter
Definition: trigger.c:3409
AfterTriggerEventList * events_stack
Definition: trigger.c:3424
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:3411
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
void AfterTriggerBeginXact ( void  )

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

4130 {
4131  /*
4132  * Initialize after-trigger state structure to empty
4133  */
4134  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4136 
4137  /*
4138  * Verify that there is no leftover state remaining. If these assertions
4139  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4140  * up properly.
4141  */
4155 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
CommandId * firing_stack
Definition: trigger.c:3426
SetConstraintState * state_stack
Definition: trigger.c:3423
SetConstraintState state
Definition: trigger.c:3410
CommandId firing_counter
Definition: trigger.c:3409
AfterTriggerEventList * events_stack
Definition: trigger.c:3424
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3331
MemoryContext event_cxt
Definition: trigger.c:3419
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList events
Definition: trigger.c:3411
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

3496 {
3497  Oid tgoid = evtshared->ats_tgoid;
3499  int i;
3500 
3501  /*
3502  * For not-deferrable triggers (i.e. normal AFTER ROW triggers and
3503  * constraints declared NOT DEFERRABLE), the state is always false.
3504  */
3505  if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
3506  return false;
3507 
3508  /*
3509  * If constraint state exists, SET CONSTRAINTS might have been executed
3510  * either for this trigger or for all triggers.
3511  */
3512  if (state != NULL)
3513  {
3514  /* Check for SET CONSTRAINTS for this specific trigger. */
3515  for (i = 0; i < state->numstates; i++)
3516  {
3517  if (state->trigstates[i].sct_tgoid == tgoid)
3518  return state->trigstates[i].sct_tgisdeferred;
3519  }
3520 
3521  /* Check for SET CONSTRAINTS ALL. */
3522  if (state->all_isset)
3523  return state->all_isdeferred;
3524  }
3525 
3526  /*
3527  * Otherwise return the default state for the trigger.
3528  */
3529  return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
3530 }
TriggerEvent ats_event
Definition: trigger.c:3272
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:68
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:67
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3220
unsigned int Oid
Definition: postgres_ext.h:31
SetConstraintState state
Definition: trigger.c:3410
#define NULL
Definition: c.h:229
Definition: regguts.h:298
int i
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
void AfterTriggerEndQuery ( EState estate)

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

4188 {
4189  AfterTriggerEventList *events;
4190  Tuplestorestate *fdw_tuplestore;
4191  Tuplestorestate *old_tuplestore;
4192  Tuplestorestate *new_tuplestore;
4193 
4194  /* Must be inside a query, too */
4196 
4197  /*
4198  * If we never even got as far as initializing the event stack, there
4199  * certainly won't be any events, so exit quickly.
4200  */
4202  {
4204  return;
4205  }
4206 
4207  /*
4208  * Process all immediate-mode triggers queued by the query, and move the
4209  * deferred ones to the main list of deferred events.
4210  *
4211  * Notice that we decide which ones will be fired, and put the deferred
4212  * ones on the main list, before anything is actually fired. This ensures
4213  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4214  * IMMEDIATE: all events we have decided to defer will be available for it
4215  * to fire.
4216  *
4217  * We loop in case a trigger queues more events at the same query level.
4218  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4219  * will instead fire any triggers in a dedicated query level. Foreign key
4220  * enforcement triggers do add to the current query level, thanks to their
4221  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4222  * C-language triggers might do likewise. Be careful here: firing a
4223  * trigger could result in query_stack being repalloc'd, so we can't save
4224  * its address across afterTriggerInvokeEvents calls.
4225  *
4226  * If we find no firable events, we don't have to increment
4227  * firing_counter.
4228  */
4229  for (;;)
4230  {
4232  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4233  {
4234  CommandId firing_id = afterTriggers.firing_counter++;
4235 
4236  /* OK to delete the immediate events after processing them */
4237  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4238  break; /* all fired */
4239  }
4240  else
4241  break;
4242  }
4243 
4244  /* Release query-local storage for events, including tuplestore if any */
4246  if (fdw_tuplestore)
4247  {
4248  tuplestore_end(fdw_tuplestore);
4250  }
4252  if (old_tuplestore)
4253  {
4254  tuplestore_end(old_tuplestore);
4256  }
4258  if (new_tuplestore)
4259  {
4260  tuplestore_end(new_tuplestore);
4262  }
4264 
4266 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3993
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3656
CommandId firing_counter
Definition: trigger.c:3409
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3921
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList events
Definition: trigger.c:3411
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
void AfterTriggerEndSubXact ( bool  isCommit)

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

4460 {
4461  int my_level = GetCurrentTransactionNestLevel();
4463  AfterTriggerEvent event;
4464  AfterTriggerEventChunk *chunk;
4465  CommandId subxact_firing_id;
4466 
4467  /*
4468  * Pop the prior state if needed.
4469  */
4470  if (isCommit)
4471  {
4472  Assert(my_level < afterTriggers.maxtransdepth);
4473  /* If we saved a prior state, we don't need it anymore */
4474  state = afterTriggers.state_stack[my_level];
4475  if (state != NULL)
4476  pfree(state);
4477  /* this avoids double pfree if error later: */
4478  afterTriggers.state_stack[my_level] = NULL;
4480  afterTriggers.depth_stack[my_level]);
4481  }
4482  else
4483  {
4484  /*
4485  * Aborting. It is possible subxact start failed before calling
4486  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4487  * stack levels that aren't there.
4488  */
4489  if (my_level >= afterTriggers.maxtransdepth)
4490  return;
4491 
4492  /*
4493  * Release any event lists from queries being aborted, and restore
4494  * query_depth to its pre-subxact value. This assumes that a
4495  * subtransaction will not add events to query levels started in a
4496  * earlier transaction state.
4497  */
4499  {
4501  {
4502  Tuplestorestate *ts;
4503 
4505  if (ts)
4506  {
4507  tuplestore_end(ts);
4509  }
4511  if (ts)
4512  {
4513  tuplestore_end(ts);
4515  }
4517  if (ts)
4518  {
4519  tuplestore_end(ts);
4521  }
4522 
4524  }
4525 
4527  }
4529  afterTriggers.depth_stack[my_level]);
4530 
4531  /*
4532  * Restore the global deferred-event list to its former length,
4533  * discarding any events queued by the subxact.
4534  */
4536  &afterTriggers.events_stack[my_level]);
4537 
4538  /*
4539  * Restore the trigger state. If the saved state is NULL, then this
4540  * subxact didn't save it, so it doesn't need restoring.
4541  */
4542  state = afterTriggers.state_stack[my_level];
4543  if (state != NULL)
4544  {
4546  afterTriggers.state = state;
4547  }
4548  /* this avoids double pfree if error later: */
4549  afterTriggers.state_stack[my_level] = NULL;
4550 
4551  /*
4552  * Scan for any remaining deferred events that were marked DONE or IN
4553  * PROGRESS by this subxact or a child, and un-mark them. We can
4554  * recognize such events because they have a firing ID greater than or
4555  * equal to the firing_counter value we saved at subtransaction start.
4556  * (This essentially assumes that the current subxact includes all
4557  * subxacts started after it.)
4558  */
4559  subxact_firing_id = afterTriggers.firing_stack[my_level];
4561  {
4562  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4563 
4564  if (event->ate_flags &
4566  {
4567  if (evtshared->ats_firing_id >= subxact_firing_id)
4568  event->ate_flags &=
4570  }
4571  }
4572  }
4573 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
TriggerFlags ate_flags
Definition: trigger.c:3282
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3259
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3344
CommandId * firing_stack
Definition: trigger.c:3426
#define GetTriggerSharedData(evt)
Definition: trigger.c:3307
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3423
SetConstraintState state
Definition: trigger.c:3410
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3656
AfterTriggerEventList * events_stack
Definition: trigger.c:3424
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Definition: regguts.h:298
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3679
CommandId ats_firing_id
Definition: trigger.c:3275
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3260
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList events
Definition: trigger.c:3411
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
void AfterTriggerEndXact ( bool  isCommit)

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

4338 {
4339  /*
4340  * Forget the pending-events list.
4341  *
4342  * Since all the info is in TopTransactionContext or children thereof, we
4343  * don't really need to do anything to reclaim memory. However, the
4344  * pending-events list could be large, and so it's useful to discard it as
4345  * soon as possible --- especially if we are aborting because we ran out
4346  * of memory for the list!
4347  */
4349  {
4355  }
4356 
4357  /*
4358  * Forget any subtransaction state as well. Since this can't be very
4359  * large, we let the eventual reset of TopTransactionContext free the
4360  * memory instead of doing it here.
4361  */
4367 
4368 
4369  /*
4370  * Forget the query stack and constraint-related state information. As
4371  * with the subtransaction state information, we don't bother freeing the
4372  * memory here.
4373  */
4380 
4381  /* No more afterTriggers manipulation until next transaction starts. */
4383 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3332
CommandId * firing_stack
Definition: trigger.c:3426
SetConstraintState * state_stack
Definition: trigger.c:3423
SetConstraintState state
Definition: trigger.c:3410
AfterTriggerEventList * events_stack
Definition: trigger.c:3424
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3331
MemoryContext event_cxt
Definition: trigger.c:3419
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList events
Definition: trigger.c:3411
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
static void AfterTriggerEnlargeQueryState ( void  )
static

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

4586 {
4587  int init_depth = afterTriggers.maxquerydepth;
4588 
4590 
4591  if (afterTriggers.maxquerydepth == 0)
4592  {
4593  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4594 
4597  new_alloc * sizeof(AfterTriggerEventList));
4600  new_alloc * sizeof(Tuplestorestate *));
4603  new_alloc * sizeof(Tuplestorestate *));
4606  new_alloc * sizeof(Tuplestorestate *));
4607  afterTriggers.maxquerydepth = new_alloc;
4608  }
4609  else
4610  {
4611  /* repalloc will keep the stack in the same context */
4612  int old_alloc = afterTriggers.maxquerydepth;
4613  int new_alloc = Max(afterTriggers.query_depth + 1,
4614  old_alloc * 2);
4615 
4618  new_alloc * sizeof(AfterTriggerEventList));
4621  new_alloc * sizeof(Tuplestorestate *));
4624  new_alloc * sizeof(Tuplestorestate *));
4627  new_alloc * sizeof(Tuplestorestate *));
4628  /* Clear newly-allocated slots for subsequent lazy initialization. */
4629  memset(afterTriggers.fdw_tuplestores + old_alloc,
4630  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4631  memset(afterTriggers.old_tuplestores + old_alloc,
4632  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4633  memset(afterTriggers.new_tuplestores + old_alloc,
4634  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4635  afterTriggers.maxquerydepth = new_alloc;
4636  }
4637 
4638  /* Initialize new query lists to empty */
4639  while (init_depth < afterTriggers.maxquerydepth)
4640  {
4641  AfterTriggerEventList *events;
4642 
4643  events = &afterTriggers.query_stack[init_depth];
4644  events->head = NULL;
4645  events->tail = NULL;
4646  events->tailfree = NULL;
4647 
4648  ++init_depth;
4649  }
4650 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3332
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:3331
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:707
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
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 3734 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().

3740 {
3741  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3742  Oid tgoid = evtshared->ats_tgoid;
3743  TriggerData LocTriggerData;
3744  HeapTupleData tuple1;
3745  HeapTupleData tuple2;
3746  HeapTuple rettuple;
3747  Buffer buffer1 = InvalidBuffer;
3748  Buffer buffer2 = InvalidBuffer;
3749  int tgindx;
3750 
3751  /*
3752  * Locate trigger in trigdesc.
3753  */
3754  LocTriggerData.tg_trigger = NULL;
3755  for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
3756  {
3757  if (trigdesc->triggers[tgindx].tgoid == tgoid)
3758  {
3759  LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
3760  break;
3761  }
3762  }
3763  if (LocTriggerData.tg_trigger == NULL)
3764  elog(ERROR, "could not find trigger %u", tgoid);
3765 
3766  /*
3767  * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want
3768  * to include time spent re-fetching tuples in the trigger cost.
3769  */
3770  if (instr)
3771  InstrStartNode(instr + tgindx);
3772 
3773  /*
3774  * Fetch the required tuple(s).
3775  */
3776  switch (event->ate_flags & AFTER_TRIGGER_TUP_BITS)
3777  {
3779  {
3780  Tuplestorestate *fdw_tuplestore =
3783 
3784  if (!tuplestore_gettupleslot(fdw_tuplestore, true, false,
3785  trig_tuple_slot1))
3786  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3787 
3788  if ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3790  !tuplestore_gettupleslot(fdw_tuplestore, true, false,
3791  trig_tuple_slot2))
3792  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3793  }
3794  /* fall through */
3796 
3797  /*
3798  * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
3799  * ensures that tg_trigtuple does not reference tuplestore memory.
3800  * (It is formally possible for the trigger function to queue
3801  * trigger events that add to the same tuplestore, which can push
3802  * other tuples out of memory.) The distinction is academic,
3803  * because we start with a minimal tuple that ExecFetchSlotTuple()
3804  * must materialize anyway.
3805  */
3806  LocTriggerData.tg_trigtuple =
3807  ExecMaterializeSlot(trig_tuple_slot1);
3808  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3809 
3810  LocTriggerData.tg_newtuple =
3811  ((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
3813  ExecMaterializeSlot(trig_tuple_slot2) : NULL;
3814  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3815 
3816  break;
3817 
3818  default:
3819  if (ItemPointerIsValid(&(event->ate_ctid1)))
3820  {
3821  ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
3822  if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
3823  elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
3824  LocTriggerData.tg_trigtuple = &tuple1;
3825  LocTriggerData.tg_trigtuplebuf = buffer1;
3826  }
3827  else
3828  {
3829  LocTriggerData.tg_trigtuple = NULL;
3830  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3831  }
3832 
3833  /* don't touch ctid2 if not there */
3834  if ((event->ate_flags & AFTER_TRIGGER_TUP_BITS) ==
3836  ItemPointerIsValid(&(event->ate_ctid2)))
3837  {
3838  ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
3839  if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
3840  elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
3841  LocTriggerData.tg_newtuple = &tuple2;
3842  LocTriggerData.tg_newtuplebuf = buffer2;
3843  }
3844  else
3845  {
3846  LocTriggerData.tg_newtuple = NULL;
3847  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3848  }
3849  }
3850 
3851  /*
3852  * Set up the tuplestore information.
3853  */
3854  if (LocTriggerData.tg_trigger->tgoldtable)
3855  LocTriggerData.tg_oldtable =
3857  else
3858  LocTriggerData.tg_oldtable = NULL;
3859  if (LocTriggerData.tg_trigger->tgnewtable)
3860  LocTriggerData.tg_newtable =
3862  else
3863  LocTriggerData.tg_newtable = NULL;
3864 
3865  /*
3866  * Setup the remaining trigger information
3867  */
3868  LocTriggerData.type = T_TriggerData;
3869  LocTriggerData.tg_event =
3871  LocTriggerData.tg_relation = rel;
3872 
3873  MemoryContextReset(per_tuple_context);
3874 
3875  /*
3876  * Call the trigger and throw away any possibly returned updated tuple.
3877  * (Don't let ExecCallTriggerFunc measure EXPLAIN time.)
3878  */
3879  rettuple = ExecCallTriggerFunc(&LocTriggerData,
3880  tgindx,
3881  finfo,
3882  NULL,
3883  per_tuple_context);
3884  if (rettuple != NULL &&
3885  rettuple != LocTriggerData.tg_trigtuple &&
3886  rettuple != LocTriggerData.tg_newtuple)
3887  heap_freetuple(rettuple);
3888 
3889  /*
3890  * Release buffers
3891  */
3892  if (buffer1 != InvalidBuffer)
3893  ReleaseBuffer(buffer1);
3894  if (buffer2 != InvalidBuffer)
3895  ReleaseBuffer(buffer2);
3896 
3897  /*
3898  * If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count
3899  * one "tuple returned" (really the number of firings).
3900  */
3901  if (instr)
3902  InstrStopNode(instr + tgindx, 1);
3903 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TriggerEvent ats_event
Definition: trigger.c:3272
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3262
ItemPointerData ate_ctid2
Definition: trigger.c:3284
TriggerFlags ate_flags
Definition: trigger.c:3282
Buffer tg_newtuplebuf
Definition: trigger.h:39
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1862
Oid tgoid
Definition: reltrigger.h:25
#define AFTER_TRIGGER_TUP_BITS
Definition: trigger.c:3266
#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:1372
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:3307
#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:3265
int numtriggers
Definition: reltrigger.h:49
#define SnapshotAny
Definition: tqual.h:28
char * tgnewtable
Definition: reltrigger.h:43
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3451
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3263
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:3414
#define elog
Definition: elog.h:219
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2043
ItemPointerData ate_ctid1
Definition: trigger.c:3283
char * tgoldtable
Definition: reltrigger.h:42
int Buffer
Definition: buf.h:23
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:139
Relation tg_relation
Definition: trigger.h:34
void AfterTriggerFireDeferred ( void  )

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

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

Definition at line 3656 of file trigger.c.

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

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

3657 {
3658  AfterTriggerEventChunk *chunk;
3659  AfterTriggerEventChunk *next_chunk;
3660 
3661  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3662  {
3663  next_chunk = chunk->next;
3664  pfree(chunk);
3665  }
3666  events->head = NULL;
3667  events->tail = NULL;
3668  events->tailfree = NULL;
3669 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3332
struct AfterTriggerEventChunk * next
Definition: trigger.c:3319
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3331
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

Definition at line 3993 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, ExecCleanUpTriggerState(), ExecDropSingleTupleTableSlot(), ExecGetTriggerResultRel(), for_each_chunk, for_each_event, FreeExecutorState(), AfterTriggerEventChunk::freeptr, GetTriggerSharedData, MakeSingleTupleTableSlot(), MemoryContextDelete(), NULL, RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, RELKIND_FOREIGN_TABLE, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

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

3997 {
3998  bool all_fired = true;
3999  AfterTriggerEventChunk *chunk;
4000  MemoryContext per_tuple_context;
4001  bool local_estate = false;
4002  Relation rel = NULL;
4003  TriggerDesc *trigdesc = NULL;
4004  FmgrInfo *finfo = NULL;
4005  Instrumentation *instr = NULL;
4006  TupleTableSlot *slot1 = NULL,
4007  *slot2 = NULL;
4008 
4009  /* Make a local EState if need be */
4010  if (estate == NULL)
4011  {
4012  estate = CreateExecutorState();
4013  local_estate = true;
4014  }
4015 
4016  /* Make a per-tuple memory context for trigger function calls */
4017  per_tuple_context =
4019  "AfterTriggerTupleContext",
4021 
4022  for_each_chunk(chunk, *events)
4023  {
4024  AfterTriggerEvent event;
4025  bool all_fired_in_chunk = true;
4026 
4027  for_each_event(event, chunk)
4028  {
4029  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4030 
4031  /*
4032  * Is it one for me to fire?
4033  */
4034  if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
4035  evtshared->ats_firing_id == firing_id)
4036  {
4037  /*
4038  * So let's fire it... but first, find the correct relation if
4039  * this is not the same relation as before.
4040  */
4041  if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
4042  {
4043  ResultRelInfo *rInfo;
4044 
4045  rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
4046  rel = rInfo->ri_RelationDesc;
4047  trigdesc = rInfo->ri_TrigDesc;
4048  finfo = rInfo->ri_TrigFunctions;
4049  instr = rInfo->ri_TrigInstrument;
4050  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4051  {
4052  if (slot1 != NULL)
4053  {
4056  }
4057  slot1 = MakeSingleTupleTableSlot(rel->rd_att);
4058  slot2 = MakeSingleTupleTableSlot(rel->rd_att);
4059  }
4060  if (trigdesc == NULL) /* should not happen */
4061  elog(ERROR, "relation %u has no triggers",
4062  evtshared->ats_relid);
4063  }
4064 
4065  /*
4066  * Fire it. Note that the AFTER_TRIGGER_IN_PROGRESS flag is
4067  * still set, so recursive examinations of the event list
4068  * won't try to re-fire it.
4069  */
4070  AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
4071  per_tuple_context, slot1, slot2);
4072 
4073  /*
4074  * Mark the event as done.
4075  */
4076  event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4077  event->ate_flags |= AFTER_TRIGGER_DONE;
4078  }
4079  else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
4080  {
4081  /* something remains to be done */
4082  all_fired = all_fired_in_chunk = false;
4083  }
4084  }
4085 
4086  /* Clear the chunk if delete_ok and nothing left of interest */
4087  if (delete_ok && all_fired_in_chunk)
4088  {
4089  chunk->freeptr = CHUNK_DATA_START(chunk);
4090  chunk->endfree = chunk->endptr;
4091 
4092  /*
4093  * If it's last chunk, must sync event list's tailfree too. Note
4094  * that delete_ok must NOT be passed as true if there could be
4095  * stacked AfterTriggerEventList values pointing at this event
4096  * list, since we'd fail to fix their copies of tailfree.
4097  */
4098  if (chunk == events->tail)
4099  events->tailfree = chunk->freeptr;
4100  }
4101  }
4102  if (slot1 != NULL)
4103  {
4106  }
4107 
4108  /* Release working resources */
4109  MemoryContextDelete(per_tuple_context);
4110 
4111  if (local_estate)
4112  {
4113  ExecCleanUpTriggerState(estate);
4114  FreeExecutorState(estate);
4115  }
4116 
4117  return all_fired;
4118 }
Definition: fmgr.h:56
Relation ri_RelationDesc
Definition: execnodes.h:354
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
TriggerFlags ate_flags
Definition: trigger.c:3282
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3259
#define CHUNK_DATA_START(cptr)
Definition: trigger.c:3326
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
AfterTriggerEventChunk * tail
Definition: trigger.c:3332
Form_pg_class rd_rel
Definition: rel.h:114
#define GetTriggerSharedData(evt)
Definition: trigger.c:3307
#define for_each_event(eptr, cptr)
Definition: trigger.c:3339
void FreeExecutorState(EState *estate)
Definition: execUtils.c:178
#define ERROR
Definition: elog.h:43
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
EState * CreateExecutorState(void)
Definition: execUtils.c:80
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid)
Definition: execMain.c:1379
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
TupleDesc rd_att
Definition: rel.h:115
#define for_each_chunk(cptr, evtlist)
Definition: trigger.c:3337
#define NULL
Definition: c.h:229
CommandId ats_firing_id
Definition: trigger.c:3275
void ExecCleanUpTriggerState(EState *estate)
Definition: execMain.c:1440
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3260
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:416
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:3734
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
static bool afterTriggerMarkEvents ( AfterTriggerEventList events,
AfterTriggerEventList move_list,
bool  immediate_only 
)
static

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

3924 {
3925  bool found = false;
3926  AfterTriggerEvent event;
3927  AfterTriggerEventChunk *chunk;
3928 
3929  for_each_event_chunk(event, chunk, *events)
3930  {
3931  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3932  bool defer_it = false;
3933 
3934  if (!(event->ate_flags &
3936  {
3937  /*
3938  * This trigger hasn't been called or scheduled yet. Check if we
3939  * should call it now.
3940  */
3941  if (immediate_only && afterTriggerCheckState(evtshared))
3942  {
3943  defer_it = true;
3944  }
3945  else
3946  {
3947  /*
3948  * Mark it as to be fired in this firing cycle.
3949  */
3951  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3952  found = true;
3953  }
3954  }
3955 
3956  /*
3957  * If it's deferred, move it to move_list, if requested.
3958  */
3959  if (defer_it && move_list != NULL)
3960  {
3961  /* add it to move_list */
3962  afterTriggerAddEvent(move_list, event, evtshared);
3963  /* mark original copy "done" so we don't do it again */
3964  event->ate_flags |= AFTER_TRIGGER_DONE;
3965  }
3966  }
3967 
3968  return found;
3969 }
TriggerFlags ate_flags
Definition: trigger.c:3282
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3259
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3344
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3495
#define GetTriggerSharedData(evt)
Definition: trigger.c:3307
CommandId firing_counter
Definition: trigger.c:3409
#define NULL
Definition: c.h:229
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3541
CommandId ats_firing_id
Definition: trigger.c:3275
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3260
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

Definition at line 3679 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

3681 {
3682  AfterTriggerEventChunk *chunk;
3683  AfterTriggerEventChunk *next_chunk;
3684 
3685  if (old_events->tail == NULL)
3686  {
3687  /* restoring to a completely empty state, so free everything */
3688  afterTriggerFreeEventList(events);
3689  }
3690  else
3691  {
3692  *events = *old_events;
3693  /* free any chunks after the last one we want to keep */
3694  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3695  {
3696  next_chunk = chunk->next;
3697  pfree(chunk);
3698  }
3699  /* and clean up the tail chunk to be the right length */
3700  events->tail->next = NULL;
3701  events->tail->freeptr = events->tailfree;
3702 
3703  /*
3704  * We don't make any effort to remove now-unused shared data records.
3705  * They might still be useful, anyway.
3706  */
3707  }
3708 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3332
struct AfterTriggerEventChunk * next
Definition: trigger.c:3319
void pfree(void *pointer)
Definition: mcxt.c:950
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3656
#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 5090 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().

5094 {
5095  Relation rel = relinfo->ri_RelationDesc;
5096  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
5097  AfterTriggerEventData new_event;
5098  AfterTriggerSharedData new_shared;
5099  char relkind = relinfo->ri_RelationDesc->rd_rel->relkind;
5100  int tgtype_event;
5101  int tgtype_level;
5102  int i;
5103  Tuplestorestate *fdw_tuplestore = NULL;
5104 
5105  /*
5106  * Check state. We use a normal test not Assert because it is possible to
5107  * reach here in the wrong state given misconfigured RI triggers, in
5108  * particular deferring a cascade action trigger.
5109  */
5110  if (afterTriggers.query_depth < 0)
5111  elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
5112 
5113  /* Be sure we have enough space to record events at this query depth. */
5116 
5117  /*
5118  * If the relation has AFTER ... FOR EACH ROW triggers, capture rows into
5119  * transition tuplestores for this depth.
5120  */
5121  if (row_trigger)
5122  {
5123  if ((event == TRIGGER_EVENT_DELETE &&
5124  trigdesc->trig_delete_old_table) ||
5125  (event == TRIGGER_EVENT_UPDATE &&
5126  trigdesc->trig_update_old_table))
5127  {
5128  Tuplestorestate *old_tuplestore;
5129 
5130  Assert(oldtup != NULL);
5131  old_tuplestore =
5134  tuplestore_puttuple(old_tuplestore, oldtup);
5135  }
5136  if ((event == TRIGGER_EVENT_INSERT &&
5137  trigdesc->trig_insert_new_table) ||
5138  (event == TRIGGER_EVENT_UPDATE &&
5139  trigdesc->trig_update_new_table))
5140  {
5141  Tuplestorestate *new_tuplestore;
5142 
5143  Assert(newtup != NULL);
5144  new_tuplestore =
5147  tuplestore_puttuple(new_tuplestore, newtup);
5148  }
5149 
5150  /* If transition tables are the only reason we're here, return. */
5151  if ((event == TRIGGER_EVENT_DELETE && !trigdesc->trig_delete_after_row) ||
5152  (event == TRIGGER_EVENT_INSERT && !trigdesc->trig_insert_after_row) ||
5153  (event == TRIGGER_EVENT_UPDATE && !trigdesc->trig_update_after_row))
5154  return;
5155  }
5156 
5157  /*
5158  * Validate the event code and collect the associated tuple CTIDs.
5159  *
5160  * The event code will be used both as a bitmask and an array offset, so
5161  * validation is important to make sure we don't walk off the edge of our
5162  * arrays.
5163  */
5164  switch (event)
5165  {
5166  case TRIGGER_EVENT_INSERT:
5167  tgtype_event = TRIGGER_TYPE_INSERT;
5168  if (row_trigger)
5169  {
5170  Assert(oldtup == NULL);
5171  Assert(newtup != NULL);
5172  ItemPointerCopy(&(newtup->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_DELETE:
5184  tgtype_event = TRIGGER_TYPE_DELETE;
5185  if (row_trigger)
5186  {
5187  Assert(oldtup != NULL);
5188  Assert(newtup == NULL);
5189  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5190  ItemPointerSetInvalid(&(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;
5200  case TRIGGER_EVENT_UPDATE:
5201  tgtype_event = TRIGGER_TYPE_UPDATE;
5202  if (row_trigger)
5203  {
5204  Assert(oldtup != NULL);
5205  Assert(newtup != NULL);
5206  ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
5207  ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
5208  }
5209  else
5210  {
5211  Assert(oldtup == NULL);
5212  Assert(newtup == NULL);
5213  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5214  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5215  }
5216  break;
5218  tgtype_event = TRIGGER_TYPE_TRUNCATE;
5219  Assert(oldtup == NULL);
5220  Assert(newtup == NULL);
5221  ItemPointerSetInvalid(&(new_event.ate_ctid1));
5222  ItemPointerSetInvalid(&(new_event.ate_ctid2));
5223  break;
5224  default:
5225  elog(ERROR, "invalid after-trigger event code: %d", event);
5226  tgtype_event = 0; /* keep compiler quiet */
5227  break;
5228  }
5229 
5230  if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
5231  new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
5233  /* else, we'll initialize ate_flags for each trigger */
5234 
5235  tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
5236 
5237  for (i = 0; i < trigdesc->numtriggers; i++)
5238  {
5239  Trigger *trigger = &trigdesc->triggers[i];
5240 
5241  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
5242  tgtype_level,
5244  tgtype_event))
5245  continue;
5246  if (!TriggerEnabled(estate, relinfo, trigger, event,
5247  modifiedCols, oldtup, newtup))
5248  continue;
5249 
5250  if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
5251  {
5252  if (fdw_tuplestore == NULL)
5253  {
5254  fdw_tuplestore =
5257  new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
5258  }
5259  else
5260  /* subsequent event for the same tuple */
5261  new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
5262  }
5263 
5264  /*
5265  * If the trigger is a foreign key enforcement trigger, there are
5266  * certain cases where we can skip queueing the event because we can
5267  * tell by inspection that the FK constraint will still pass.
5268  */
5269  if (TRIGGER_FIRED_BY_UPDATE(event))
5270  {
5271  switch (RI_FKey_trigger_type(trigger->tgfoid))
5272  {
5273  case RI_TRIGGER_PK:
5274  /* Update on trigger's PK table */
5275  if (!RI_FKey_pk_upd_check_required(trigger, rel,
5276  oldtup, newtup))
5277  {
5278  /* skip queuing this event */
5279  continue;
5280  }
5281  break;
5282 
5283  case RI_TRIGGER_FK:
5284  /* Update on trigger's FK table */
5285  if (!RI_FKey_fk_upd_check_required(trigger, rel,
5286  oldtup, newtup))
5287  {
5288  /* skip queuing this event */
5289  continue;
5290  }
5291  break;
5292 
5293  case RI_TRIGGER_NONE:
5294  /* Not an FK trigger */
5295  break;
5296  }
5297  }
5298 
5299  /*
5300  * If the trigger is a deferred unique constraint check trigger, only
5301  * queue it if the unique constraint was potentially violated, which
5302  * we know from index insertion time.
5303  */
5304  if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
5305  {
5306  if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
5307  continue; /* Uniqueness definitely not violated */
5308  }
5309 
5310  /*
5311  * Fill in event structure and add it to the current query's queue.
5312  */
5313  new_shared.ats_event =
5314  (event & TRIGGER_EVENT_OPMASK) |
5315  (row_trigger ? TRIGGER_EVENT_ROW : 0) |
5316  (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
5317  (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
5318  new_shared.ats_tgoid = trigger->tgoid;
5319  new_shared.ats_relid = RelationGetRelid(rel);
5320  new_shared.ats_firing_id = 0;
5321 
5323  &new_event, &new_shared);
5324  }
5325 
5326  /*
5327  * Finally, spool any foreign tuple(s). The tuplestore squashes them to
5328  * minimal tuples, so this loses any system columns. The executor lost
5329  * those columns before us, for an unrelated reason, so this is fine.
5330  */
5331  if (fdw_tuplestore)
5332  {
5333  if (oldtup != NULL)
5334  tuplestore_puttuple(fdw_tuplestore, oldtup);
5335  if (newtup != NULL)
5336  tuplestore_puttuple(fdw_tuplestore, newtup);
5337  }
5338 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TriggerEvent ats_event
Definition: trigger.c:3272
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3416
Relation ri_RelationDesc
Definition: execnodes.h:354
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3701
#define AFTER_TRIGGER_FDW_REUSE
Definition: trigger.c:3262
#define AFTER_TRIGGER_INITDEFERRED
Definition: trigger.h:68
ItemPointerData ate_ctid2
Definition: trigger.c:3284
#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:3282
#define AFTER_TRIGGER_DEFERRABLE
Definition: trigger.h:67
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Oid tgoid
Definition: reltrigger.h:25
bool trig_update_new_table
Definition: reltrigger.h:76
Form_pg_class rd_rel
Definition: rel.h:114
#define TRIGGER_EVENT_OPMASK
Definition: trigger.h:56
bool trig_insert_new_table
Definition: reltrigger.h:74
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
int16 tgtype
Definition: reltrigger.h:29
bool tgdeferrable
Definition: reltrigger.h:35
ItemPointerData t_self
Definition: htup.h:65
bool tginitdeferred
Definition: reltrigger.h:36
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:730
bool trig_delete_after_row
Definition: reltrigger.h:66
Trigger * triggers
Definition: reltrigger.h:48
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
bool trig_insert_after_row
Definition: reltrigger.h:56
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
bool trig_update_old_table
Definition: reltrigger.h:75
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3264
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3265
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
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:2141
#define TRIGGER_TYPE_TRUNCATE
Definition: pg_trigger.h:103
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:102
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3040
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4585
#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:3541
#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:2084
static Tuplestorestate * GetTriggerTransitionTuplestore(Tuplestorestate **tss)
Definition: trigger.c:3451
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
#define AFTER_TRIGGER_FDW_FETCH
Definition: trigger.c:3263
CommandId ats_firing_id
Definition: trigger.c:3275
#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:150
int i
bool trig_delete_old_table
Definition: reltrigger.h:77
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3414
AfterTriggerEventList * query_stack
Definition: trigger.c:3413
#define elog
Definition: elog.h:219
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
ItemPointerData ate_ctid1
Definition: trigger.c:3283
#define RI_TRIGGER_NONE
Definition: trigger.h:211
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:76
static AfterTriggersData afterTriggers
Definition: trigger.c:3430
#define RelationGetRelid(relation)
Definition: rel.h:416
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3417
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:139
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

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

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

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

961 {
962  static List *info_list = NIL;
963 
964  static const char *const funcdescr[3] = {
965  gettext_noop("Found referenced table's UPDATE trigger."),
966  gettext_noop("Found referenced table's DELETE trigger."),
967  gettext_noop("Found referencing table's trigger.")
968  };
969 
970  char *constr_name;
971  char *fk_table_name;
972  char *pk_table_name;
973  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
974  List *fk_attrs = NIL;
975  List *pk_attrs = NIL;
977  int funcnum;
978  OldTriggerInfo *info = NULL;
979  ListCell *l;
980  int i;
981 
982  /* Parse out the trigger arguments */
983  constr_name = strVal(linitial(stmt->args));
984  fk_table_name = strVal(lsecond(stmt->args));
985  pk_table_name = strVal(lthird(stmt->args));
986  i = 0;
987  foreach(l, stmt->args)
988  {
989  Value *arg = (Value *) lfirst(l);
990 
991  i++;
992  if (i < 4) /* skip constraint and table names */
993  continue;
994  if (i == 4) /* handle match type */
995  {
996  if (strcmp(strVal(arg), "FULL") == 0)
997  fk_matchtype = FKCONSTR_MATCH_FULL;
998  else
999  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
1000  continue;
1001  }
1002  if (i % 2)
1003  fk_attrs = lappend(fk_attrs, arg);
1004  else
1005  pk_attrs = lappend(pk_attrs, arg);
1006  }
1007 
1008  /* Prepare description of constraint for use in messages */
1009  initStringInfo(&buf);
1010  appendStringInfo(&buf, "FOREIGN KEY %s(",
1011  quote_identifier(fk_table_name));
1012  i = 0;
1013  foreach(l, fk_attrs)
1014  {
1015  Value *arg = (Value *) lfirst(l);
1016 
1017  if (i++ > 0)
1018  appendStringInfoChar(&buf, ',');
1020  }
1021  appendStringInfo(&buf, ") REFERENCES %s(",
1022  quote_identifier(pk_table_name));
1023  i = 0;
1024  foreach(l, pk_attrs)
1025  {
1026  Value *arg = (Value *) lfirst(l);
1027 
1028  if (i++ > 0)
1029  appendStringInfoChar(&buf, ',');
1031  }
1032  appendStringInfoChar(&buf, ')');
1033 
1034  /* Identify class of trigger --- update, delete, or referencing-table */
1035  switch (funcoid)
1036  {
1037  case F_RI_FKEY_CASCADE_UPD:
1038  case F_RI_FKEY_RESTRICT_UPD:
1039  case F_RI_FKEY_SETNULL_UPD:
1040  case F_RI_FKEY_SETDEFAULT_UPD:
1041  case F_RI_FKEY_NOACTION_UPD:
1042  funcnum = 0;
1043  break;
1044 
1045  case F_RI_FKEY_CASCADE_DEL:
1046  case F_RI_FKEY_RESTRICT_DEL:
1047  case F_RI_FKEY_SETNULL_DEL:
1048  case F_RI_FKEY_SETDEFAULT_DEL:
1049  case F_RI_FKEY_NOACTION_DEL:
1050  funcnum = 1;
1051  break;
1052 
1053  default:
1054  funcnum = 2;
1055  break;
1056  }
1057 
1058  /* See if we have a match to this trigger */
1059  foreach(l, info_list)
1060  {
1061  info = (OldTriggerInfo *) lfirst(l);
1062  if (info->funcoids[funcnum] == InvalidOid &&
1063  equal(info->args, stmt->args))
1064  {
1065  info->funcoids[funcnum] = funcoid;
1066  break;
1067  }
1068  }
1069 
1070  if (l == NULL)
1071  {
1072  /* First trigger of set, so create a new list entry */
1073  MemoryContext oldContext;
1074 
1075  ereport(NOTICE,
1076  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1077  constr_name, buf.data),
1078  errdetail_internal("%s", _(funcdescr[funcnum]))));
1080  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
1081  info->args = copyObject(stmt->args);
1082  info->funcoids[funcnum] = funcoid;
1083  info_list = lappend(info_list, info);
1084  MemoryContextSwitchTo(oldContext);
1085  }
1086  else if (info->funcoids[0] == InvalidOid ||
1087  info->funcoids[1] == InvalidOid ||
1088  info->funcoids[2] == InvalidOid)
1089  {
1090  /* Second trigger of set */
1091  ereport(NOTICE,
1092  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1093  constr_name, buf.data),
1094  errdetail_internal("%s", _(funcdescr[funcnum]))));
1095  }
1096  else
1097  {
1098  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
1101  Constraint *fkcon = makeNode(Constraint);
1102  PlannedStmt *wrapper = makeNode(PlannedStmt);
1103 
1104  ereport(NOTICE,
1105  (errmsg("converting trigger group into constraint \"%s\" %s",
1106  constr_name, buf.data),
1107  errdetail_internal("%s", _(funcdescr[funcnum]))));
1108  fkcon->contype = CONSTR_FOREIGN;
1109  fkcon->location = -1;
1110  if (funcnum == 2)
1111  {
1112  /* This trigger is on the FK table */
1113  atstmt->relation = stmt->relation;
1114  if (stmt->constrrel)
1115  fkcon->pktable = stmt->constrrel;
1116  else
1117  {
1118  /* Work around ancient pg_dump bug that omitted constrrel */
1119  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
1120  }
1121  }
1122  else
1123  {
1124  /* This trigger is on the PK table */
1125  fkcon->pktable = stmt->relation;
1126  if (stmt->constrrel)
1127  atstmt->relation = stmt->constrrel;
1128  else
1129  {
1130  /* Work around ancient pg_dump bug that omitted constrrel */
1131  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1132  }
1133  }
1134  atstmt->cmds = list_make1(atcmd);
1135  atstmt->relkind = OBJECT_TABLE;
1136  atcmd->subtype = AT_AddConstraint;
1137  atcmd->def = (Node *) fkcon;
1138  if (strcmp(constr_name, "<unnamed>") == 0)
1139  fkcon->conname = NULL;
1140  else
1141  fkcon->conname = constr_name;
1142  fkcon->fk_attrs = fk_attrs;
1143  fkcon->pk_attrs = pk_attrs;
1144  fkcon->fk_matchtype = fk_matchtype;
1145  switch (info->funcoids[0])
1146  {
1147  case F_RI_FKEY_NOACTION_UPD:
1149  break;
1150  case F_RI_FKEY_CASCADE_UPD:
1152  break;
1153  case F_RI_FKEY_RESTRICT_UPD:
1155  break;
1156  case F_RI_FKEY_SETNULL_UPD:
1158  break;
1159  case F_RI_FKEY_SETDEFAULT_UPD:
1161  break;
1162  default:
1163  /* can't get here because of earlier checks */
1164  elog(ERROR, "confused about RI update function");
1165  }
1166  switch (info->funcoids[1])
1167  {
1168  case F_RI_FKEY_NOACTION_DEL:
1170  break;
1171  case F_RI_FKEY_CASCADE_DEL:
1173  break;
1174  case F_RI_FKEY_RESTRICT_DEL:
1176  break;
1177  case F_RI_FKEY_SETNULL_DEL:
1179  break;
1180  case F_RI_FKEY_SETDEFAULT_DEL:
1182  break;
1183  default:
1184  /* can't get here because of earlier checks */
1185  elog(ERROR, "confused about RI delete function");
1186  }
1187  fkcon->deferrable = stmt->deferrable;
1188  fkcon->initdeferred = stmt->initdeferred;
1189  fkcon->skip_validation = false;
1190  fkcon->initially_valid = true;
1191 
1192  /* finally, wrap it in a dummy PlannedStmt */
1193  wrapper->commandType = CMD_UTILITY;
1194  wrapper->canSetTag = false;
1195  wrapper->utilityStmt = (Node *) atstmt;
1196  wrapper->stmt_location = -1;
1197  wrapper->stmt_len = -1;
1198 
1199  /* ... and execute it */
1200  ProcessUtility(wrapper,
1201  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1203  None_Receiver, NULL);
1204 
1205  /* Remove the matched item from the list */
1206  info_list = list_delete_ptr(info_list, info);
1207  pfree(info);
1208  /* We leak the copied args ... not worth worrying about */
1209  }
1210 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2060
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10280
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2962
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2051
char fk_matchtype
Definition: parsenodes.h:2097
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2055
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:509
#define strVal(v)
Definition: value.h:54
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:335
bool initdeferred
Definition: parsenodes.h:2070
AlterTableType subtype
Definition: parsenodes.h:1764
List * pk_attrs
Definition: parsenodes.h:2096
char * conname
Definition: parsenodes.h:2068
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
DestReceiver * None_Receiver
Definition: dest.c:91
int stmt_len
Definition: plannodes.h:98
#define lsecond(l)
Definition: pg_list.h:116
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
#define list_make1(x1)
Definition: pg_list.h:139
RangeVar * constrrel
Definition: parsenodes.h:2355
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2069
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
int stmt_location
Definition: plannodes.h:97
static char * buf
Definition: pg_test_fsync.c:66
Node * utilityStmt
Definition: plannodes.h:94
Oid funcoids[3]
Definition: trigger.c:955
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1679
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2053
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2058
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:2106
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:557
char fk_del_action
Definition: parsenodes.h:2099
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:954
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1677
int i
RangeVar * relation
Definition: parsenodes.h:2339
ConstrType contype
Definition: parsenodes.h:2065
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2052
#define lthird(l)
Definition: pg_list.h:121
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:622
RangeVar * pktable
Definition: parsenodes.h:2094
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2054
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:2105
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:2095
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:2098
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1853 {
1854  TriggerDesc *newdesc;
1855  Trigger *trigger;
1856  int i;
1857 
1858  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1859  return NULL;
1860 
1861  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1862  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1863 
1864  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1865  memcpy(trigger, trigdesc->triggers,
1866  trigdesc->numtriggers * sizeof(Trigger));
1867  newdesc->triggers = trigger;
1868 
1869  for (i = 0; i < trigdesc->numtriggers; i++)
1870  {
1871  trigger->tgname = pstrdup(trigger->tgname);
1872  if (trigger->tgnattr > 0)
1873  {
1874  int16 *newattr;
1875 
1876  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1877  memcpy(newattr, trigger->tgattr,
1878  trigger->tgnattr * sizeof(int16));
1879  trigger->tgattr = newattr;
1880  }
1881  if (trigger->tgnargs > 0)
1882  {
1883  char **newargs;
1884  int16 j;
1885 
1886  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1887  for (j = 0; j < trigger->tgnargs; j++)
1888  newargs[j] = pstrdup(trigger->tgargs[j]);
1889  trigger->tgargs = newargs;
1890  }
1891  if (trigger->tgqual)
1892  trigger->tgqual = pstrdup(trigger->tgqual);
1893  if (trigger->tgoldtable)
1894  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1895  if (trigger->tgnewtable)
1896  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1897  trigger++;
1898  }
1899 
1900  return newdesc;
1901 }
signed short int16
Definition: c.h:255
char * pstrdup(const char *in)
Definition: mcxt.c:1077
char * tgqual
Definition: reltrigger.h:41
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char ** tgargs
Definition: reltrigger.h:40
int16 * tgattr
Definition: reltrigger.h:39
char * tgnewtable
Definition: reltrigger.h:43
#define NULL
Definition: c.h:229
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:849
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42
ObjectAddress CreateTrigger ( CreateTrigStmt stmt,
const char *  queryString,
Oid  relOid,
Oid  refRelOid,
Oid  constraintOid,
Oid  indexOid,
bool  isInternal 
)

Definition at line 138 of file trigger.c.

References AccessShareLock, ACL_EXECUTE, ACL_KIND_CLASS, ACL_KIND_PROC, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addRangeTableEntryForRelation(), addRTEtoQuery(), allowSystemTableMods, Anum_pg_trigger_tgargs, Anum_pg_trigger_tgattr, Anum_pg_trigger_tgconstraint, Anum_pg_trigger_tgconstrindid, Anum_pg_trigger_tgconstrrelid, Anum_pg_trigger_tgdeferrable, Anum_pg_trigger_tgenabled, Anum_pg_trigger_tgfoid, Anum_pg_trigger_tginitdeferred, Anum_pg_trigger_tgisinternal, Anum_pg_trigger_tgname, Anum_pg_trigger_tgnargs, Anum_pg_trigger_tgnewtable, Anum_pg_trigger_tgoldtable, Anum_pg_trigger_tgqual, Anum_pg_trigger_tgrelid, Anum_pg_trigger_tgtype, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CONSTRAINT_TRIGGER, ConstraintRelationId, CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject, CreateConstraintEntry(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), GetNewOid(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleIsValid, HeapTupleSetOid, i, CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, lfirst, lfirst_node, list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), name, TriggerTransition::name, NAMEDATALEN, namein(), NameListToString(), namestrcmp(), Natts_pg_trigger, NIL, nodeToString(), NoLock, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPAQUEOID, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, ProcedureRelationId, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, snprintf(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, TRIGGER_CLEAR_TYPE, TRIGGER_FIRES_ON_ORIGIN, TRIGGER_FOR_BEFORE, TRIGGER_FOR_DELETE, TRIGGER_FOR_INSERT, TRIGGER_FOR_INSTEAD, TRIGGER_FOR_ROW, TRIGGER_FOR_TRUNCATE, TRIGGER_FOR_UPDATE, TRIGGER_SETT_ROW, TRIGGER_TYPE_AFTER, TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSTEAD, TRIGGEROID, TriggerRelationId, TriggerRelidNameIndexId, CreateTrigStmt::trigname, values, Var::varattno, Var::varno, WARNING, and CreateTrigStmt::whenClause.

Referenced by CreateFKCheckTrigger(), createForeignKeyTriggers(), index_constraint_create(), and ProcessUtilitySlow().

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

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

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

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

2477 {
2478  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2479 
2480  if (trigdesc &&
2481  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2482  {
2483  HeapTuple trigtuple;
2484 
2485  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2486  if (fdw_trigtuple == NULL)
2487  trigtuple = GetTupleForTrigger(estate,
2488  NULL,
2489  relinfo,
2490  tupleid,
2492  NULL);
2493  else
2494  trigtuple = fdw_trigtuple;
2495 
2497  true, trigtuple, NULL, NIL, NULL);
2498  if (trigtuple != fdw_trigtuple)
2499  heap_freetuple(trigtuple);
2500  }
2501 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
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:5090
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2896
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

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

2267 {
2268  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2269 
2270  if (trigdesc &&
2271  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2273  true, NULL, trigtuple, recheckIndexes, NULL);
2274 }
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:5090
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#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 2734 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().

2739 {
2740  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2741 
2742  if (trigdesc && (trigdesc->trig_update_after_row ||
2743  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2744  {
2745  HeapTuple trigtuple;
2746 
2747  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2748  if (fdw_trigtuple == NULL)
2749  trigtuple = GetTupleForTrigger(estate,
2750  NULL,
2751  relinfo,
2752  tupleid,
2754  NULL);
2755  else
2756  trigtuple = fdw_trigtuple;
2757 
2759  true, trigtuple, newtuple, recheckIndexes,
2760  GetUpdatedColumns(relinfo, estate));
2761  if (trigtuple != fdw_trigtuple)
2762  heap_freetuple(trigtuple);
2763  }
2764 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
bool trig_update_new_table
Definition: reltrigger.h:76
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
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:5090
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
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:2896
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2395 of file trigger.c.

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

Referenced by fireASTriggers().

2396 {
2397  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2398 
2399  if (trigdesc && trigdesc->trig_delete_after_statement)
2401  false, NULL, NULL, NIL, NULL);
2402 }
#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:5090
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)