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

Referenced by AfterTriggerSaveEvent().

#define AFTER_TRIGGER_2CTID   0xC0000000

Definition at line 3252 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_DONE   0x10000000
#define AFTER_TRIGGER_FDW_FETCH   0x80000000

Definition at line 3250 of file trigger.c.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define AFTER_TRIGGER_FDW_REUSE   0x00000000

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

Referenced by afterTriggerAddEvent().

#define AFTER_TRIGGER_TUP_BITS   0xC0000000

Definition at line 3253 of file trigger.c.

Referenced by AfterTriggerExecute().

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

Definition at line 3313 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 3324 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:3313
#define SizeofTriggerEvent(evt)
Definition: trigger.c:3287
struct AfterTriggerEventData * AfterTriggerEvent
Definition: trigger.c:3265

Definition at line 3326 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:3253
#define AFTER_TRIGGER_1CTID
Definition: trigger.c:3251
#define AFTER_TRIGGER_2CTID
Definition: trigger.c:3252

Definition at line 3287 of file trigger.c.

Referenced by afterTriggerAddEvent().

Typedef Documentation

Definition at line 3265 of file trigger.c.

Definition at line 3255 of file trigger.c.

Definition at line 3242 of file trigger.c.

Function Documentation

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

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

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

Definition at line 4162 of file trigger.c.

References AfterTriggersData::query_depth.

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

4163 {
4164  /* Increase the query stack depth */
4166 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
void AfterTriggerBeginSubXact ( void  )

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

4387 {
4388  int my_level = GetCurrentTransactionNestLevel();
4389 
4390  /*
4391  * Allocate more space in the stacks if needed. (Note: because the
4392  * minimum nest level of a subtransaction is 2, we waste the first couple
4393  * entries of each array; not worth the notational effort to avoid it.)
4394  */
4395  while (my_level >= afterTriggers.maxtransdepth)
4396  {
4397  if (afterTriggers.maxtransdepth == 0)
4398  {
4399  MemoryContext old_cxt;
4400 
4402 
4403 #define DEFTRIG_INITALLOC 8
4408  afterTriggers.depth_stack = (int *)
4409  palloc(DEFTRIG_INITALLOC * sizeof(int));
4411  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4413 
4414  MemoryContextSwitchTo(old_cxt);
4415  }
4416  else
4417  {
4418  /* repalloc will keep the stacks in the same context */
4419  int new_alloc = afterTriggers.maxtransdepth * 2;
4420 
4423  new_alloc * sizeof(SetConstraintState));
4426  new_alloc * sizeof(AfterTriggerEventList));
4427  afterTriggers.depth_stack = (int *)
4429  new_alloc * sizeof(int));
4432  new_alloc * sizeof(CommandId));
4433  afterTriggers.maxtransdepth = new_alloc;
4434  }
4435  }
4436 
4437  /*
4438  * Push the current information into the stack. The SET CONSTRAINTS state
4439  * is not saved until/unless changed. Likewise, we don't make a
4440  * per-subtransaction event context until needed.
4441  */
4442  afterTriggers.state_stack[my_level] = NULL;
4446 }
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:3412
SetConstraintState * state_stack
Definition: trigger.c:3409
CommandId firing_counter
Definition: trigger.c:3396
AfterTriggerEventList * events_stack
Definition: trigger.c:3410
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:3398
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
void AfterTriggerBeginXact ( void  )

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

4125 {
4126  /*
4127  * Initialize after-trigger state structure to empty
4128  */
4129  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4131 
4132  /*
4133  * Verify that there is no leftover state remaining. If these assertions
4134  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4135  * up properly.
4136  */
4150 }
uint32 CommandId
Definition: c.h:407
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3402
CommandId * firing_stack
Definition: trigger.c:3412
SetConstraintState * state_stack
Definition: trigger.c:3409
SetConstraintState state
Definition: trigger.c:3397
CommandId firing_counter
Definition: trigger.c:3396
AfterTriggerEventList * events_stack
Definition: trigger.c:3410
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
AfterTriggerEventChunk * head
Definition: trigger.c:3318
MemoryContext event_cxt
Definition: trigger.c:3405
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3401
AfterTriggerEventList events
Definition: trigger.c:3398
AfterTriggerEventList * query_stack
Definition: trigger.c:3400
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3403
static bool afterTriggerCheckState ( AfterTriggerShared  evtshared)
static

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

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

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

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

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

4455 {
4456  int my_level = GetCurrentTransactionNestLevel();
4458  AfterTriggerEvent event;
4459  AfterTriggerEventChunk *chunk;
4460  CommandId subxact_firing_id;
4461 
4462  /*
4463  * Pop the prior state if needed.
4464  */
4465  if (isCommit)
4466  {
4467  Assert(my_level < afterTriggers.maxtransdepth);
4468  /* If we saved a prior state, we don't need it anymore */
4469  state = afterTriggers.state_stack[my_level];
4470  if (state != NULL)
4471  pfree(state);
4472  /* this avoids double pfree if error later: */
4473  afterTriggers.state_stack[my_level] = NULL;
4475  afterTriggers.depth_stack[my_level]);
4476  }
4477  else
4478  {
4479  /*
4480  * Aborting. It is possible subxact start failed before calling
4481  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4482  * stack levels that aren't there.
4483  */
4484  if (my_level >= afterTriggers.maxtransdepth)
4485  return;
4486 
4487  /*
4488  * Release any event lists from queries being aborted, and restore
4489  * query_depth to its pre-subxact value. This assumes that a
4490  * subtransaction will not add events to query levels started in a
4491  * earlier transaction state.
4492  */
4494  {
4496  {
4497  Tuplestorestate *ts;
4498 
4500  if (ts)
4501  {
4502  tuplestore_end(ts);
4504  }
4506  if (ts)
4507  {
4508  tuplestore_end(ts);
4510  }
4512  if (ts)
4513  {
4514  tuplestore_end(ts);
4516  }
4517 
4519  }
4520 
4522  }
4524  afterTriggers.depth_stack[my_level]);
4525 
4526  /*
4527  * Restore the global deferred-event list to its former length,
4528  * discarding any events queued by the subxact.
4529  */
4531  &afterTriggers.events_stack[my_level]);
4532 
4533  /*
4534  * Restore the trigger state. If the saved state is NULL, then this
4535  * subxact didn't save it, so it doesn't need restoring.
4536  */
4537  state = afterTriggers.state_stack[my_level];
4538  if (state != NULL)
4539  {
4541  afterTriggers.state = state;
4542  }
4543  /* this avoids double pfree if error later: */
4544  afterTriggers.state_stack[my_level] = NULL;
4545 
4546  /*
4547  * Scan for any remaining deferred events that were marked DONE or IN
4548  * PROGRESS by this subxact or a child, and un-mark them. We can
4549  * recognize such events because they have a firing ID greater than or
4550  * equal to the firing_counter value we saved at subtransaction start.
4551  * (This essentially assumes that the current subxact includes all
4552  * subxacts started after it.)
4553  */
4554  subxact_firing_id = afterTriggers.firing_stack[my_level];
4556  {
4557  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4558 
4559  if (event->ate_flags &
4561  {
4562  if (evtshared->ats_firing_id >= subxact_firing_id)
4563  event->ate_flags &=
4565  }
4566  }
4567  }
4568 }
uint32 CommandId
Definition: c.h:407
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3402
TriggerFlags ate_flags
Definition: trigger.c:3269
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3246
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3331
CommandId * firing_stack
Definition: trigger.c:3412
#define GetTriggerSharedData(evt)
Definition: trigger.c:3294
void pfree(void *pointer)
Definition: mcxt.c:992
SetConstraintState * state_stack
Definition: trigger.c:3409
SetConstraintState state
Definition: trigger.c:3397
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3642
AfterTriggerEventList * events_stack
Definition: trigger.c:3410
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:3665
CommandId ats_firing_id
Definition: trigger.c:3262
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3247
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3401
AfterTriggerEventList events
Definition: trigger.c:3398
AfterTriggerEventList * query_stack
Definition: trigger.c:3400
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3403
void AfterTriggerEndXact ( bool  isCommit)

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

4333 {
4334  /*
4335  * Forget the pending-events list.
4336  *
4337  * Since all the info is in TopTransactionContext or children thereof, we
4338  * don't really need to do anything to reclaim memory. However, the
4339  * pending-events list could be large, and so it's useful to discard it as
4340  * soon as possible --- especially if we are aborting because we ran out
4341  * of memory for the list!
4342  */
4344  {
4350  }
4351 
4352  /*
4353  * Forget any subtransaction state as well. Since this can't be very
4354  * large, we let the eventual reset of TopTransactionContext free the
4355  * memory instead of doing it here.
4356  */
4362 
4363 
4364  /*
4365  * Forget the query stack and constraint-related state information. As
4366  * with the subtransaction state information, we don't bother freeing the
4367  * memory here.
4368  */
4375 
4376  /* No more afterTriggers manipulation until next transaction starts. */
4378 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3402
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3319
CommandId * firing_stack
Definition: trigger.c:3412
SetConstraintState * state_stack
Definition: trigger.c:3409
SetConstraintState state
Definition: trigger.c:3397
AfterTriggerEventList * events_stack
Definition: trigger.c:3410
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3318
MemoryContext event_cxt
Definition: trigger.c:3405
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3401
AfterTriggerEventList events
Definition: trigger.c:3398
AfterTriggerEventList * query_stack
Definition: trigger.c:3400
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3403
static void AfterTriggerEnlargeQueryState ( void  )
static

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

4581 {
4582  int init_depth = afterTriggers.maxquerydepth;
4583 
4585 
4586  if (afterTriggers.maxquerydepth == 0)
4587  {
4588  int new_alloc = Max(afterTriggers.query_depth + 1, 8);
4589 
4592  new_alloc * sizeof(AfterTriggerEventList));
4595  new_alloc * sizeof(Tuplestorestate *));
4598  new_alloc * sizeof(Tuplestorestate *));
4601  new_alloc * sizeof(Tuplestorestate *));
4602  afterTriggers.maxquerydepth = new_alloc;
4603  }
4604  else
4605  {
4606  /* repalloc will keep the stack in the same context */
4607  int old_alloc = afterTriggers.maxquerydepth;
4608  int new_alloc = Max(afterTriggers.query_depth + 1,
4609  old_alloc * 2);
4610 
4613  new_alloc * sizeof(AfterTriggerEventList));
4616  new_alloc * sizeof(Tuplestorestate *));
4619  new_alloc * sizeof(Tuplestorestate *));
4622  new_alloc * sizeof(Tuplestorestate *));
4623  /* Clear newly-allocated slots for subsequent lazy initialization. */
4624  memset(afterTriggers.fdw_tuplestores + old_alloc,
4625  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4626  memset(afterTriggers.old_tuplestores + old_alloc,
4627  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4628  memset(afterTriggers.new_tuplestores + old_alloc,
4629  0, (new_alloc - old_alloc) * sizeof(Tuplestorestate *));
4630  afterTriggers.maxquerydepth = new_alloc;
4631  }
4632 
4633  /* Initialize new query lists to empty */
4634  while (init_depth < afterTriggers.maxquerydepth)
4635  {
4636  AfterTriggerEventList *events;
4637 
4638  events = &afterTriggers.query_stack[init_depth];
4639  events->head = NULL;
4640  events->tail = NULL;
4641  events->tailfree = NULL;
4642 
4643  ++init_depth;
4644  }
4645 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3402
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventChunk * tail
Definition: trigger.c:3319
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:3318
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3401
AfterTriggerEventList * query_stack
Definition: trigger.c:3400
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3403
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 3720 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().

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

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

4277 {
4278  AfterTriggerEventList *events;
4279  bool snap_pushed = false;
4280 
4281  /* Must not be inside a query */
4283 
4284  /*
4285  * If there are any triggers to fire, make sure we have set a snapshot for
4286  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4287  * can't assume ActiveSnapshot is valid on entry.)
4288  */
4289  events = &afterTriggers.events;
4290  if (events->head != NULL)
4291  {
4293  snap_pushed = true;
4294  }
4295 
4296  /*
4297  * Run all the remaining triggers. Loop until they are all gone, in case
4298  * some trigger queues more for us to do.
4299  */
4300  while (afterTriggerMarkEvents(events, NULL, false))
4301  {
4302  CommandId firing_id = afterTriggers.firing_counter++;
4303 
4304  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4305  break; /* all fired */
4306  }
4307 
4308  /*
4309  * We don't bother freeing the event list, since it will go away anyway
4310  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4311  */
4312 
4313  if (snap_pushed)
4315 }
uint32 CommandId
Definition: c.h:407
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3979
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:3396
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
AfterTriggerEventChunk * head
Definition: trigger.c:3318
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3907
AfterTriggerEventList events
Definition: trigger.c:3398
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
static void afterTriggerFreeEventList ( AfterTriggerEventList events)
static

Definition at line 3642 of file trigger.c.

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

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

3643 {
3644  AfterTriggerEventChunk *chunk;
3645  AfterTriggerEventChunk *next_chunk;
3646 
3647  for (chunk = events->head; chunk != NULL; chunk = next_chunk)
3648  {
3649  next_chunk = chunk->next;
3650  pfree(chunk);
3651  }
3652  events->head = NULL;
3653  events->tail = NULL;
3654  events->tailfree = NULL;
3655 }
AfterTriggerEventChunk * tail
Definition: trigger.c:3319
struct AfterTriggerEventChunk * next
Definition: trigger.c:3306
void pfree(void *pointer)
Definition: mcxt.c:992
#define NULL
Definition: c.h:226
AfterTriggerEventChunk * head
Definition: trigger.c:3318
static bool afterTriggerInvokeEvents ( AfterTriggerEventList events,
CommandId  firing_id,
EState estate,
bool  delete_ok 
)
static

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

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

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

3910 {
3911  bool found = false;
3912  AfterTriggerEvent event;
3913  AfterTriggerEventChunk *chunk;
3914 
3915  for_each_event_chunk(event, chunk, *events)
3916  {
3917  AfterTriggerShared evtshared = GetTriggerSharedData(event);
3918  bool defer_it = false;
3919 
3920  if (!(event->ate_flags &
3922  {
3923  /*
3924  * This trigger hasn't been called or scheduled yet. Check if we
3925  * should call it now.
3926  */
3927  if (immediate_only && afterTriggerCheckState(evtshared))
3928  {
3929  defer_it = true;
3930  }
3931  else
3932  {
3933  /*
3934  * Mark it as to be fired in this firing cycle.
3935  */
3937  event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
3938  found = true;
3939  }
3940  }
3941 
3942  /*
3943  * If it's deferred, move it to move_list, if requested.
3944  */
3945  if (defer_it && move_list != NULL)
3946  {
3947  /* add it to move_list */
3948  afterTriggerAddEvent(move_list, event, evtshared);
3949  /* mark original copy "done" so we don't do it again */
3950  event->ate_flags |= AFTER_TRIGGER_DONE;
3951  }
3952  }
3953 
3954  return found;
3955 }
TriggerFlags ate_flags
Definition: trigger.c:3269
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3246
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3331
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
Definition: trigger.c:3481
#define GetTriggerSharedData(evt)
Definition: trigger.c:3294
CommandId firing_counter
Definition: trigger.c:3396
#define NULL
Definition: c.h:226
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
Definition: trigger.c:3527
CommandId ats_firing_id
Definition: trigger.c:3262
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3247
static AfterTriggersData afterTriggers
Definition: trigger.c:3416
bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

Definition at line 3665 of file trigger.c.

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

Referenced by AfterTriggerEndSubXact().

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

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

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

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

Definition at line 940 of file trigger.c.

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

Referenced by CreateTrigger().

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

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

1839 {
1840  TriggerDesc *newdesc;
1841  Trigger *trigger;
1842  int i;
1843 
1844  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1845  return NULL;
1846 
1847  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1848  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1849 
1850  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1851  memcpy(trigger, trigdesc->triggers,
1852  trigdesc->numtriggers * sizeof(Trigger));
1853  newdesc->triggers = trigger;
1854 
1855  for (i = 0; i < trigdesc->numtriggers; i++)
1856  {
1857  trigger->tgname = pstrdup(trigger->tgname);
1858  if (trigger->tgnattr > 0)
1859  {
1860  int16 *newattr;
1861 
1862  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1863  memcpy(newattr, trigger->tgattr,
1864  trigger->tgnattr * sizeof(int16));
1865  trigger->tgattr = newattr;
1866  }
1867  if (trigger->tgnargs > 0)
1868  {
1869  char **newargs;
1870  int16 j;
1871 
1872  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1873  for (j = 0; j < trigger->tgnargs; j++)
1874  newargs[j] = pstrdup(trigger->tgargs[j]);
1875  trigger->tgargs = newargs;
1876  }
1877  if (trigger->tgqual)
1878  trigger->tgqual = pstrdup(trigger->tgqual);
1879  if (trigger->tgoldtable)
1880  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1881  if (trigger->tgnewtable)
1882  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1883  trigger++;
1884  }
1885 
1886  return newdesc;
1887 }
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 %s to %s",
526  NameListToString(stmt->funcname),
527  "opaque", "trigger")));
529  }
530  else
531  ereport(ERROR,
532  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
533  errmsg("function %s must return type %s",
534  NameListToString(stmt->funcname), "trigger")));
535  }
536 
537  /*
538  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
539  * references one of the built-in RI_FKey trigger functions, assume it is
540  * from a dump of a pre-7.3 foreign key constraint, and take steps to
541  * convert this legacy representation into a regular foreign key
542  * constraint. Ugly, but necessary for loading old dump files.
543  */
544  if (stmt->isconstraint && !isInternal &&
545  list_length(stmt->args) >= 6 &&
546  (list_length(stmt->args) % 2) == 0 &&
548  {
549  /* Keep lock on target rel until end of xact */
550  heap_close(rel, NoLock);
551 
552  ConvertTriggerToFK(stmt, funcoid);
553 
554  return InvalidObjectAddress;
555  }
556 
557  /*
558  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
559  * corresponding pg_constraint entry.
560  */
561  if (stmt->isconstraint && !OidIsValid(constraintOid))
562  {
563  /* Internal callers should have made their own constraints */
564  Assert(!isInternal);
565  constraintOid = CreateConstraintEntry(stmt->trigname,
568  stmt->deferrable,
569  stmt->initdeferred,
570  true,
571  RelationGetRelid(rel),
572  NULL, /* no conkey */
573  0,
574  InvalidOid, /* no domain */
575  InvalidOid, /* no index */
576  InvalidOid, /* no foreign key */
577  NULL,
578  NULL,
579  NULL,
580  NULL,
581  0,
582  ' ',
583  ' ',
584  ' ',
585  NULL, /* no exclusion */
586  NULL, /* no check constraint */
587  NULL,
588  NULL,
589  true, /* islocal */
590  0, /* inhcount */
591  true, /* isnoinherit */
592  isInternal); /* is_internal */
593  }
594 
595  /*
596  * Generate the trigger's OID now, so that we can use it in the name if
597  * needed.
598  */
600 
601  trigoid = GetNewOid(tgrel);
602 
603  /*
604  * If trigger is internally generated, modify the provided trigger name to
605  * ensure uniqueness by appending the trigger OID. (Callers will usually
606  * supply a simple constant trigger name in these cases.)
607  */
608  if (isInternal)
609  {
610  snprintf(internaltrigname, sizeof(internaltrigname),
611  "%s_%u", stmt->trigname, trigoid);
612  trigname = internaltrigname;
613  }
614  else
615  {
616  /* user-defined trigger; use the specified trigger name as-is */
617  trigname = stmt->trigname;
618  }
619 
620  /*
621  * Scan pg_trigger for existing triggers on relation. We do this only to
622  * give a nice error message if there's already a trigger of the same
623  * name. (The unique index on tgrelid/tgname would complain anyway.) We
624  * can skip this for internally generated triggers, since the name
625  * modification above should be sufficient.
626  *
627  * NOTE that this is cool only because we have ShareRowExclusiveLock on
628  * the relation, so the trigger set won't be changing underneath us.
629  */
630  if (!isInternal)
631  {
632  ScanKeyInit(&key,
634  BTEqualStrategyNumber, F_OIDEQ,
636  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
637  NULL, 1, &key);
638  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
639  {
640  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
641 
642  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
643  ereport(ERROR,
645  errmsg("trigger \"%s\" for relation \"%s\" already exists",
646  trigname, RelationGetRelationName(rel))));
647  }
648  systable_endscan(tgscan);
649  }
650 
651  /*
652  * Build the new pg_trigger tuple.
653  */
654  memset(nulls, false, sizeof(nulls));
655 
658  CStringGetDatum(trigname));
659  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
660  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
662  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
663  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
664  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
665  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
668 
669  if (stmt->args)
670  {
671  ListCell *le;
672  char *args;
673  int16 nargs = list_length(stmt->args);
674  int len = 0;
675 
676  foreach(le, stmt->args)
677  {
678  char *ar = strVal(lfirst(le));
679 
680  len += strlen(ar) + 4;
681  for (; *ar; ar++)
682  {
683  if (*ar == '\\')
684  len++;
685  }
686  }
687  args = (char *) palloc(len + 1);
688  args[0] = '\0';
689  foreach(le, stmt->args)
690  {
691  char *s = strVal(lfirst(le));
692  char *d = args + strlen(args);
693 
694  while (*s)
695  {
696  if (*s == '\\')
697  *d++ = '\\';
698  *d++ = *s++;
699  }
700  strcpy(d, "\\000");
701  }
702  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
704  CStringGetDatum(args));
705  }
706  else
707  {
708  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
710  CStringGetDatum(""));
711  }
712 
713  /* build column number array if it's a column-specific trigger */
714  ncolumns = list_length(stmt->columns);
715  if (ncolumns == 0)
716  columns = NULL;
717  else
718  {
719  ListCell *cell;
720  int i = 0;
721 
722  columns = (int16 *) palloc(ncolumns * sizeof(int16));
723  foreach(cell, stmt->columns)
724  {
725  char *name = strVal(lfirst(cell));
726  int16 attnum;
727  int j;
728 
729  /* Lookup column name. System columns are not allowed */
730  attnum = attnameAttNum(rel, name, false);
731  if (attnum == InvalidAttrNumber)
732  ereport(ERROR,
733  (errcode(ERRCODE_UNDEFINED_COLUMN),
734  errmsg("column \"%s\" of relation \"%s\" does not exist",
735  name, RelationGetRelationName(rel))));
736 
737  /* Check for duplicates */
738  for (j = i - 1; j >= 0; j--)
739  {
740  if (columns[j] == attnum)
741  ereport(ERROR,
742  (errcode(ERRCODE_DUPLICATE_COLUMN),
743  errmsg("column \"%s\" specified more than once",
744  name)));
745  }
746 
747  columns[i++] = attnum;
748  }
749  }
750  tgattr = buildint2vector(columns, ncolumns);
751  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
752 
753  /* set tgqual if trigger has WHEN clause */
754  if (qual)
755  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
756  else
757  nulls[Anum_pg_trigger_tgqual - 1] = true;
758 
759  if (oldtablename)
761  CStringGetDatum(oldtablename));
762  else
763  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
764  if (newtablename)
766  CStringGetDatum(newtablename));
767  else
768  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
769 
770  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
771 
772  /* force tuple to have the desired OID */
773  HeapTupleSetOid(tuple, trigoid);
774 
775  /*
776  * Insert tuple into pg_trigger.
777  */
778  simple_heap_insert(tgrel, tuple);
779 
780  CatalogUpdateIndexes(tgrel, tuple);
781 
782  heap_freetuple(tuple);
784 
788  if (oldtablename)
790  if (newtablename)
792 
793  /*
794  * Update relation's pg_class entry. Crucial side-effect: other backends
795  * (and this one too!) are sent SI message to make them rebuild relcache
796  * entries.
797  */
799  tuple = SearchSysCacheCopy1(RELOID,
801  if (!HeapTupleIsValid(tuple))
802  elog(ERROR, "cache lookup failed for relation %u",
803  RelationGetRelid(rel));
804 
805  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
806 
807  simple_heap_update(pgrel, &tuple->t_self, tuple);
808 
809  CatalogUpdateIndexes(pgrel, tuple);
810 
811  heap_freetuple(tuple);
813 
814  /*
815  * We used to try to update the rel's relcache entry here, but that's
816  * fairly pointless since it will happen as a byproduct of the upcoming
817  * CommandCounterIncrement...
818  */
819 
820  /*
821  * Record dependencies for trigger. Always place a normal dependency on
822  * the function.
823  */
824  myself.classId = TriggerRelationId;
825  myself.objectId = trigoid;
826  myself.objectSubId = 0;
827 
828  referenced.classId = ProcedureRelationId;
829  referenced.objectId = funcoid;
830  referenced.objectSubId = 0;
831  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
832 
833  if (isInternal && OidIsValid(constraintOid))
834  {
835  /*
836  * Internally-generated trigger for a constraint, so make it an
837  * internal dependency of the constraint. We can skip depending on
838  * the relation(s), as there'll be an indirect dependency via the
839  * constraint.
840  */
841  referenced.classId = ConstraintRelationId;
842  referenced.objectId = constraintOid;
843  referenced.objectSubId = 0;
844  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
845  }
846  else
847  {
848  /*
849  * User CREATE TRIGGER, so place dependencies. We make trigger be
850  * auto-dropped if its relation is dropped or if the FK relation is
851  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
852  */
853  referenced.classId = RelationRelationId;
854  referenced.objectId = RelationGetRelid(rel);
855  referenced.objectSubId = 0;
856  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
857  if (OidIsValid(constrrelid))
858  {
859  referenced.classId = RelationRelationId;
860  referenced.objectId = constrrelid;
861  referenced.objectSubId = 0;
862  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
863  }
864  /* Not possible to have an index dependency in this case */
865  Assert(!OidIsValid(indexOid));
866 
867  /*
868  * If it's a user-specified constraint trigger, make the constraint
869  * internally dependent on the trigger instead of vice versa.
870  */
871  if (OidIsValid(constraintOid))
872  {
873  referenced.classId = ConstraintRelationId;
874  referenced.objectId = constraintOid;
875  referenced.objectSubId = 0;
876  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
877  }
878  }
879 
880  /* If column-specific trigger, add normal dependencies on columns */
881  if (columns != NULL)
882  {
883  int i;
884 
885  referenced.classId = RelationRelationId;
886  referenced.objectId = RelationGetRelid(rel);
887  for (i = 0; i < ncolumns; i++)
888  {
889  referenced.objectSubId = columns[i];
890  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
891  }
892  }
893 
894  /*
895  * If it has a WHEN clause, add dependencies on objects mentioned in the
896  * expression (eg, functions, as well as any columns used).
897  */
898  if (whenClause != NULL)
899  recordDependencyOnExpr(&myself, whenClause, whenRtable,
901 
902  /* Post creation hook for new trigger */
904  isInternal);
905 
906  /* Keep lock on target rel until end of xact */
907  heap_close(rel, NoLock);
908 
909  return myself;
910 }
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:554
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:2248
#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:503
#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:146
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:141
#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:4410
#define TriggerRelidNameIndexId
Definition: indexing.h:236
#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:2255
#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:71
int location
Definition: primnodes.h:156
#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:3397
#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:1317
#define RelationGetRelationName(relation)
Definition: rel.h:428
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:166
const char * p_sourcetext
Definition: parse_node.h:164
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:940
List * transitionRels
Definition: parsenodes.h:2251
#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:138
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:144
char * NameListToString(List *names)
Definition: namespace.c:2896
#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:4416
#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:152
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:72
#define RELKIND_VIEW
Definition: pg_class.h:164
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4440
int i
RangeVar * relation
Definition: parsenodes.h:2239
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:103
char * nodeToString(const void *obj)
Definition: outfuncs.c:3980
#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:139
#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:165
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

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

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

2463 {
2464  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2465 
2466  if (trigdesc &&
2467  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2468  {
2469  HeapTuple trigtuple;
2470 
2471  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2472  if (fdw_trigtuple == NULL)
2473  trigtuple = GetTupleForTrigger(estate,
2474  NULL,
2475  relinfo,
2476  tupleid,
2478  NULL);
2479  else
2480  trigtuple = fdw_trigtuple;
2481 
2483  true, trigtuple, NULL, NIL, NULL);
2484  if (trigtuple != fdw_trigtuple)
2485  heap_freetuple(trigtuple);
2486  }
2487 }
#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:5085
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:2882
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

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

2253 {
2254  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2255 
2256  if (trigdesc &&
2257  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2259  true, NULL, trigtuple, recheckIndexes, NULL);
2260 }
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:5085
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 2720 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().

2725 {
2726  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2727 
2728  if (trigdesc && (trigdesc->trig_update_after_row ||
2729  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2730  {
2731  HeapTuple trigtuple;
2732 
2733  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2734  if (fdw_trigtuple == NULL)
2735  trigtuple = GetTupleForTrigger(estate,
2736  NULL,
2737  relinfo,
2738  tupleid,
2740  NULL);
2741  else
2742  trigtuple = fdw_trigtuple;
2743 
2745  true, trigtuple, newtuple, recheckIndexes,
2746  GetUpdatedColumns(relinfo, estate));
2747  if (trigtuple != fdw_trigtuple)
2748  heap_freetuple(trigtuple);
2749  }
2750 }
#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:5085
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:2882
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2381 of file trigger.c.

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

Referenced by fireASTriggers().

2382 {
2383  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2384 
2385  if (trigdesc && trigdesc->trig_delete_after_statement)
2387  false, NULL, NULL, NIL, NULL);
2388 }
#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:5085
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 2175 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().

2176 {
2177  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2178 
2179  if (trigdesc && trigdesc->trig_insert_after_statement)
2181  false, NULL, NULL,