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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static void ConvertTriggerToFK (CreateTrigStmt *stmt, Oid funcoid)
 
static void SetTriggerFlags (TriggerDesc *trigdesc, Trigger *trigger)
 
static HeapTuple GetTupleForTrigger (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
 
static bool TriggerEnabled (EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
 
static HeapTuple ExecCallTriggerFunc (TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
 
static void AfterTriggerSaveEvent (EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
 
static void AfterTriggerEnlargeQueryState (void)
 
ObjectAddress CreateTrigger (CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, bool isInternal)
 
void RemoveTriggerById (Oid trigOid)
 
Oid get_trigger_oid (Oid relid, const char *trigname, bool missing_ok)
 
static void RangeVarCallbackForRenameTrigger (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renametrig (RenameStmt *stmt)
 
void EnableDisableTrigger (Relation rel, const char *tgname, char fires_when, bool skip_system)
 
void RelationBuildTriggers (Relation relation)
 
TriggerDescCopyTriggerDesc (TriggerDesc *trigdesc)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes)
 
TupleTableSlotExecIRUpdateTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
 
void ExecBSTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
static void AfterTriggerExecute (AfterTriggerEvent event, Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
 
static SetConstraintState SetConstraintStateCreate (int numalloc)
 
static SetConstraintState SetConstraintStateCopy (SetConstraintState state)
 
static SetConstraintState SetConstraintStateAddItem (SetConstraintState state, Oid tgoid, bool tgisdeferred)
 
static TuplestorestateGetTriggerTransitionTuplestore (Tuplestorestate **tss)
 
static bool afterTriggerCheckState (AfterTriggerShared evtshared)
 
static void afterTriggerAddEvent (AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
 
static void afterTriggerFreeEventList (AfterTriggerEventList *events)
 
static void afterTriggerRestoreEventList (AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
 
static bool afterTriggerMarkEvents (AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
 
static bool afterTriggerInvokeEvents (AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
 
void AfterTriggerBeginXact (void)
 
void AfterTriggerBeginQuery (void)
 
void AfterTriggerEndQuery (EState *estate)
 
void AfterTriggerFireDeferred (void)
 
void AfterTriggerEndXact (bool isCommit)
 
void AfterTriggerBeginSubXact (void)
 
void AfterTriggerEndSubXact (bool isCommit)
 
void AfterTriggerSetState (ConstraintsSetStmt *stmt)
 
bool AfterTriggerPendingOnRel (Oid relid)
 
Datum pg_trigger_depth (PG_FUNCTION_ARGS)
 

Variables

int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN
 
static int MyTriggerDepth = 0
 
static AfterTriggersData afterTriggers
 

Macro Definition Documentation

#define AFTER_TRIGGER_1CTID   0x40000000

Definition at line 3242 of file trigger.c.

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3243 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3241 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

Definition at line 3240 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

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

Definition at line 3235 of file trigger.c.

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3244 of file trigger.c.

Referenced by AfterTriggerExecute().

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

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

Definition at line 3317 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:3244
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3242
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3243

Definition at line 3278 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3256 of file trigger.c.

Definition at line 3246 of file trigger.c.

Definition at line 3233 of file trigger.c.

Function Documentation

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

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

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

Definition at line 4153 of file trigger.c.

References AfterTriggersData::query_depth.

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

4154 {
4155  /* Increase the query stack depth */
4157 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
void AfterTriggerBeginSubXact ( void  )

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

4378 {
4379  int my_level = GetCurrentTransactionNestLevel();
4380 
4381  /*
4382  * Allocate more space in the stacks if needed. (Note: because the
4383  * minimum nest level of a subtransaction is 2, we waste the first couple
4384  * entries of each array; not worth the notational effort to avoid it.)
4385  */
4386  while (my_level >= afterTriggers.maxtransdepth)
4387  {
4388  if (afterTriggers.maxtransdepth == 0)
4389  {
4390  MemoryContext old_cxt;
4391 
4393 
4394 #define DEFTRIG_INITALLOC 8
4399  afterTriggers.depth_stack = (int *)
4400  palloc(DEFTRIG_INITALLOC * sizeof(int));
4402  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4404 
4405  MemoryContextSwitchTo(old_cxt);
4406  }
4407  else
4408  {
4409  /* repalloc will keep the stacks in the same context */
4410  int new_alloc = afterTriggers.maxtransdepth * 2;
4411 
4414  new_alloc * sizeof(SetConstraintState));
4417  new_alloc * sizeof(AfterTriggerEventList));
4418  afterTriggers.depth_stack = (int *)
4420  new_alloc * sizeof(int));
4423  new_alloc * sizeof(CommandId));
4424  afterTriggers.maxtransdepth = new_alloc;
4425  }
4426  }
4427 
4428  /*
4429  * Push the current information into the stack. The SET CONSTRAINTS state
4430  * is not saved until/unless changed. Likewise, we don't make a
4431  * per-subtransaction event context until needed.
4432  */
4433  afterTriggers.state_stack[my_level] = NULL;
4437 }
uint32 CommandId
Definition: c.h:407
MemoryContext TopTransactionContext
Definition: mcxt.c:48
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define DEFTRIG_INITALLOC
CommandId * firing_stack
Definition: trigger.c:3403
SetConstraintState * state_stack
Definition: trigger.c:3400
CommandId firing_counter
Definition: trigger.c:3387
AfterTriggerEventList * events_stack
Definition: trigger.c:3401
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:759
#define NULL
Definition: c.h:226
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
void * palloc(Size size)
Definition: mcxt.c:891
AfterTriggerEventList events
Definition: trigger.c:3389
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
void AfterTriggerBeginXact ( void  )

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

4116 {
4117  /*
4118  * Initialize after-trigger state structure to empty
4119  */
4120  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4122 
4123  /*
4124  * Verify that there is no leftover state remaining. If these assertions
4125  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4126  * up properly.
4127  */
4141 }
uint32 CommandId
Definition: c.h:407
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3393
CommandId * firing_stack
Definition: trigger.c:3403
SetConstraintState * state_stack
Definition: trigger.c:3400
SetConstraintState state
Definition: trigger.c:3388
CommandId firing_counter
Definition: trigger.c:3387
AfterTriggerEventList * events_stack
Definition: trigger.c:3401
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
AfterTriggerEventChunk * head
Definition: trigger.c:3309
MemoryContext event_cxt
Definition: trigger.c:3396
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3392
AfterTriggerEventList events
Definition: trigger.c:3389
AfterTriggerEventList * query_stack
Definition: trigger.c:3391
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3394
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

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

Definition at line 4173 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 CopyFrom(), ExecuteTruncate(), and standard_ExecutorFinish().

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

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

4446 {
4447  int my_level = GetCurrentTransactionNestLevel();
4449  AfterTriggerEvent event;
4450  AfterTriggerEventChunk *chunk;
4451  CommandId subxact_firing_id;
4452 
4453  /*
4454  * Pop the prior state if needed.
4455  */
4456  if (isCommit)
4457  {
4458  Assert(my_level < afterTriggers.maxtransdepth);
4459  /* If we saved a prior state, we don't need it anymore */
4460  state = afterTriggers.state_stack[my_level];
4461  if (state != NULL)
4462  pfree(state);
4463  /* this avoids double pfree if error later: */
4464  afterTriggers.state_stack[my_level] = NULL;
4466  afterTriggers.depth_stack[my_level]);
4467  }
4468  else
4469  {
4470  /*
4471  * Aborting. It is possible subxact start failed before calling
4472  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4473  * stack levels that aren't there.
4474  */
4475  if (my_level >= afterTriggers.maxtransdepth)
4476  return;
4477 
4478  /*
4479  * Release any event lists from queries being aborted, and restore
4480  * query_depth to its pre-subxact value. This assumes that a
4481  * subtransaction will not add events to query levels started in a
4482  * earlier transaction state.
4483  */
4485  {
4487  {
4488  Tuplestorestate *ts;
4489 
4491  if (ts)
4492  {
4493  tuplestore_end(ts);
4495  }
4497  if (ts)
4498  {
4499  tuplestore_end(ts);
4501  }
4503  if (ts)
4504  {
4505  tuplestore_end(ts);
4507  }
4508 
4510  }
4511 
4513  }
4515  afterTriggers.depth_stack[my_level]);
4516 
4517  /*
4518  * Restore the global deferred-event list to its former length,
4519  * discarding any events queued by the subxact.
4520  */
4522  &afterTriggers.events_stack[my_level]);
4523 
4524  /*
4525  * Restore the trigger state. If the saved state is NULL, then this
4526  * subxact didn't save it, so it doesn't need restoring.
4527  */
4528  state = afterTriggers.state_stack[my_level];
4529  if (state != NULL)
4530  {
4532  afterTriggers.state = state;
4533  }
4534  /* this avoids double pfree if error later: */
4535  afterTriggers.state_stack[my_level] = NULL;
4536 
4537  /*
4538  * Scan for any remaining deferred events that were marked DONE or IN
4539  * PROGRESS by this subxact or a child, and un-mark them. We can
4540  * recognize such events because they have a firing ID greater than or
4541  * equal to the firing_counter value we saved at subtransaction start.
4542  * (This essentially assumes that the current subxact includes all
4543  * subxacts started after it.)
4544  */
4545  subxact_firing_id = afterTriggers.firing_stack[my_level];
4547  {
4548  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4549 
4550  if (event->ate_flags &
4552  {
4553  if (evtshared->ats_firing_id >= subxact_firing_id)
4554  event->ate_flags &=
4556  }
4557  }
4558  }
4559 }
uint32 CommandId
Definition: c.h:407
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3393
TriggerFlags ate_flags
Definition: trigger.c:3260
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3237
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3322
CommandId * firing_stack
Definition: trigger.c:3403
#define GetTriggerSharedData(evt)
Definition: trigger.c:3285
void pfree(void *pointer)
Definition: mcxt.c:992
SetConstraintState * state_stack
Definition: trigger.c:3400
SetConstraintState state
Definition: trigger.c:3388
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3633
AfterTriggerEventList * events_stack
Definition: trigger.c:3401
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:759
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
Definition: regguts.h:298
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:450
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3656
CommandId ats_firing_id
Definition: trigger.c:3253
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3238
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3392
AfterTriggerEventList events
Definition: trigger.c:3389
AfterTriggerEventList * query_stack
Definition: trigger.c:3391
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3394
void AfterTriggerEndXact ( bool  isCommit)

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

4324 {
4325  /*
4326  * Forget the pending-events list.
4327  *
4328  * Since all the info is in TopTransactionContext or children thereof, we
4329  * don't really need to do anything to reclaim memory. However, the
4330  * pending-events list could be large, and so it's useful to discard it as
4331  * soon as possible --- especially if we are aborting because we ran out
4332  * of memory for the list!
4333  */
4335  {
4341  }
4342 
4343  /*
4344  * Forget any subtransaction state as well. Since this can't be very
4345  * large, we let the eventual reset of TopTransactionContext free the
4346  * memory instead of doing it here.
4347  */
4353 
4354 
4355  /*
4356  * Forget the query stack and constraint-related state information. As
4357  * with the subtransaction state information, we don't bother freeing the
4358  * memory here.
4359  */
4366 
4367  /* No more afterTriggers manipulation until next transaction starts. */
4369 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3393
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3310
CommandId * firing_stack
Definition: trigger.c:3403
SetConstraintState * state_stack
Definition: trigger.c:3400
SetConstraintState state
Definition: trigger.c:3388
AfterTriggerEventList * events_stack
Definition: trigger.c:3401
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3309
MemoryContext event_cxt
Definition: trigger.c:3396
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3392
AfterTriggerEventList events
Definition: trigger.c:3389
AfterTriggerEventList * query_stack
Definition: trigger.c:3391
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3394
static void AfterTriggerEnlargeQueryState ( void  )
static

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

4572 {
4573  int init_depth = afterTriggers.maxquerydepth;
4574 
4576 
4577  if (afterTriggers.maxquerydepth == 0)
4578  {
4579  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4580 
4583  new_alloc * sizeof(AfterTriggerEventList));
4586  new_alloc * sizeof(Tuplestorestate *));
4589  new_alloc * sizeof(Tuplestorestate *));
4592  new_alloc * sizeof(Tuplestorestate *));
4593  afterTriggers.maxquerydepth = new_alloc;
4594  }
4595  else
4596  {
4597  /* repalloc will keep the stack in the same context */
4598  int old_alloc = afterTriggers.maxquerydepth;
4599  int new_alloc = Max(afterTriggers.query_depth + 1,
4600  old_alloc * 2);
4601 
4604  new_alloc * sizeof(AfterTriggerEventList));
4607  new_alloc * sizeof(Tuplestorestate *));
4610  new_alloc * sizeof(Tuplestorestate *));
4613  new_alloc * sizeof(Tuplestorestate *));
4614  /* Clear newly-allocated slots for subsequent lazy initialization. */
4615  memset(afterTriggers.fdw_tuplestores + old_alloc,
4616  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4617  memset(afterTriggers.old_tuplestores + old_alloc,
4618  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4619  memset(afterTriggers.new_tuplestores + old_alloc,
4620  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4621  afterTriggers.maxquerydepth = new_alloc;
4622  }
4623 
4624  /* Initialize new query lists to empty */
4625  while (init_depth < afterTriggers.maxquerydepth)
4626  {
4627  AfterTriggerEventList *events;
4628 
4629  events = &afterTriggers.query_stack[init_depth];
4630  events->head = NULL;
4631  events->tail = NULL;
4632  events->tailfree = NULL;
4633 
4634  ++init_depth;
4635  }
4636 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3393
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3310
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:784
#define Max(x, y)
Definition: c.h:792
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
AfterTriggerEventChunk * head
Definition: trigger.c:3309
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3392
AfterTriggerEventList * query_stack
Definition: trigger.c:3391
static AfterTriggersData afterTriggers
Definition: trigger.c:3407
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3394
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 3711 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().

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

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

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

Definition at line 3633 of file trigger.c.

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

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

3634 {
3635  AfterTriggerEventChunk *chunk;
3636  AfterTriggerEventChunk *next_chunk;
3637 
3638  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3639  {
3640  next_chunk = chunk->next;
3641  pfree(chunk);
3642  }
3643  events->head = NULL;
3644  events->tail = NULL;
3645  events->tailfree = NULL;
3646 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3310
struct AfterTriggerEventChunk * next
Definition: trigger.c:3297
void pfree(void *pointer)
Definition: mcxt.c:992
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3309
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

Definition at line 3970 of file trigger.c.

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

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

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

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

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

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

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

Definition at line 3656 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

3658 {
3659  AfterTriggerEventChunk *chunk;
3660  AfterTriggerEventChunk *next_chunk;
3661 
3662  if (old_events->tail == NULL)
3663  {
3664  /* restoring to a completely empty state, so free everything */
3665  afterTriggerFreeEventList(events);
3666  }
3667  else
3668  {
3669  *events = *old_events;
3670  /* free any chunks after the last one we want to keep */
3671  for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
3672  {
3673  next_chunk = chunk->next;
3674  pfree(chunk);
3675  }
3676  /* and clean up the tail chunk to be the right length */
3677  events->tail->next = NULL;
3678  events->tail->freeptr = events->tailfree;
3679 
3680  /*
3681  * We don't make any effort to remove now-unused shared data records.
3682  * They might still be useful, anyway.
3683  */
3684  }
3685 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3310
struct AfterTriggerEventChunk * next
Definition: trigger.c:3297
void pfree(void *pointer)
Definition: mcxt.c:992
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3633
#define NULL
Definition: c.h:226
static void AfterTriggerSaveEvent ( EState estate,
ResultRelInfo relinfo,
int  event,
bool  row_trigger,
HeapTuple  oldtup,
HeapTuple  newtup,
List recheckIndexes,
Bitmapset modifiedCols 
)
static

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

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

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

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

Definition at line 939 of file trigger.c.

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), arg, OldTriggerInfo::args, CreateTrigStmt::args, AT_AddConstraint, buf, AlterTableStmt::cmds, Constraint::conname, CONSTR_FOREIGN, CreateTrigStmt::constrrel, Constraint::contype, copyObject(), StringInfoData::data, AlterTableCmd::def, Constraint::deferrable, CreateTrigStmt::deferrable, elog, equal(), ereport, errdetail_internal(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, FKCONSTR_ACTION_CASCADE, FKCONSTR_ACTION_NOACTION, FKCONSTR_ACTION_RESTRICT, FKCONSTR_ACTION_SETDEFAULT, FKCONSTR_ACTION_SETNULL, FKCONSTR_MATCH_FULL, FKCONSTR_MATCH_SIMPLE, OldTriggerInfo::funcoids, gettext_noop, i, Constraint::initdeferred, CreateTrigStmt::initdeferred, Constraint::initially_valid, initStringInfo(), InvalidOid, lappend(), lfirst, linitial, list_delete_ptr(), list_make1, Constraint::location, lsecond, lthird, makeNode, makeRangeVar(), MemoryContextSwitchTo(), NIL, None_Receiver, NOTICE, NULL, OBJECT_TABLE, palloc0(), pfree(), Constraint::pk_attrs, Constraint::pktable, PROCESS_UTILITY_SUBCOMMAND, ProcessUtility(), quote_identifier(), AlterTableStmt::relation, CreateTrigStmt::relation, AlterTableStmt::relkind, Constraint::skip_validation, strVal, AlterTableCmd::subtype, and TopMemoryContext.

Referenced by CreateTrigger().

940 {
941  static List *info_list = NIL;
942 
943  static const char *const funcdescr[3] = {
944  gettext_noop("Found referenced table's UPDATE trigger."),
945  gettext_noop("Found referenced table's DELETE trigger."),
946  gettext_noop("Found referencing table's trigger.")
947  };
948 
949  char *constr_name;
950  char *fk_table_name;
951  char *pk_table_name;
952  char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
953  List *fk_attrs = NIL;
954  List *pk_attrs = NIL;
956  int funcnum;
957  OldTriggerInfo *info = NULL;
958  ListCell *l;
959  int i;
960 
961  /* Parse out the trigger arguments */
962  constr_name = strVal(linitial(stmt->args));
963  fk_table_name = strVal(lsecond(stmt->args));
964  pk_table_name = strVal(lthird(stmt->args));
965  i = 0;
966  foreach(l, stmt->args)
967  {
968  Value *arg = (Value *) lfirst(l);
969 
970  i++;
971  if (i < 4) /* skip constraint and table names */
972  continue;
973  if (i == 4) /* handle match type */
974  {
975  if (strcmp(strVal(arg), "FULL") == 0)
976  fk_matchtype = FKCONSTR_MATCH_FULL;
977  else
978  fk_matchtype = FKCONSTR_MATCH_SIMPLE;
979  continue;
980  }
981  if (i % 2)
982  fk_attrs = lappend(fk_attrs, arg);
983  else
984  pk_attrs = lappend(pk_attrs, arg);
985  }
986 
987  /* Prepare description of constraint for use in messages */
988  initStringInfo(&buf);
989  appendStringInfo(&buf, "FOREIGN KEY %s(",
990  quote_identifier(fk_table_name));
991  i = 0;
992  foreach(l, fk_attrs)
993  {
994  Value *arg = (Value *) lfirst(l);
995 
996  if (i++ > 0)
997  appendStringInfoChar(&buf, ',');
999  }
1000  appendStringInfo(&buf, ") REFERENCES %s(",
1001  quote_identifier(pk_table_name));
1002  i = 0;
1003  foreach(l, pk_attrs)
1004  {
1005  Value *arg = (Value *) lfirst(l);
1006 
1007  if (i++ > 0)
1008  appendStringInfoChar(&buf, ',');
1010  }
1011  appendStringInfoChar(&buf, ')');
1012 
1013  /* Identify class of trigger --- update, delete, or referencing-table */
1014  switch (funcoid)
1015  {
1016  case F_RI_FKEY_CASCADE_UPD:
1017  case F_RI_FKEY_RESTRICT_UPD:
1018  case F_RI_FKEY_SETNULL_UPD:
1019  case F_RI_FKEY_SETDEFAULT_UPD:
1020  case F_RI_FKEY_NOACTION_UPD:
1021  funcnum = 0;
1022  break;
1023 
1024  case F_RI_FKEY_CASCADE_DEL:
1025  case F_RI_FKEY_RESTRICT_DEL:
1026  case F_RI_FKEY_SETNULL_DEL:
1027  case F_RI_FKEY_SETDEFAULT_DEL:
1028  case F_RI_FKEY_NOACTION_DEL:
1029  funcnum = 1;
1030  break;
1031 
1032  default:
1033  funcnum = 2;
1034  break;
1035  }
1036 
1037  /* See if we have a match to this trigger */
1038  foreach(l, info_list)
1039  {
1040  info = (OldTriggerInfo *) lfirst(l);
1041  if (info->funcoids[funcnum] == InvalidOid &&
1042  equal(info->args, stmt->args))
1043  {
1044  info->funcoids[funcnum] = funcoid;
1045  break;
1046  }
1047  }
1048 
1049  if (l == NULL)
1050  {
1051  /* First trigger of set, so create a new list entry */
1052  MemoryContext oldContext;
1053 
1054  ereport(NOTICE,
1055  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1056  constr_name, buf.data),
1057  errdetail_internal("%s", _(funcdescr[funcnum]))));
1059  info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
1060  info->args = copyObject(stmt->args);
1061  info->funcoids[funcnum] = funcoid;
1062  info_list = lappend(info_list, info);
1063  MemoryContextSwitchTo(oldContext);
1064  }
1065  else if (info->funcoids[0] == InvalidOid ||
1066  info->funcoids[1] == InvalidOid ||
1067  info->funcoids[2] == InvalidOid)
1068  {
1069  /* Second trigger of set */
1070  ereport(NOTICE,
1071  (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
1072  constr_name, buf.data),
1073  errdetail_internal("%s", _(funcdescr[funcnum]))));
1074  }
1075  else
1076  {
1077  /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
1080  Constraint *fkcon = makeNode(Constraint);
1081 
1082  ereport(NOTICE,
1083  (errmsg("converting trigger group into constraint \"%s\" %s",
1084  constr_name, buf.data),
1085  errdetail_internal("%s", _(funcdescr[funcnum]))));
1086  fkcon->contype = CONSTR_FOREIGN;
1087  fkcon->location = -1;
1088  if (funcnum == 2)
1089  {
1090  /* This trigger is on the FK table */
1091  atstmt->relation = stmt->relation;
1092  if (stmt->constrrel)
1093  fkcon->pktable = stmt->constrrel;
1094  else
1095  {
1096  /* Work around ancient pg_dump bug that omitted constrrel */
1097  fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
1098  }
1099  }
1100  else
1101  {
1102  /* This trigger is on the PK table */
1103  fkcon->pktable = stmt->relation;
1104  if (stmt->constrrel)
1105  atstmt->relation = stmt->constrrel;
1106  else
1107  {
1108  /* Work around ancient pg_dump bug that omitted constrrel */
1109  atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
1110  }
1111  }
1112  atstmt->cmds = list_make1(atcmd);
1113  atstmt->relkind = OBJECT_TABLE;
1114  atcmd->subtype = AT_AddConstraint;
1115  atcmd->def = (Node *) fkcon;
1116  if (strcmp(constr_name, "<unnamed>") == 0)
1117  fkcon->conname = NULL;
1118  else
1119  fkcon->conname = constr_name;
1120  fkcon->fk_attrs = fk_attrs;
1121  fkcon->pk_attrs = pk_attrs;
1122  fkcon->fk_matchtype = fk_matchtype;
1123  switch (info->funcoids[0])
1124  {
1125  case F_RI_FKEY_NOACTION_UPD:
1127  break;
1128  case F_RI_FKEY_CASCADE_UPD:
1130  break;
1131  case F_RI_FKEY_RESTRICT_UPD:
1133  break;
1134  case F_RI_FKEY_SETNULL_UPD:
1136  break;
1137  case F_RI_FKEY_SETDEFAULT_UPD:
1139  break;
1140  default:
1141  /* can't get here because of earlier checks */
1142  elog(ERROR, "confused about RI update function");
1143  }
1144  switch (info->funcoids[1])
1145  {
1146  case F_RI_FKEY_NOACTION_DEL:
1148  break;
1149  case F_RI_FKEY_CASCADE_DEL:
1151  break;
1152  case F_RI_FKEY_RESTRICT_DEL:
1154  break;
1155  case F_RI_FKEY_SETNULL_DEL:
1157  break;
1158  case F_RI_FKEY_SETDEFAULT_DEL:
1160  break;
1161  default:
1162  /* can't get here because of earlier checks */
1163  elog(ERROR, "confused about RI delete function");
1164  }
1165  fkcon->deferrable = stmt->deferrable;
1166  fkcon->initdeferred = stmt->initdeferred;
1167  fkcon->skip_validation = false;
1168  fkcon->initially_valid = true;
1169 
1170  /* ... and execute it */
1171  ProcessUtility((Node *) atstmt,
1172  "(generated ALTER TABLE ADD FOREIGN KEY command)",
1174  None_Receiver, NULL);
1175 
1176  /* Remove the matched item from the list */
1177  info_list = list_delete_ptr(info_list, info);
1178  pfree(info);
1179  /* We leak the copied args ... not worth worrying about */
1180  }
1181 }
#define NIL
Definition: pg_list.h:69
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:1928
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:9974
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2797
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:1919
char fk_matchtype
Definition: parsenodes.h:1964
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:1923
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:499
#define strVal(v)
Definition: value.h:54
bool initdeferred
Definition: parsenodes.h:1938
AlterTableType subtype
Definition: parsenodes.h:1647
List * pk_attrs
Definition: parsenodes.h:1963
char * conname
Definition: parsenodes.h:1936
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
DestReceiver * None_Receiver
Definition: dest.c:85
#define lsecond(l)
Definition: pg_list.h:114
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void * copyObject(const void *from)
Definition: copyfuncs.c:4377
#define list_make1(x1)
Definition: pg_list.h:133
RangeVar * constrrel
Definition: parsenodes.h:2220
void pfree(void *pointer)
Definition: mcxt.c:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:1937
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
static char * buf
Definition: pg_test_fsync.c:65
Oid funcoids[3]
Definition: trigger.c:934
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1565
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:1921
List * lappend(List *list, void *datum)
Definition: list.c:128
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:1926
void * palloc0(Size size)
Definition: mcxt.c:920
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:1972
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:547
char fk_del_action
Definition: parsenodes.h:1966
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Definition: value.h:42
List * args
Definition: trigger.c:933
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1563
int i
RangeVar * relation
Definition: parsenodes.h:2204
ConstrType contype
Definition: parsenodes.h:1933
void * arg
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:1920
#define lthird(l)
Definition: pg_list.h:118
#define elog
Definition: elog.h:219
RangeVar * pktable
Definition: parsenodes.h:1961
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:1922
Definition: pg_list.h:45
bool skip_validation
Definition: parsenodes.h:1971
#define _(x)
Definition: elog.c:84
List * fk_attrs
Definition: parsenodes.h:1962
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
char fk_upd_action
Definition: parsenodes.h:1965
void ProcessUtility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:318
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1830 {
1831  TriggerDesc *newdesc;
1832  Trigger *trigger;
1833  int i;
1834 
1835  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1836  return NULL;
1837 
1838  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1839  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1840 
1841  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1842  memcpy(trigger, trigdesc->triggers,
1843  trigdesc->numtriggers * sizeof(Trigger));
1844  newdesc->triggers = trigger;
1845 
1846  for (i = 0; i < trigdesc->numtriggers; i++)
1847  {
1848  trigger->tgname = pstrdup(trigger->tgname);
1849  if (trigger->tgnattr > 0)
1850  {
1851  int16 *newattr;
1852 
1853  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1854  memcpy(newattr, trigger->tgattr,
1855  trigger->tgnattr * sizeof(int16));
1856  trigger->tgattr = newattr;
1857  }
1858  if (trigger->tgnargs > 0)
1859  {
1860  char **newargs;
1861  int16 j;
1862 
1863  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1864  for (j = 0; j < trigger->tgnargs; j++)
1865  newargs[j] = pstrdup(trigger->tgargs[j]);
1866  trigger->tgargs = newargs;
1867  }
1868  if (trigger->tgqual)
1869  trigger->tgqual = pstrdup(trigger->tgqual);
1870  if (trigger->tgoldtable)
1871  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1872  if (trigger->tgnewtable)
1873  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1874  trigger++;
1875  }
1876 
1877  return newdesc;
1878 }
signed short int16
Definition: c.h:252
char * pstrdup(const char *in)
Definition: mcxt.c:1165
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:226
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:891
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(), CatalogUpdateIndexes(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CONSTRAINT_TRIGGER, ConstraintRelationId, CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject(), CreateConstraintEntry(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DirectFunctionCall1, elog, ereport, errcode(), 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, IsA, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, lfirst, list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), name, TriggerTransition::name, NAMEDATALEN, namein(), NameListToString(), namestrcmp(), Natts_pg_trigger, NIL, nodeToString(), NoLock, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPAQUEOID, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, ProcedureRelationId, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, simple_heap_insert(), simple_heap_update(), 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 
346 
347  if (!(tt->isTable))
348  ereport(ERROR,
349  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
350  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
351  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
352 
353  /*
354  * Because of the above test, we omit further ROW-related testing
355  * below. If we later allow naming OLD and NEW ROW variables,
356  * adjustments will be needed below.
357  */
358 
359  if (stmt->timing != TRIGGER_TYPE_AFTER)
360  ereport(ERROR,
361  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
362  errmsg("transition table name can only be specified for an AFTER trigger")));
363 
364  if (tt->isNew)
365  {
366  if (!(TRIGGER_FOR_INSERT(tgtype) ||
367  TRIGGER_FOR_UPDATE(tgtype)))
368  ereport(ERROR,
369  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
370  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
371 
372  if (newtablename != NULL)
373  ereport(ERROR,
374  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
375  errmsg("NEW TABLE cannot be specified multiple times")));
376 
377  newtablename = tt->name;
378  }
379  else
380  {
381  if (!(TRIGGER_FOR_DELETE(tgtype) ||
382  TRIGGER_FOR_UPDATE(tgtype)))
383  ereport(ERROR,
384  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
385  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
386 
387  if (oldtablename != NULL)
388  ereport(ERROR,
389  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
390  errmsg("OLD TABLE cannot be specified multiple times")));
391 
392  oldtablename = tt->name;
393  }
394  }
395 
396  if (newtablename != NULL && oldtablename != NULL &&
397  strcmp(newtablename, oldtablename) == 0)
398  ereport(ERROR,
399  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
400  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
401  }
402 
403  /*
404  * Parse the WHEN clause, if any
405  */
406  if (stmt->whenClause)
407  {
408  ParseState *pstate;
409  RangeTblEntry *rte;
410  List *varList;
411  ListCell *lc;
412 
413  /* Set up a pstate to parse with */
414  pstate = make_parsestate(NULL);
415  pstate->p_sourcetext = queryString;
416 
417  /*
418  * Set up RTEs for OLD and NEW references.
419  *
420  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
421  */
422  rte = addRangeTableEntryForRelation(pstate, rel,
423  makeAlias("old", NIL),
424  false, false);
425  addRTEtoQuery(pstate, rte, false, true, true);
426  rte = addRangeTableEntryForRelation(pstate, rel,
427  makeAlias("new", NIL),
428  false, false);
429  addRTEtoQuery(pstate, rte, false, true, true);
430 
431  /* Transform expression. Copy to be sure we don't modify original */
432  whenClause = transformWhereClause(pstate,
433  copyObject(stmt->whenClause),
435  "WHEN");
436  /* we have to fix its collations too */
437  assign_expr_collations(pstate, whenClause);
438 
439  /*
440  * Check for disallowed references to OLD/NEW.
441  *
442  * NB: pull_var_clause is okay here only because we don't allow
443  * subselects in WHEN clauses; it would fail to examine the contents
444  * of subselects.
445  */
446  varList = pull_var_clause(whenClause, 0);
447  foreach(lc, varList)
448  {
449  Var *var = (Var *) lfirst(lc);
450 
451  switch (var->varno)
452  {
453  case PRS2_OLD_VARNO:
454  if (!TRIGGER_FOR_ROW(tgtype))
455  ereport(ERROR,
456  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
457  errmsg("statement trigger's WHEN condition cannot reference column values"),
458  parser_errposition(pstate, var->location)));
459  if (TRIGGER_FOR_INSERT(tgtype))
460  ereport(ERROR,
461  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
462  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
463  parser_errposition(pstate, var->location)));
464  /* system columns are okay here */
465  break;
466  case PRS2_NEW_VARNO:
467  if (!TRIGGER_FOR_ROW(tgtype))
468  ereport(ERROR,
469  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
470  errmsg("statement trigger's WHEN condition cannot reference column values"),
471  parser_errposition(pstate, var->location)));
472  if (TRIGGER_FOR_DELETE(tgtype))
473  ereport(ERROR,
474  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
475  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
476  parser_errposition(pstate, var->location)));
477  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
478  ereport(ERROR,
479  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
480  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
481  parser_errposition(pstate, var->location)));
482  break;
483  default:
484  /* can't happen without add_missing_from, so just elog */
485  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
486  break;
487  }
488  }
489 
490  /* we'll need the rtable for recordDependencyOnExpr */
491  whenRtable = pstate->p_rtable;
492 
493  qual = nodeToString(whenClause);
494 
495  free_parsestate(pstate);
496  }
497  else
498  {
499  whenClause = NULL;
500  whenRtable = NIL;
501  qual = NULL;
502  }
503 
504  /*
505  * Find and validate the trigger function.
506  */
507  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
508  if (!isInternal)
509  {
510  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
511  if (aclresult != ACLCHECK_OK)
512  aclcheck_error(aclresult, ACL_KIND_PROC,
513  NameListToString(stmt->funcname));
514  }
515  funcrettype = get_func_rettype(funcoid);
516  if (funcrettype != TRIGGEROID)
517  {
518  /*
519  * We allow OPAQUE just so we can load old dump files. When we see a
520  * trigger function declared OPAQUE, change it to TRIGGER.
521  */
522  if (funcrettype == OPAQUEOID)
523  {
525  (errmsg("changing return type of function %s from \"opaque\" to \"trigger\"",
526  NameListToString(stmt->funcname))));
528  }
529  else
530  ereport(ERROR,
531  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
532  errmsg("function %s must return type %s",
533  NameListToString(stmt->funcname), "trigger")));
534  }
535 
536  /*
537  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
538  * references one of the built-in RI_FKey trigger functions, assume it is
539  * from a dump of a pre-7.3 foreign key constraint, and take steps to
540  * convert this legacy representation into a regular foreign key
541  * constraint. Ugly, but necessary for loading old dump files.
542  */
543  if (stmt->isconstraint && !isInternal &&
544  list_length(stmt->args) >= 6 &&
545  (list_length(stmt->args) % 2) == 0 &&
547  {
548  /* Keep lock on target rel until end of xact */
549  heap_close(rel, NoLock);
550 
551  ConvertTriggerToFK(stmt, funcoid);
552 
553  return InvalidObjectAddress;
554  }
555 
556  /*
557  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
558  * corresponding pg_constraint entry.
559  */
560  if (stmt->isconstraint && !OidIsValid(constraintOid))
561  {
562  /* Internal callers should have made their own constraints */
563  Assert(!isInternal);
564  constraintOid = CreateConstraintEntry(stmt->trigname,
567  stmt->deferrable,
568  stmt->initdeferred,
569  true,
570  RelationGetRelid(rel),
571  NULL, /* no conkey */
572  0,
573  InvalidOid, /* no domain */
574  InvalidOid, /* no index */
575  InvalidOid, /* no foreign key */
576  NULL,
577  NULL,
578  NULL,
579  NULL,
580  0,
581  ' ',
582  ' ',
583  ' ',
584  NULL, /* no exclusion */
585  NULL, /* no check constraint */
586  NULL,
587  NULL,
588  true, /* islocal */
589  0, /* inhcount */
590  true, /* isnoinherit */
591  isInternal); /* is_internal */
592  }
593 
594  /*
595  * Generate the trigger's OID now, so that we can use it in the name if
596  * needed.
597  */
599 
600  trigoid = GetNewOid(tgrel);
601 
602  /*
603  * If trigger is internally generated, modify the provided trigger name to
604  * ensure uniqueness by appending the trigger OID. (Callers will usually
605  * supply a simple constant trigger name in these cases.)
606  */
607  if (isInternal)
608  {
609  snprintf(internaltrigname, sizeof(internaltrigname),
610  "%s_%u", stmt->trigname, trigoid);
611  trigname = internaltrigname;
612  }
613  else
614  {
615  /* user-defined trigger; use the specified trigger name as-is */
616  trigname = stmt->trigname;
617  }
618 
619  /*
620  * Scan pg_trigger for existing triggers on relation. We do this only to
621  * give a nice error message if there's already a trigger of the same
622  * name. (The unique index on tgrelid/tgname would complain anyway.) We
623  * can skip this for internally generated triggers, since the name
624  * modification above should be sufficient.
625  *
626  * NOTE that this is cool only because we have ShareRowExclusiveLock on
627  * the relation, so the trigger set won't be changing underneath us.
628  */
629  if (!isInternal)
630  {
631  ScanKeyInit(&key,
633  BTEqualStrategyNumber, F_OIDEQ,
635  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
636  NULL, 1, &key);
637  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
638  {
639  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
640 
641  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
642  ereport(ERROR,
644  errmsg("trigger \"%s\" for relation \"%s\" already exists",
645  trigname, RelationGetRelationName(rel))));
646  }
647  systable_endscan(tgscan);
648  }
649 
650  /*
651  * Build the new pg_trigger tuple.
652  */
653  memset(nulls, false, sizeof(nulls));
654 
657  CStringGetDatum(trigname));
658  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
659  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
661  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
662  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
663  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
664  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
667 
668  if (stmt->args)
669  {
670  ListCell *le;
671  char *args;
672  int16 nargs = list_length(stmt->args);
673  int len = 0;
674 
675  foreach(le, stmt->args)
676  {
677  char *ar = strVal(lfirst(le));
678 
679  len += strlen(ar) + 4;
680  for (; *ar; ar++)
681  {
682  if (*ar == '\\')
683  len++;
684  }
685  }
686  args = (char *) palloc(len + 1);
687  args[0] = '\0';
688  foreach(le, stmt->args)
689  {
690  char *s = strVal(lfirst(le));
691  char *d = args + strlen(args);
692 
693  while (*s)
694  {
695  if (*s == '\\')
696  *d++ = '\\';
697  *d++ = *s++;
698  }
699  strcpy(d, "\\000");
700  }
701  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
703  CStringGetDatum(args));
704  }
705  else
706  {
707  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
709  CStringGetDatum(""));
710  }
711 
712  /* build column number array if it's a column-specific trigger */
713  ncolumns = list_length(stmt->columns);
714  if (ncolumns == 0)
715  columns = NULL;
716  else
717  {
718  ListCell *cell;
719  int i = 0;
720 
721  columns = (int16 *) palloc(ncolumns * sizeof(int16));
722  foreach(cell, stmt->columns)
723  {
724  char *name = strVal(lfirst(cell));
725  int16 attnum;
726  int j;
727 
728  /* Lookup column name. System columns are not allowed */
729  attnum = attnameAttNum(rel, name, false);
730  if (attnum == InvalidAttrNumber)
731  ereport(ERROR,
732  (errcode(ERRCODE_UNDEFINED_COLUMN),
733  errmsg("column \"%s\" of relation \"%s\" does not exist",
734  name, RelationGetRelationName(rel))));
735 
736  /* Check for duplicates */
737  for (j = i - 1; j >= 0; j--)
738  {
739  if (columns[j] == attnum)
740  ereport(ERROR,
741  (errcode(ERRCODE_DUPLICATE_COLUMN),
742  errmsg("column \"%s\" specified more than once",
743  name)));
744  }
745 
746  columns[i++] = attnum;
747  }
748  }
749  tgattr = buildint2vector(columns, ncolumns);
750  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
751 
752  /* set tgqual if trigger has WHEN clause */
753  if (qual)
754  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
755  else
756  nulls[Anum_pg_trigger_tgqual - 1] = true;
757 
758  if (oldtablename)
760  CStringGetDatum(oldtablename));
761  else
762  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
763  if (newtablename)
765  CStringGetDatum(newtablename));
766  else
767  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
768 
769  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
770 
771  /* force tuple to have the desired OID */
772  HeapTupleSetOid(tuple, trigoid);
773 
774  /*
775  * Insert tuple into pg_trigger.
776  */
777  simple_heap_insert(tgrel, tuple);
778 
779  CatalogUpdateIndexes(tgrel, tuple);
780 
781  heap_freetuple(tuple);
783 
787  if (oldtablename)
789  if (newtablename)
791 
792  /*
793  * Update relation's pg_class entry. Crucial side-effect: other backends
794  * (and this one too!) are sent SI message to make them rebuild relcache
795  * entries.
796  */
798  tuple = SearchSysCacheCopy1(RELOID,
800  if (!HeapTupleIsValid(tuple))
801  elog(ERROR, "cache lookup failed for relation %u",
802  RelationGetRelid(rel));
803 
804  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
805 
806  simple_heap_update(pgrel, &tuple->t_self, tuple);
807 
808  CatalogUpdateIndexes(pgrel, tuple);
809 
810  heap_freetuple(tuple);
812 
813  /*
814  * We used to try to update the rel's relcache entry here, but that's
815  * fairly pointless since it will happen as a byproduct of the upcoming
816  * CommandCounterIncrement...
817  */
818 
819  /*
820  * Record dependencies for trigger. Always place a normal dependency on
821  * the function.
822  */
823  myself.classId = TriggerRelationId;
824  myself.objectId = trigoid;
825  myself.objectSubId = 0;
826 
827  referenced.classId = ProcedureRelationId;
828  referenced.objectId = funcoid;
829  referenced.objectSubId = 0;
830  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
831 
832  if (isInternal && OidIsValid(constraintOid))
833  {
834  /*
835  * Internally-generated trigger for a constraint, so make it an
836  * internal dependency of the constraint. We can skip depending on
837  * the relation(s), as there'll be an indirect dependency via the
838  * constraint.
839  */
840  referenced.classId = ConstraintRelationId;
841  referenced.objectId = constraintOid;
842  referenced.objectSubId = 0;
843  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
844  }
845  else
846  {
847  /*
848  * User CREATE TRIGGER, so place dependencies. We make trigger be
849  * auto-dropped if its relation is dropped or if the FK relation is
850  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
851  */
852  referenced.classId = RelationRelationId;
853  referenced.objectId = RelationGetRelid(rel);
854  referenced.objectSubId = 0;
855  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
856  if (OidIsValid(constrrelid))
857  {
858  referenced.classId = RelationRelationId;
859  referenced.objectId = constrrelid;
860  referenced.objectSubId = 0;
861  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
862  }
863  /* Not possible to have an index dependency in this case */
864  Assert(!OidIsValid(indexOid));
865 
866  /*
867  * If it's a user-specified constraint trigger, make the constraint
868  * internally dependent on the trigger instead of vice versa.
869  */
870  if (OidIsValid(constraintOid))
871  {
872  referenced.classId = ConstraintRelationId;
873  referenced.objectId = constraintOid;
874  referenced.objectSubId = 0;
875  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
876  }
877  }
878 
879  /* If column-specific trigger, add normal dependencies on columns */
880  if (columns != NULL)
881  {
882  int i;
883 
884  referenced.classId = RelationRelationId;
885  referenced.objectId = RelationGetRelid(rel);
886  for (i = 0; i < ncolumns; i++)
887  {
888  referenced.objectSubId = columns[i];
889  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
890  }
891  }
892 
893  /*
894  * If it has a WHEN clause, add dependencies on objects mentioned in the
895  * expression (eg, functions, as well as any columns used).
896  */
897  if (whenClause != NULL)
898  recordDependencyOnExpr(&myself, whenClause, whenRtable,
900 
901  /* Post creation hook for new trigger */
903  isInternal);
904 
905  /* Keep lock on target rel until end of xact */
906  heap_close(rel, NoLock);
907 
908  return myself;
909 }
signed short int16
Definition: c.h:252
#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
#define IsA(nodeptr, _type_)
Definition: nodes.h:550
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3704
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
int errhint(const char *fmt,...)
Definition: elog.c:987
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool IsSystemRelation(Relation relation)
Definition: catalog.c:61
Oid GetUserId(void)
Definition: miscinit.c:282
#define PointerGetDatum(X)
Definition: postgres.h:564
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:87
#define ProcedureRelationId
Definition: pg_proc.h:33
Node * whenClause
Definition: parsenodes.h:2213
#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:459
#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:499
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
int namestrcmp(Name name, const char *str)
Definition: name.c:248
#define TRIGGER_FOR_UPDATE(type)
Definition: pg_trigger.h:136
AttrNumber varattno
Definition: primnodes.h:153
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
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:555
Form_pg_class rd_rel
Definition: rel.h:112
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:148
#define Anum_pg_trigger_tgisinternal
Definition: pg_trigger.h:84
#define OidIsValid(objectId)
Definition: c.h:530
#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:322
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1427
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4377
#define TriggerRelidNameIndexId
Definition: indexing.h:233
#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:2220
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define TRIGGER_FOR_ROW(type)
Definition: pg_trigger.h:130
void pfree(void *pointer)
Definition: mcxt.c:992
#define OPAQUEOID
Definition: pg_type.h:688
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
#define TRIGGEROID
Definition: pg_type.h:680
ItemPointerData t_self
Definition: htup.h:65
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:256
#define ACL_TRIGGER
Definition: parsenodes.h:69
int location
Definition: primnodes.h:163
#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:3396
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define CStringGetDatum(X)
Definition: postgres.h:586
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1311
#define RelationGetRelationName(relation)
Definition: rel.h:428
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:166
const char * p_sourcetext
Definition: parse_node.h:135
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:939
List * transitionRels
Definition: parsenodes.h:2216
#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:145
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:151
char * NameListToString(List *names)
Definition: namespace.c:2912
#define Anum_pg_trigger_tgnewtable
Definition: pg_trigger.h:95
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Definition: c.h:462
#define Anum_pg_trigger_tgconstrindid
Definition: pg_trigger.h:86
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:374
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2914
#define Anum_pg_trigger_tgenabled
Definition: pg_trigger.h:83
Oid GetNewOid(Relation relation)
Definition: catalog.c:284
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1286
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:113
#define BoolGetDatum(X)
Definition: postgres.h:410
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1314
bool allowSystemTableMods
Definition: globals.c:111
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define lfirst(lc)
Definition: pg_list.h:106
#define Anum_pg_trigger_tgargs
Definition: pg_trigger.h:92
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
Definition: indexing.c:157
#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
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:108
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4477
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:424
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4415
#define DatumGetPointer(X)
Definition: postgres.h:557
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1909
#define Anum_pg_trigger_tgoldtable
Definition: pg_trigger.h:94
static Datum values[MAXATTR]
Definition: bootstrap.c:162
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:151
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:70
#define RELKIND_VIEW
Definition: pg_class.h:164
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4439
int i
RangeVar * relation
Definition: parsenodes.h:2204
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:815
char * nodeToString(const void *obj)
Definition: outfuncs.c:3945
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define CONSTRAINT_TRIGGER
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:74
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RI_TRIGGER_NONE
Definition: trigger.h:211
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:34
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
#define RelationGetRelid(relation)
Definition: rel.h:408
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:146
#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:435
List * p_rtable
Definition: parse_node.h:136
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

Definition at line 1496 of file trigger.c.

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

Referenced by ATExecEnableDisableTrigger().

1498 {
1499  Relation tgrel;
1500  int nkeys;
1501  ScanKeyData keys[2];
1502  SysScanDesc tgscan;
1503  HeapTuple tuple;
1504  bool found;
1505  bool changed;
1506 
1507  /* Scan the relevant entries in pg_triggers */
1509 
1510  ScanKeyInit(&keys[0],
1512  BTEqualStrategyNumber, F_OIDEQ,
1514  if (tgname)
1515  {
1516  ScanKeyInit(&keys[1],
1518  BTEqualStrategyNumber, F_NAMEEQ,
1519  CStringGetDatum(tgname));
1520  nkeys = 2;
1521  }
1522  else
1523  nkeys = 1;
1524 
1525  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1526  NULL, nkeys, keys);
1527 
1528  found = changed = false;
1529 
1530  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1531  {
1532  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1533 
1534  if (oldtrig->tgisinternal)
1535  {
1536  /* system trigger ... ok to process? */
1537  if (skip_system)
1538  continue;
1539  if (!superuser())
1540  ereport(ERROR,
1541  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1542  errmsg("permission denied: \"%s\" is a system trigger",
1543  NameStr(oldtrig->tgname))));
1544  }
1545 
1546  found = true;
1547 
1548  if (oldtrig->tgenabled != fires_when)
1549  {
1550  /* need to change this one ... make a copy to scribble on */
1551  HeapTuple newtup = heap_copytuple(tuple);
1552  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1553 
1554  newtrig->tgenabled = fires_when;
1555 
1556  simple_heap_update(tgrel, &newtup->t_self, newtup);
1557 
1558  /* Keep catalog indexes current */
1559  CatalogUpdateIndexes(tgrel, newtup);
1560 
1561  heap_freetuple(newtup);
1562 
1563  changed = true;
1564  }
1565 
1567  HeapTupleGetOid(tuple), 0);
1568  }
1569 
1570  systable_endscan(tgscan);
1571 
1572  heap_close(tgrel, RowExclusiveLock);
1573 
1574  if (tgname && !found)
1575  ereport(ERROR,
1576  (errcode(ERRCODE_UNDEFINED_OBJECT),
1577  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1578  tgname, RelationGetRelationName(rel))));
1579 
1580  /*
1581  * If we changed anything, broadcast a SI inval message to force each
1582  * backend (including our own!) to rebuild relation's relcache entry.
1583  * Otherwise they will fail to apply the change promptly.
1584  */
1585  if (changed)
1587 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
#define TriggerRelidNameIndexId
Definition: indexing.h:233
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:586
#define RelationGetRelationName(relation)
Definition: rel.h:428
#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:1286
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
Definition: indexing.c:157
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4477
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1213
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:494
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:408
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

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

2454 {
2455  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2456 
2457  if (trigdesc &&
2458  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2459  {
2460  HeapTuple trigtuple;
2461 
2462  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2463  if (fdw_trigtuple == NULL)
2464  trigtuple = GetTupleForTrigger(estate,
2465  NULL,
2466  relinfo,
2467  tupleid,
2469  NULL);
2470  else
2471  trigtuple = fdw_trigtuple;
2472 
2474  true, trigtuple, NULL, NIL, NULL);
2475  if (trigtuple != fdw_trigtuple)
2476  heap_freetuple(trigtuple);
2477  }
2478 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
bool trig_delete_after_row
Definition: reltrigger.h:66
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5076
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:336
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2873
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

Definition at line 2242 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(), and ExecInsert().

2244 {
2245  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2246 
2247  if (trigdesc &&
2248  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2250  true, NULL, trigtuple, recheckIndexes, NULL);
2251 }
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:5076
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:336
#define NULL
Definition: c.h:226
#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 2711 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 ExecUpdate().

2716 {
2717  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2718 
2719  if (trigdesc && (trigdesc->trig_update_after_row ||
2720  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2721  {
2722  HeapTuple trigtuple;
2723 
2724  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2725  if (fdw_trigtuple == NULL)
2726  trigtuple = GetTupleForTrigger(estate,
2727  NULL,
2728  relinfo,
2729  tupleid,
2731  NULL);
2732  else
2733  trigtuple = fdw_trigtuple;
2734 
2736  true, trigtuple, newtuple, recheckIndexes,
2737  GetUpdatedColumns(relinfo, estate));
2738  if (trigtuple != fdw_trigtuple)
2739  heap_freetuple(trigtuple);
2740  }
2741 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
bool trig_update_new_table
Definition: reltrigger.h:76
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
bool trig_update_old_table
Definition: reltrigger.h:75
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5076
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:336
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:226
#define Assert(condition)
Definition: c.h:667
#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:2873
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2372 of file trigger.c.

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

Referenced by fireASTriggers().

2373 {
2374  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2375 
2376  if (trigdesc && trigdesc->trig_delete_after_statement)
2378  false, NULL, NULL, NIL, NULL);
2379 }
#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:5076
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:336
#define NULL
Definition: c.h:226
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2166 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2167 {
2168  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2169 
2170  if (trigdesc && trigdesc->trig_insert_after_statement)
2172  false, NULL, NULL, NIL, NULL);
2173 }
#define NIL
Definition: pg_list.h:69
bool trig_insert_after_statement
Definition: reltrigger.h:59
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5076
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:336
#define NULL
Definition: c.h:226
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2862 of file trigger.c.

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

Referenced by ExecuteTruncate().

2863 {
2864  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2865