PostgreSQL Source Code  git master
trigger.h File Reference
Include dependency graph for trigger.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TriggerData
 
struct  TransitionCaptureState
 

Macros

#define CALLED_AS_TRIGGER(fcinfo)   ((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
 
#define TRIGGER_EVENT_INSERT   0x00000000
 
#define TRIGGER_EVENT_DELETE   0x00000001
 
#define TRIGGER_EVENT_UPDATE   0x00000002
 
#define TRIGGER_EVENT_TRUNCATE   0x00000003
 
#define TRIGGER_EVENT_OPMASK   0x00000003
 
#define TRIGGER_EVENT_ROW   0x00000004
 
#define TRIGGER_EVENT_BEFORE   0x00000008
 
#define TRIGGER_EVENT_AFTER   0x00000000
 
#define TRIGGER_EVENT_INSTEAD   0x00000010
 
#define TRIGGER_EVENT_TIMINGMASK   0x00000018
 
#define AFTER_TRIGGER_DEFERRABLE   0x00000020
 
#define AFTER_TRIGGER_INITDEFERRED   0x00000040
 
#define TRIGGER_FIRED_BY_INSERT(event)   (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_INSERT)
 
#define TRIGGER_FIRED_BY_DELETE(event)   (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_DELETE)
 
#define TRIGGER_FIRED_BY_UPDATE(event)   (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_UPDATE)
 
#define TRIGGER_FIRED_BY_TRUNCATE(event)   (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_TRUNCATE)
 
#define TRIGGER_FIRED_FOR_ROW(event)   ((event) & TRIGGER_EVENT_ROW)
 
#define TRIGGER_FIRED_FOR_STATEMENT(event)   (!TRIGGER_FIRED_FOR_ROW(event))
 
#define TRIGGER_FIRED_BEFORE(event)   (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_BEFORE)
 
#define TRIGGER_FIRED_AFTER(event)   (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_AFTER)
 
#define TRIGGER_FIRED_INSTEAD(event)   (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_INSTEAD)
 
#define SESSION_REPLICATION_ROLE_ORIGIN   0
 
#define SESSION_REPLICATION_ROLE_REPLICA   1
 
#define SESSION_REPLICATION_ROLE_LOCAL   2
 
#define TRIGGER_FIRES_ON_ORIGIN   'O'
 
#define TRIGGER_FIRES_ALWAYS   'A'
 
#define TRIGGER_FIRES_ON_REPLICA   'R'
 
#define TRIGGER_DISABLED   'D'
 
#define RI_TRIGGER_PK   1 /* is a trigger on the PK relation */
 
#define RI_TRIGGER_FK   2 /* is a trigger on the FK relation */
 
#define RI_TRIGGER_NONE   0 /* is not an RI trigger function */
 

Typedefs

typedef uint32 TriggerEvent
 
typedef struct TriggerData TriggerData
 
typedef struct TransitionCaptureState TransitionCaptureState
 

Functions

ObjectAddress CreateTrigger (CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
 
void RemoveTriggerById (Oid trigOid)
 
Oid get_trigger_oid (Oid relid, const char *name, bool missing_ok)
 
ObjectAddress renametrig (RenameStmt *stmt)
 
void EnableDisableTrigger (Relation rel, const char *tgname, char fires_when, bool skip_system, LOCKMODE lockmode)
 
void RelationBuildTriggers (Relation relation)
 
TriggerDescCopyTriggerDesc (TriggerDesc *trigdesc)
 
const char * FindTriggerIncompatibleWithInheritance (TriggerDesc *trigdesc)
 
TransitionCaptureStateMakeTransitionCaptureState (TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
bool ExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
bool ExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot **epqslot)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
bool ExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
bool ExecIRUpdateTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
 
void ExecBSTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
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)
 
bool RI_FKey_pk_upd_check_required (Trigger *trigger, Relation pk_rel, TupleTableSlot *old_slot, TupleTableSlot *new_slot)
 
bool RI_FKey_fk_upd_check_required (Trigger *trigger, Relation fk_rel, TupleTableSlot *old_slot, TupleTableSlot *new_slot)
 
bool RI_Initial_Check (Trigger *trigger, Relation fk_rel, Relation pk_rel)
 
void RI_PartitionRemove_Check (Trigger *trigger, Relation fk_rel, Relation pk_rel)
 
int RI_FKey_trigger_type (Oid tgfoid)
 

Variables

PGDLLIMPORT int SessionReplicationRole
 

Macro Definition Documentation

◆ AFTER_TRIGGER_DEFERRABLE

#define AFTER_TRIGGER_DEFERRABLE   0x00000020

Definition at line 113 of file trigger.h.

Referenced by afterTriggerCheckState(), AfterTriggerSaveEvent(), and ExecCallTriggerFunc().

◆ AFTER_TRIGGER_INITDEFERRED

#define AFTER_TRIGGER_INITDEFERRED   0x00000040

Definition at line 114 of file trigger.h.

Referenced by afterTriggerCheckState(), AfterTriggerSaveEvent(), and ExecCallTriggerFunc().

◆ CALLED_AS_TRIGGER

◆ RI_TRIGGER_FK

#define RI_TRIGGER_FK   2 /* is a trigger on the FK relation */

Definition at line 271 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

◆ RI_TRIGGER_NONE

#define RI_TRIGGER_NONE   0 /* is not an RI trigger function */

Definition at line 272 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), CreateTrigger(), and RI_FKey_trigger_type().

◆ RI_TRIGGER_PK

#define RI_TRIGGER_PK   1 /* is a trigger on the PK relation */

Definition at line 270 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

◆ SESSION_REPLICATION_ROLE_LOCAL

#define SESSION_REPLICATION_ROLE_LOCAL   2

Definition at line 148 of file trigger.h.

◆ SESSION_REPLICATION_ROLE_ORIGIN

#define SESSION_REPLICATION_ROLE_ORIGIN   0

Definition at line 146 of file trigger.h.

◆ SESSION_REPLICATION_ROLE_REPLICA

#define SESSION_REPLICATION_ROLE_REPLICA   1

Definition at line 147 of file trigger.h.

Referenced by filter_event_trigger(), matchLocks(), and TriggerEnabled().

◆ TRIGGER_DISABLED

#define TRIGGER_DISABLED   'D'

Definition at line 158 of file trigger.h.

Referenced by ATExecCmd(), BuildEventTriggerCache(), and TriggerEnabled().

◆ TRIGGER_EVENT_AFTER

#define TRIGGER_EVENT_AFTER   0x00000000

Definition at line 107 of file trigger.h.

◆ TRIGGER_EVENT_BEFORE

◆ TRIGGER_EVENT_DELETE

#define TRIGGER_EVENT_DELETE   0x00000001

◆ TRIGGER_EVENT_INSERT

◆ TRIGGER_EVENT_INSTEAD

#define TRIGGER_EVENT_INSTEAD   0x00000010

Definition at line 108 of file trigger.h.

Referenced by ExecIRDeleteTriggers(), ExecIRInsertTriggers(), and ExecIRUpdateTriggers().

◆ TRIGGER_EVENT_OPMASK

#define TRIGGER_EVENT_OPMASK   0x00000003

◆ TRIGGER_EVENT_ROW

◆ TRIGGER_EVENT_TIMINGMASK

#define TRIGGER_EVENT_TIMINGMASK   0x00000018

Definition at line 109 of file trigger.h.

◆ TRIGGER_EVENT_TRUNCATE

#define TRIGGER_EVENT_TRUNCATE   0x00000003

◆ TRIGGER_EVENT_UPDATE

◆ TRIGGER_FIRED_AFTER

◆ TRIGGER_FIRED_BEFORE

◆ TRIGGER_FIRED_BY_DELETE

◆ TRIGGER_FIRED_BY_INSERT

◆ TRIGGER_FIRED_BY_TRUNCATE

#define TRIGGER_FIRED_BY_TRUNCATE (   event)    (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_TRUNCATE)

◆ TRIGGER_FIRED_BY_UPDATE

◆ TRIGGER_FIRED_FOR_ROW

◆ TRIGGER_FIRED_FOR_STATEMENT

#define TRIGGER_FIRED_FOR_STATEMENT (   event)    (!TRIGGER_FIRED_FOR_ROW(event))

◆ TRIGGER_FIRED_INSTEAD

#define TRIGGER_FIRED_INSTEAD (   event)    (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_INSTEAD)

◆ TRIGGER_FIRES_ALWAYS

#define TRIGGER_FIRES_ALWAYS   'A'

Definition at line 156 of file trigger.h.

Referenced by ATExecCmd().

◆ TRIGGER_FIRES_ON_ORIGIN

◆ TRIGGER_FIRES_ON_REPLICA

#define TRIGGER_FIRES_ON_REPLICA   'R'

Definition at line 157 of file trigger.h.

Referenced by ATExecCmd(), filter_event_trigger(), and TriggerEnabled().

Typedef Documentation

◆ TransitionCaptureState

◆ TriggerData

typedef struct TriggerData TriggerData

◆ TriggerEvent

Definition at line 28 of file trigger.h.

Function Documentation

◆ AfterTriggerBeginQuery()

void AfterTriggerBeginQuery ( void  )

Definition at line 4782 of file trigger.c.

References AfterTriggersData::query_depth.

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

4783 {
4784  /* Increase the query stack depth */
4786 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerBeginSubXact()

void AfterTriggerBeginSubXact ( void  )

Definition at line 5050 of file trigger.c.

References AfterTriggersData::events, AfterTriggersTransData::events, AfterTriggersData::firing_counter, AfterTriggersTransData::firing_counter, GetCurrentTransactionNestLevel(), AfterTriggersData::maxtransdepth, MemoryContextAlloc(), AfterTriggersData::query_depth, AfterTriggersTransData::query_depth, repalloc(), AfterTriggersTransData::state, TopTransactionContext, and AfterTriggersData::trans_stack.

Referenced by StartSubTransaction().

5051 {
5052  int my_level = GetCurrentTransactionNestLevel();
5053 
5054  /*
5055  * Allocate more space in the trans_stack if needed. (Note: because the
5056  * minimum nest level of a subtransaction is 2, we waste the first couple
5057  * entries of the array; not worth the notational effort to avoid it.)
5058  */
5059  while (my_level >= afterTriggers.maxtransdepth)
5060  {
5061  if (afterTriggers.maxtransdepth == 0)
5062  {
5063  /* Arbitrarily initialize for max of 8 subtransaction levels */
5066  8 * sizeof(AfterTriggersTransData));
5068  }
5069  else
5070  {
5071  /* repalloc will keep the stack in the same context */
5072  int new_alloc = afterTriggers.maxtransdepth * 2;
5073 
5076  new_alloc * sizeof(AfterTriggersTransData));
5077  afterTriggers.maxtransdepth = new_alloc;
5078  }
5079  }
5080 
5081  /*
5082  * Push the current information into the stack. The SET CONSTRAINTS state
5083  * is not saved until/unless changed. Likewise, we don't make a
5084  * per-subtransaction event context until needed.
5085  */
5086  afterTriggers.trans_stack[my_level].state = NULL;
5090 }
AfterTriggersTransData * trans_stack
Definition: trigger.c:3807
MemoryContext TopTransactionContext
Definition: mcxt.c:49
AfterTriggerEventList events
Definition: trigger.c:3822
CommandId firing_counter
Definition: trigger.c:3824
CommandId firing_counter
Definition: trigger.c:3796
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
AfterTriggerEventList events
Definition: trigger.c:3798
static AfterTriggersData afterTriggers
Definition: trigger.c:3841
SetConstraintState state
Definition: trigger.c:3821

◆ AfterTriggerBeginXact()

void AfterTriggerBeginXact ( void  )

Definition at line 4750 of file trigger.c.

References Assert, AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggersData::firing_counter, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, and AfterTriggersData::trans_stack.

Referenced by StartTransaction().

4751 {
4752  /*
4753  * Initialize after-trigger state structure to empty
4754  */
4755  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4757 
4758  /*
4759  * Verify that there is no leftover state remaining. If these assertions
4760  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4761  * up properly.
4762  */
4763  Assert(afterTriggers.state == NULL);
4764  Assert(afterTriggers.query_stack == NULL);
4766  Assert(afterTriggers.event_cxt == NULL);
4767  Assert(afterTriggers.events.head == NULL);
4768  Assert(afterTriggers.trans_stack == NULL);
4770 }
uint32 CommandId
Definition: c.h:522
AfterTriggersTransData * trans_stack
Definition: trigger.c:3807
AfterTriggersQueryData * query_stack
Definition: trigger.c:3802
SetConstraintState state
Definition: trigger.c:3797
CommandId firing_counter
Definition: trigger.c:3796
#define Assert(condition)
Definition: c.h:733
AfterTriggerEventChunk * head
Definition: trigger.c:3690
MemoryContext event_cxt
Definition: trigger.c:3799
AfterTriggerEventList events
Definition: trigger.c:3798
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerEndQuery()

void AfterTriggerEndQuery ( EState estate)

Definition at line 4802 of file trigger.c.

References afterTriggerDeleteHeadEventChunk(), AfterTriggerFreeQuery(), afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersQueryData::events, AfterTriggersData::firing_counter, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::query_depth, AfterTriggersData::query_stack, and AfterTriggerEventList::tail.

Referenced by apply_handle_delete(), apply_handle_insert(), apply_handle_update(), CopyFrom(), ExecuteTruncateGuts(), and standard_ExecutorFinish().

4803 {
4805 
4806  /* Must be inside a query, too */
4808 
4809  /*
4810  * If we never even got as far as initializing the event stack, there
4811  * certainly won't be any events, so exit quickly.
4812  */
4814  {
4816  return;
4817  }
4818 
4819  /*
4820  * Process all immediate-mode triggers queued by the query, and move the
4821  * deferred ones to the main list of deferred events.
4822  *
4823  * Notice that we decide which ones will be fired, and put the deferred
4824  * ones on the main list, before anything is actually fired. This ensures
4825  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4826  * IMMEDIATE: all events we have decided to defer will be available for it
4827  * to fire.
4828  *
4829  * We loop in case a trigger queues more events at the same query level.
4830  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4831  * will instead fire any triggers in a dedicated query level. Foreign key
4832  * enforcement triggers do add to the current query level, thanks to their
4833  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4834  * C-language triggers might do likewise.
4835  *
4836  * If we find no firable events, we don't have to increment
4837  * firing_counter.
4838  */
4840 
4841  for (;;)
4842  {
4844  {
4845  CommandId firing_id = afterTriggers.firing_counter++;
4846  AfterTriggerEventChunk *oldtail = qs->events.tail;
4847 
4848  if (afterTriggerInvokeEvents(&qs->events, firing_id, estate, false))
4849  break; /* all fired */
4850 
4851  /*
4852  * Firing a trigger could result in query_stack being repalloc'd,
4853  * so we must recalculate qs after each afterTriggerInvokeEvents
4854  * call. Furthermore, it's unsafe to pass delete_ok = true here,
4855  * because that could cause afterTriggerInvokeEvents to try to
4856  * access qs->events after the stack has been repalloc'd.
4857  */
4859 
4860  /*
4861  * We'll need to scan the events list again. To reduce the cost
4862  * of doing so, get rid of completely-fired chunks. We know that
4863  * all events were marked IN_PROGRESS or DONE at the conclusion of
4864  * afterTriggerMarkEvents, so any still-interesting events must
4865  * have been added after that, and so must be in the chunk that
4866  * was then the tail chunk, or in later chunks. So, zap all
4867  * chunks before oldtail. This is approximately the same set of
4868  * events we would have gotten rid of by passing delete_ok = true.
4869  */
4870  Assert(oldtail != NULL);
4871  while (qs->events.head != oldtail)
4873  }
4874  else
4875  break;
4876  }
4877 
4878  /* Release query-level-local storage, including tuplestores if any */
4880 
4882 }
uint32 CommandId
Definition: c.h:522
static void afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs)
Definition: trigger.c:4126
AfterTriggersQueryData * query_stack
Definition: trigger.c:3802
AfterTriggerEventChunk * tail
Definition: trigger.c:3691
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4459
CommandId firing_counter
Definition: trigger.c:3796
#define Assert(condition)
Definition: c.h:733
AfterTriggerEventChunk * head
Definition: trigger.c:3690
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4387
AfterTriggerEventList events
Definition: trigger.c:3798
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4893
AfterTriggerEventList events
Definition: trigger.c:3813
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerEndSubXact()

void AfterTriggerEndSubXact ( bool  isCommit)

Definition at line 5098 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, AfterTriggerFreeQuery(), afterTriggerRestoreEventList(), Assert, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggersData::events, AfterTriggersTransData::events, AfterTriggersTransData::firing_counter, for_each_event_chunk, GetCurrentTransactionNestLevel(), GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, pfree(), AfterTriggersData::query_depth, AfterTriggersTransData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersTransData::state, and AfterTriggersData::trans_stack.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

5099 {
5100  int my_level = GetCurrentTransactionNestLevel();
5102  AfterTriggerEvent event;
5103  AfterTriggerEventChunk *chunk;
5104  CommandId subxact_firing_id;
5105 
5106  /*
5107  * Pop the prior state if needed.
5108  */
5109  if (isCommit)
5110  {
5111  Assert(my_level < afterTriggers.maxtransdepth);
5112  /* If we saved a prior state, we don't need it anymore */
5113  state = afterTriggers.trans_stack[my_level].state;
5114  if (state != NULL)
5115  pfree(state);
5116  /* this avoids double pfree if error later: */
5117  afterTriggers.trans_stack[my_level].state = NULL;
5120  }
5121  else
5122  {
5123  /*
5124  * Aborting. It is possible subxact start failed before calling
5125  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
5126  * trans_stack levels that aren't there.
5127  */
5128  if (my_level >= afterTriggers.maxtransdepth)
5129  return;
5130 
5131  /*
5132  * Release query-level storage for queries being aborted, and restore
5133  * query_depth to its pre-subxact value. This assumes that a
5134  * subtransaction will not add events to query levels started in a
5135  * earlier transaction state.
5136  */
5138  {
5142  }
5145 
5146  /*
5147  * Restore the global deferred-event list to its former length,
5148  * discarding any events queued by the subxact.
5149  */
5151  &afterTriggers.trans_stack[my_level].events);
5152 
5153  /*
5154  * Restore the trigger state. If the saved state is NULL, then this
5155  * subxact didn't save it, so it doesn't need restoring.
5156  */
5157  state = afterTriggers.trans_stack[my_level].state;
5158  if (state != NULL)
5159  {
5161  afterTriggers.state = state;
5162  }
5163  /* this avoids double pfree if error later: */
5164  afterTriggers.trans_stack[my_level].state = NULL;
5165 
5166  /*
5167  * Scan for any remaining deferred events that were marked DONE or IN
5168  * PROGRESS by this subxact or a child, and un-mark them. We can
5169  * recognize such events because they have a firing ID greater than or
5170  * equal to the firing_counter value we saved at subtransaction start.
5171  * (This essentially assumes that the current subxact includes all
5172  * subxacts started after it.)
5173  */
5174  subxact_firing_id = afterTriggers.trans_stack[my_level].firing_counter;
5176  {
5177  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5178 
5179  if (event->ate_flags &
5181  {
5182  if (evtshared->ats_firing_id >= subxact_firing_id)
5183  event->ate_flags &=
5185  }
5186  }
5187  }
5188 }
uint32 CommandId
Definition: c.h:522
AfterTriggersTransData * trans_stack
Definition: trigger.c:3807
TriggerFlags ate_flags
Definition: trigger.c:3641
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3617
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3703
AfterTriggerEventList events
Definition: trigger.c:3822
AfterTriggersQueryData * query_stack
Definition: trigger.c:3802
CommandId firing_counter
Definition: trigger.c:3824
#define GetTriggerSharedData(evt)
Definition: trigger.c:3666
void pfree(void *pointer)
Definition: mcxt.c:1056
SetConstraintState state
Definition: trigger.c:3797
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
#define Assert(condition)
Definition: c.h:733
Definition: regguts.h:298
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:4086
CommandId ats_firing_id
Definition: trigger.c:3633
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3618
AfterTriggerEventList events
Definition: trigger.c:3798
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4893
static AfterTriggersData afterTriggers
Definition: trigger.c:3841
SetConstraintState state
Definition: trigger.c:3821

◆ AfterTriggerEndXact()

void AfterTriggerEndXact ( bool  isCommit)

Definition at line 5002 of file trigger.c.

References AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, MemoryContextDelete(), AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggerEventList::tail, AfterTriggerEventList::tailfree, and AfterTriggersData::trans_stack.

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

5003 {
5004  /*
5005  * Forget the pending-events list.
5006  *
5007  * Since all the info is in TopTransactionContext or children thereof, we
5008  * don't really need to do anything to reclaim memory. However, the
5009  * pending-events list could be large, and so it's useful to discard it as
5010  * soon as possible --- especially if we are aborting because we ran out
5011  * of memory for the list!
5012  */
5014  {
5016  afterTriggers.event_cxt = NULL;
5017  afterTriggers.events.head = NULL;
5018  afterTriggers.events.tail = NULL;
5019  afterTriggers.events.tailfree = NULL;
5020  }
5021 
5022  /*
5023  * Forget any subtransaction state as well. Since this can't be very
5024  * large, we let the eventual reset of TopTransactionContext free the
5025  * memory instead of doing it here.
5026  */
5027  afterTriggers.trans_stack = NULL;
5029 
5030 
5031  /*
5032  * Forget the query stack and constraint-related state information. As
5033  * with the subtransaction state information, we don't bother freeing the
5034  * memory here.
5035  */
5036  afterTriggers.query_stack = NULL;
5038  afterTriggers.state = NULL;
5039 
5040  /* No more afterTriggers manipulation until next transaction starts. */
5042 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
AfterTriggersTransData * trans_stack
Definition: trigger.c:3807
AfterTriggersQueryData * query_stack
Definition: trigger.c:3802
AfterTriggerEventChunk * tail
Definition: trigger.c:3691
SetConstraintState state
Definition: trigger.c:3797
AfterTriggerEventChunk * head
Definition: trigger.c:3690
MemoryContext event_cxt
Definition: trigger.c:3799
AfterTriggerEventList events
Definition: trigger.c:3798
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerFireDeferred()

void AfterTriggerFireDeferred ( void  )

Definition at line 4946 of file trigger.c.

References afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::firing_counter, GetTransactionSnapshot(), AfterTriggerEventList::head, PopActiveSnapshot(), PushActiveSnapshot(), and AfterTriggersData::query_depth.

Referenced by CommitTransaction(), and PrepareTransaction().

4947 {
4948  AfterTriggerEventList *events;
4949  bool snap_pushed = false;
4950 
4951  /* Must not be inside a query */
4953 
4954  /*
4955  * If there are any triggers to fire, make sure we have set a snapshot for
4956  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4957  * can't assume ActiveSnapshot is valid on entry.)
4958  */
4959  events = &afterTriggers.events;
4960  if (events->head != NULL)
4961  {
4963  snap_pushed = true;
4964  }
4965 
4966  /*
4967  * Run all the remaining triggers. Loop until they are all gone, in case
4968  * some trigger queues more for us to do.
4969  */
4970  while (afterTriggerMarkEvents(events, NULL, false))
4971  {
4972  CommandId firing_id = afterTriggers.firing_counter++;
4973 
4974  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4975  break; /* all fired */
4976  }
4977 
4978  /*
4979  * We don't bother freeing the event list, since it will go away anyway
4980  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4981  */
4982 
4983  if (snap_pushed)
4985 }
uint32 CommandId
Definition: c.h:522
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4459
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
CommandId firing_counter
Definition: trigger.c:3796
#define Assert(condition)
Definition: c.h:733
AfterTriggerEventChunk * head
Definition: trigger.c:3690
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4387
AfterTriggerEventList events
Definition: trigger.c:3798
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerPendingOnRel()

bool AfterTriggerPendingOnRel ( Oid  relid)

Definition at line 5637 of file trigger.c.

References AFTER_TRIGGER_DONE, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_relid, AfterTriggersData::events, AfterTriggersQueryData::events, for_each_event_chunk, GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::query_depth, and AfterTriggersData::query_stack.

Referenced by CheckTableNotInUse().

5638 {
5639  AfterTriggerEvent event;
5640  AfterTriggerEventChunk *chunk;
5641  int depth;
5642 
5643  /* Scan queued events */
5645  {
5646  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5647 
5648  /*
5649  * We can ignore completed events. (Even if a DONE flag is rolled
5650  * back by subxact abort, it's OK because the effects of the TRUNCATE
5651  * or whatever must get rolled back too.)
5652  */
5653  if (event->ate_flags & AFTER_TRIGGER_DONE)
5654  continue;
5655 
5656  if (evtshared->ats_relid == relid)
5657  return true;
5658  }
5659 
5660  /*
5661  * Also scan events queued by incomplete queries. This could only matter
5662  * if TRUNCATE/etc is executed by a function or trigger within an updating
5663  * query on the same relation, which is pretty perverse, but let's check.
5664  */
5665  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5666  {
5668  {
5669  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5670 
5671  if (event->ate_flags & AFTER_TRIGGER_DONE)
5672  continue;
5673 
5674  if (evtshared->ats_relid == relid)
5675  return true;
5676  }
5677  }
5678 
5679  return false;
5680 }
TriggerFlags ate_flags
Definition: trigger.c:3641
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3617
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3703
AfterTriggersQueryData * query_stack
Definition: trigger.c:3802
#define GetTriggerSharedData(evt)
Definition: trigger.c:3666
AfterTriggerEventList events
Definition: trigger.c:3798
AfterTriggerEventList events
Definition: trigger.c:3813
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerSetState()

void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 5322 of file trigger.c.

References AccessShareLock, afterTriggerInvokeEvents(), afterTriggerMarkEvents(), SetConstraintStateData::all_isdeferred, SetConstraintStateData::all_isset, BTEqualStrategyNumber, RangeVar::catalogname, ConstraintNameNspIndexId, ConstraintParentIndexId, ConstraintsSetStmt::constraints, CStringGetDatum, ConstraintsSetStmt::deferred, ereport, errcode(), errmsg(), ERROR, AfterTriggersData::events, fetch_search_path(), AfterTriggersData::firing_counter, get_database_name(), GetCurrentTransactionNestLevel(), GETSTRUCT, GetTransactionSnapshot(), HeapTupleIsValid, i, IsSubTransaction(), sort-test::key, lappend_oid(), lfirst, lfirst_oid, list_free(), list_make1_oid, LookupExplicitNamespace(), MyDatabaseId, NIL, SetConstraintStateData::numstates, ObjectIdGetDatum, PopActiveSnapshot(), PushActiveSnapshot(), RangeVar::relname, ScanKeyInit(), RangeVar::schemaname, SetConstraintTriggerData::sct_tgisdeferred, SetConstraintTriggerData::sct_tgoid, SetConstraintStateAddItem(), SetConstraintStateCopy(), SetConstraintStateCreate(), AfterTriggersData::state, AfterTriggersTransData::state, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), AfterTriggersData::trans_stack, TriggerConstraintIndexId, and SetConstraintStateData::trigstates.

Referenced by standard_ProcessUtility().

5323 {
5324  int my_level = GetCurrentTransactionNestLevel();
5325 
5326  /* If we haven't already done so, initialize our state. */
5327  if (afterTriggers.state == NULL)
5329 
5330  /*
5331  * If in a subtransaction, and we didn't save the current state already,
5332  * save it so it can be restored if the subtransaction aborts.
5333  */
5334  if (my_level > 1 &&
5335  afterTriggers.trans_stack[my_level].state == NULL)
5336  {
5337  afterTriggers.trans_stack[my_level].state =
5339  }
5340 
5341  /*
5342  * Handle SET CONSTRAINTS ALL ...
5343  */
5344  if (stmt->constraints == NIL)
5345  {
5346  /*
5347  * Forget any previous SET CONSTRAINTS commands in this transaction.
5348  */
5350 
5351  /*
5352  * Set the per-transaction ALL state to known.
5353  */
5354  afterTriggers.state->all_isset = true;
5356  }
5357  else
5358  {
5359  Relation conrel;
5360  Relation tgrel;
5361  List *conoidlist = NIL;
5362  List *tgoidlist = NIL;
5363  ListCell *lc;
5364 
5365  /*
5366  * Handle SET CONSTRAINTS constraint-name [, ...]
5367  *
5368  * First, identify all the named constraints and make a list of their
5369  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
5370  * the same name within a schema, the specifications are not
5371  * necessarily unique. Our strategy is to target all matching
5372  * constraints within the first search-path schema that has any
5373  * matches, but disregard matches in schemas beyond the first match.
5374  * (This is a bit odd but it's the historical behavior.)
5375  *
5376  * A constraint in a partitioned table may have corresponding
5377  * constraints in the partitions. Grab those too.
5378  */
5379  conrel = table_open(ConstraintRelationId, AccessShareLock);
5380 
5381  foreach(lc, stmt->constraints)
5382  {
5383  RangeVar *constraint = lfirst(lc);
5384  bool found;
5385  List *namespacelist;
5386  ListCell *nslc;
5387 
5388  if (constraint->catalogname)
5389  {
5390  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
5391  ereport(ERROR,
5392  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5393  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
5394  constraint->catalogname, constraint->schemaname,
5395  constraint->relname)));
5396  }
5397 
5398  /*
5399  * If we're given the schema name with the constraint, look only
5400  * in that schema. If given a bare constraint name, use the
5401  * search path to find the first matching constraint.
5402  */
5403  if (constraint->schemaname)
5404  {
5405  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
5406  false);
5407 
5408  namespacelist = list_make1_oid(namespaceId);
5409  }
5410  else
5411  {
5412  namespacelist = fetch_search_path(true);
5413  }
5414 
5415  found = false;
5416  foreach(nslc, namespacelist)
5417  {
5418  Oid namespaceId = lfirst_oid(nslc);
5419  SysScanDesc conscan;
5420  ScanKeyData skey[2];
5421  HeapTuple tup;
5422 
5423  ScanKeyInit(&skey[0],
5424  Anum_pg_constraint_conname,
5425  BTEqualStrategyNumber, F_NAMEEQ,
5426  CStringGetDatum(constraint->relname));
5427  ScanKeyInit(&skey[1],
5428  Anum_pg_constraint_connamespace,
5429  BTEqualStrategyNumber, F_OIDEQ,
5430  ObjectIdGetDatum(namespaceId));
5431 
5432  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
5433  true, NULL, 2, skey);
5434 
5435  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
5436  {
5438 
5439  if (con->condeferrable)
5440  conoidlist = lappend_oid(conoidlist, con->oid);
5441  else if (stmt->deferred)
5442  ereport(ERROR,
5443  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5444  errmsg("constraint \"%s\" is not deferrable",
5445  constraint->relname)));
5446  found = true;
5447  }
5448 
5449  systable_endscan(conscan);
5450 
5451  /*
5452  * Once we've found a matching constraint we do not search
5453  * later parts of the search path.
5454  */
5455  if (found)
5456  break;
5457  }
5458 
5459  list_free(namespacelist);
5460 
5461  /*
5462  * Not found ?
5463  */
5464  if (!found)
5465  ereport(ERROR,
5466  (errcode(ERRCODE_UNDEFINED_OBJECT),
5467  errmsg("constraint \"%s\" does not exist",
5468  constraint->relname)));
5469  }
5470 
5471  /*
5472  * Scan for any possible descendants of the constraints. We append
5473  * whatever we find to the same list that we're scanning; this has the
5474  * effect that we create new scans for those, too, so if there are
5475  * further descendents, we'll also catch them.
5476  */
5477  foreach(lc, conoidlist)
5478  {
5479  Oid parent = lfirst_oid(lc);
5480  ScanKeyData key;
5481  SysScanDesc scan;
5482  HeapTuple tuple;
5483 
5484  ScanKeyInit(&key,
5485  Anum_pg_constraint_conparentid,
5486  BTEqualStrategyNumber, F_OIDEQ,
5487  ObjectIdGetDatum(parent));
5488 
5489  scan = systable_beginscan(conrel, ConstraintParentIndexId, true, NULL, 1, &key);
5490 
5491  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
5492  {
5494 
5495  conoidlist = lappend_oid(conoidlist, con->oid);
5496  }
5497 
5498  systable_endscan(scan);
5499  }
5500 
5501  table_close(conrel, AccessShareLock);
5502 
5503  /*
5504  * Now, locate the trigger(s) implementing each of these constraints,
5505  * and make a list of their OIDs.
5506  */
5507  tgrel = table_open(TriggerRelationId, AccessShareLock);
5508 
5509  foreach(lc, conoidlist)
5510  {
5511  Oid conoid = lfirst_oid(lc);
5512  ScanKeyData skey;
5513  SysScanDesc tgscan;
5514  HeapTuple htup;
5515 
5516  ScanKeyInit(&skey,
5517  Anum_pg_trigger_tgconstraint,
5518  BTEqualStrategyNumber, F_OIDEQ,
5519  ObjectIdGetDatum(conoid));
5520 
5521  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
5522  NULL, 1, &skey);
5523 
5524  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
5525  {
5526  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
5527 
5528  /*
5529  * Silently skip triggers that are marked as non-deferrable in
5530  * pg_trigger. This is not an error condition, since a
5531  * deferrable RI constraint may have some non-deferrable
5532  * actions.
5533  */
5534  if (pg_trigger->tgdeferrable)
5535  tgoidlist = lappend_oid(tgoidlist, pg_trigger->oid);
5536  }
5537 
5538  systable_endscan(tgscan);
5539  }
5540 
5541  table_close(tgrel, AccessShareLock);
5542 
5543  /*
5544  * Now we can set the trigger states of individual triggers for this
5545  * xact.
5546  */
5547  foreach(lc, tgoidlist)
5548  {
5549  Oid tgoid = lfirst_oid(lc);
5551  bool found = false;
5552  int i;
5553 
5554  for (i = 0; i < state->numstates; i++)
5555  {
5556  if (state->trigstates[i].sct_tgoid == tgoid)
5557  {
5558  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5559  found = true;
5560  break;
5561  }
5562  }
5563  if (!found)
5564  {
5566  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
5567  }
5568  }
5569  }
5570 
5571  /*
5572  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
5573  * checks against that constraint must be made when the SET CONSTRAINTS
5574  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
5575  * apply retroactively. We've updated the constraints state, so scan the
5576  * list of previously deferred events to fire any that have now become
5577  * immediate.
5578  *
5579  * Obviously, if this was SET ... DEFERRED then it can't have converted
5580  * any unfired events to immediate, so we need do nothing in that case.
5581  */
5582  if (!stmt->deferred)
5583  {
5585  bool snapshot_set = false;
5586 
5587  while (afterTriggerMarkEvents(events, NULL, true))
5588  {
5589  CommandId firing_id = afterTriggers.firing_counter++;
5590 
5591  /*
5592  * Make sure a snapshot has been established in case trigger
5593  * functions need one. Note that we avoid setting a snapshot if
5594  * we don't find at least one trigger that has to be fired now.
5595  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
5596  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
5597  * at the start of a transaction it's not possible for any trigger
5598  * events to be queued yet.)
5599  */
5600  if (!snapshot_set)
5601  {
5603  snapshot_set = true;
5604  }
5605 
5606  /*
5607  * We can delete fired events if we are at top transaction level,
5608  * but we'd better not if inside a subtransaction, since the
5609  * subtransaction could later get rolled back.
5610  */
5611  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5612  !IsSubTransaction()))
5613  break; /* all fired */
5614  }
5615 
5616  if (snapshot_set)
5618  }
5619 }
#define NIL
Definition: pg_list.h:65
uint32 CommandId
Definition: c.h:522
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2885
AfterTriggersTransData * trans_stack
Definition: trigger.c:3807
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3571
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
Definition: trigger.c:5292
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4459
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
char * schemaname
Definition: primnodes.h:67
char * relname
Definition: primnodes.h:68
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
SetConstraintState state
Definition: trigger.c:3797
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2131
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
#define CStringGetDatum(X)
Definition: postgres.h:578
#define TriggerConstraintIndexId
Definition: indexing.h:254
#define ereport(elevel, rest)
Definition: elog.h:141
static SetConstraintState SetConstraintStateCreate(int numalloc)
Definition: trigger.c:5247
#define list_make1_oid(x1)
Definition: pg_list.h:249
Oid MyDatabaseId
Definition: globals.c:85
CommandId firing_counter
Definition: trigger.c:3796
#define ConstraintNameNspIndexId
Definition: indexing.h:126
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:841
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
Definition: regguts.h:298
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:71
bool IsSubTransaction(void)
Definition: xact.c:4708
int errmsg(const char *fmt,...)
Definition: elog.c:822
void list_free(List *list)
Definition: list.c:1377
int i
#define ConstraintParentIndexId
Definition: indexing.h:134
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4387
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3798
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4305
static AfterTriggersData afterTriggers
Definition: trigger.c:3841
char * catalogname
Definition: primnodes.h:66
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192
SetConstraintState state
Definition: trigger.c:3821
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:5272

◆ CopyTriggerDesc()

TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

Definition at line 2157 of file trigger.c.

References i, 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().

2158 {
2159  TriggerDesc *newdesc;
2160  Trigger *trigger;
2161  int i;
2162 
2163  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
2164  return NULL;
2165 
2166  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
2167  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
2168 
2169  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
2170  memcpy(trigger, trigdesc->triggers,
2171  trigdesc->numtriggers * sizeof(Trigger));
2172  newdesc->triggers = trigger;
2173 
2174  for (i = 0; i < trigdesc->numtriggers; i++)
2175  {
2176  trigger->tgname = pstrdup(trigger->tgname);
2177  if (trigger->tgnattr > 0)
2178  {
2179  int16 *newattr;
2180 
2181  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
2182  memcpy(newattr, trigger->tgattr,
2183  trigger->tgnattr * sizeof(int16));
2184  trigger->tgattr = newattr;
2185  }
2186  if (trigger->tgnargs > 0)
2187  {
2188  char **newargs;
2189  int16 j;
2190 
2191  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
2192  for (j = 0; j < trigger->tgnargs; j++)
2193  newargs[j] = pstrdup(trigger->tgargs[j]);
2194  trigger->tgargs = newargs;
2195  }
2196  if (trigger->tgqual)
2197  trigger->tgqual = pstrdup(trigger->tgqual);
2198  if (trigger->tgoldtable)
2199  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
2200  if (trigger->tgnewtable)
2201  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
2202  trigger++;
2203  }
2204 
2205  return newdesc;
2206 }
signed short int16
Definition: c.h:346
char * pstrdup(const char *in)
Definition: mcxt.c:1186
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
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:949
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42

◆ CreateTrigger()

ObjectAddress CreateTrigger ( CreateTrigStmt stmt,
const char *  queryString,
Oid  relOid,
Oid  refRelOid,
Oid  constraintOid,
Oid  indexOid,
Oid  funcoid,
Oid  parentTriggerOid,
Node whenClause,
bool  isInternal,
bool  in_partition 
)

Definition at line 162 of file trigger.c.

References AccessShareLock, ACL_EXECUTE, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addRangeTableEntryForRelation(), addRTEtoQuery(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, allowSystemTableMods, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), attnum, BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CacheInvalidateRelcacheByTuple(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CommandCounterIncrement(), CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject, CreateConstraintEntry(), CreateTrigger(), CStringGetDatum, CStringGetTextDatum, CurrentMemoryContext, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, find_all_inheritors(), find_inheritance_children(), forboth, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), has_superclass(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, IndexGetRelation(), CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, sort-test::key, lappend_oid(), lfirst, lfirst_node, lfirst_oid, list_free(), list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), map_partition_varattnos(), MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), name, TriggerTransition::name, NAMEDATALEN, namein(), NameListToString(), NameStr, namestrcmp(), NIL, nodeToString(), NoLock, PartitionDescData::nparts, OBJECT_FUNCTION, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, PartitionDescData::oids, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_id, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetDescr, RelationGetNamespace, RelationGetPartitionDesc, RelationGetRelationName, RelationGetRelid, relhastriggers, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, snprintf, strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), table_openrv(), CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, TRIGGER_FIRES_ON_ORIGIN, TriggerOidIndexId, TriggerRelidNameIndexId, CreateTrigStmt::trigname, TupleDescAttr, values, Var::varattno, Var::varno, WARNING, and CreateTrigStmt::whenClause.

Referenced by CloneRowTriggersToPartition(), CreateFKCheckTrigger(), createForeignKeyActionTriggers(), CreateTrigger(), index_constraint_create(), and ProcessUtilitySlow().

166 {
167  int16 tgtype;
168  int ncolumns;
169  int16 *columns;
170  int2vector *tgattr;
171  List *whenRtable;
172  char *qual;
173  Datum values[Natts_pg_trigger];
174  bool nulls[Natts_pg_trigger];
175  Relation rel;
176  AclResult aclresult;
177  Relation tgrel;
178  SysScanDesc tgscan;
180  Relation pgrel;
181  HeapTuple tuple;
182  Oid funcrettype;
183  Oid trigoid;
184  char internaltrigname[NAMEDATALEN];
185  char *trigname;
186  Oid constrrelid = InvalidOid;
187  ObjectAddress myself,
188  referenced;
189  char *oldtablename = NULL;
190  char *newtablename = NULL;
191  bool partition_recurse;
192 
193  if (OidIsValid(relOid))
194  rel = table_open(relOid, ShareRowExclusiveLock);
195  else
197 
198  /*
199  * Triggers must be on tables or views, and there are additional
200  * relation-type-specific restrictions.
201  */
202  if (rel->rd_rel->relkind == RELKIND_RELATION)
203  {
204  /* Tables can't have INSTEAD OF triggers */
205  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
206  stmt->timing != TRIGGER_TYPE_AFTER)
207  ereport(ERROR,
208  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
209  errmsg("\"%s\" is a table",
211  errdetail("Tables cannot have INSTEAD OF triggers.")));
212  }
213  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
214  {
215  /* Partitioned tables can't have INSTEAD OF triggers */
216  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
217  stmt->timing != TRIGGER_TYPE_AFTER)
218  ereport(ERROR,
219  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
220  errmsg("\"%s\" is a table",
222  errdetail("Tables cannot have INSTEAD OF triggers.")));
223 
224  /*
225  * FOR EACH ROW triggers have further restrictions
226  */
227  if (stmt->row)
228  {
229  /*
230  * BEFORE triggers FOR EACH ROW are forbidden, because they would
231  * allow the user to direct the row to another partition, which
232  * isn't implemented in the executor.
233  */
234  if (stmt->timing != TRIGGER_TYPE_AFTER)
235  ereport(ERROR,
236  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
237  errmsg("\"%s\" is a partitioned table",
239  errdetail("Partitioned tables cannot have BEFORE / FOR EACH ROW triggers.")));
240 
241  /*
242  * Disallow use of transition tables.
243  *
244  * Note that we have another restriction about transition tables
245  * in partitions; search for 'has_superclass' below for an
246  * explanation. The check here is just to protect from the fact
247  * that if we allowed it here, the creation would succeed for a
248  * partitioned table with no partitions, but would be blocked by
249  * the other restriction when the first partition was created,
250  * which is very unfriendly behavior.
251  */
252  if (stmt->transitionRels != NIL)
253  ereport(ERROR,
254  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
255  errmsg("\"%s\" is a partitioned table",
257  errdetail("Triggers on partitioned tables cannot have transition tables.")));
258  }
259  }
260  else if (rel->rd_rel->relkind == RELKIND_VIEW)
261  {
262  /*
263  * Views can have INSTEAD OF triggers (which we check below are
264  * row-level), or statement-level BEFORE/AFTER triggers.
265  */
266  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
267  ereport(ERROR,
268  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
269  errmsg("\"%s\" is a view",
271  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
272  /* Disallow TRUNCATE triggers on VIEWs */
273  if (TRIGGER_FOR_TRUNCATE(stmt->events))
274  ereport(ERROR,
275  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
276  errmsg("\"%s\" is a view",
278  errdetail("Views cannot have TRUNCATE triggers.")));
279  }
280  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
281  {
282  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
283  stmt->timing != TRIGGER_TYPE_AFTER)
284  ereport(ERROR,
285  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
286  errmsg("\"%s\" is a foreign table",
288  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
289 
290  if (TRIGGER_FOR_TRUNCATE(stmt->events))
291  ereport(ERROR,
292  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
293  errmsg("\"%s\" is a foreign table",
295  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
296 
297  /*
298  * We disallow constraint triggers to protect the assumption that
299  * triggers on FKs can't be deferred. See notes with AfterTriggers
300  * data structures, below.
301  */
302  if (stmt->isconstraint)
303  ereport(ERROR,
304  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
305  errmsg("\"%s\" is a foreign table",
307  errdetail("Foreign tables cannot have constraint triggers.")));
308  }
309  else
310  ereport(ERROR,
311  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
312  errmsg("\"%s\" is not a table or view",
313  RelationGetRelationName(rel))));
314 
316  ereport(ERROR,
317  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318  errmsg("permission denied: \"%s\" is a system catalog",
319  RelationGetRelationName(rel))));
320 
321  if (stmt->isconstraint)
322  {
323  /*
324  * We must take a lock on the target relation to protect against
325  * concurrent drop. It's not clear that AccessShareLock is strong
326  * enough, but we certainly need at least that much... otherwise, we
327  * might end up creating a pg_constraint entry referencing a
328  * nonexistent table.
329  */
330  if (OidIsValid(refRelOid))
331  {
332  LockRelationOid(refRelOid, AccessShareLock);
333  constrrelid = refRelOid;
334  }
335  else if (stmt->constrrel != NULL)
336  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
337  false);
338  }
339 
340  /* permission checks */
341  if (!isInternal)
342  {
343  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
344  ACL_TRIGGER);
345  if (aclresult != ACLCHECK_OK)
346  aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
348 
349  if (OidIsValid(constrrelid))
350  {
351  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
352  ACL_TRIGGER);
353  if (aclresult != ACLCHECK_OK)
354  aclcheck_error(aclresult, get_relkind_objtype(get_rel_relkind(constrrelid)),
355  get_rel_name(constrrelid));
356  }
357  }
358 
359  /*
360  * When called on a partitioned table to create a FOR EACH ROW trigger
361  * that's not internal, we create one trigger for each partition, too.
362  *
363  * For that, we'd better hold lock on all of them ahead of time.
364  */
365  partition_recurse = !isInternal && stmt->row &&
366  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
367  if (partition_recurse)
369  ShareRowExclusiveLock, NULL));
370 
371  /* Compute tgtype */
372  TRIGGER_CLEAR_TYPE(tgtype);
373  if (stmt->row)
374  TRIGGER_SETT_ROW(tgtype);
375  tgtype |= stmt->timing;
376  tgtype |= stmt->events;
377 
378  /* Disallow ROW-level TRUNCATE triggers */
379  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
380  ereport(ERROR,
381  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
382  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
383 
384  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
385  if (TRIGGER_FOR_INSTEAD(tgtype))
386  {
387  if (!TRIGGER_FOR_ROW(tgtype))
388  ereport(ERROR,
389  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
390  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
391  if (stmt->whenClause)
392  ereport(ERROR,
393  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
394  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
395  if (stmt->columns != NIL)
396  ereport(ERROR,
397  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
398  errmsg("INSTEAD OF triggers cannot have column lists")));
399  }
400 
401  /*
402  * We don't yet support naming ROW transition variables, but the parser
403  * recognizes the syntax so we can give a nicer message here.
404  *
405  * Per standard, REFERENCING TABLE names are only allowed on AFTER
406  * triggers. Per standard, REFERENCING ROW names are not allowed with FOR
407  * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is
408  * only allowed once. Per standard, OLD may not be specified when
409  * creating a trigger only for INSERT, and NEW may not be specified when
410  * creating a trigger only for DELETE.
411  *
412  * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to
413  * reference both ROW and TABLE transition data.
414  */
415  if (stmt->transitionRels != NIL)
416  {
417  List *varList = stmt->transitionRels;
418  ListCell *lc;
419 
420  foreach(lc, varList)
421  {
423 
424  if (!(tt->isTable))
425  ereport(ERROR,
426  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
427  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
428  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
429 
430  /*
431  * Because of the above test, we omit further ROW-related testing
432  * below. If we later allow naming OLD and NEW ROW variables,
433  * adjustments will be needed below.
434  */
435 
436  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
437  ereport(ERROR,
438  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
439  errmsg("\"%s\" is a foreign table",
441  errdetail("Triggers on foreign tables cannot have transition tables.")));
442 
443  if (rel->rd_rel->relkind == RELKIND_VIEW)
444  ereport(ERROR,
445  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
446  errmsg("\"%s\" is a view",
448  errdetail("Triggers on views cannot have transition tables.")));
449 
450  /*
451  * We currently don't allow row-level triggers with transition
452  * tables on partition or inheritance children. Such triggers
453  * would somehow need to see tuples converted to the format of the
454  * table they're attached to, and it's not clear which subset of
455  * tuples each child should see. See also the prohibitions in
456  * ATExecAttachPartition() and ATExecAddInherit().
457  */
458  if (TRIGGER_FOR_ROW(tgtype) && has_superclass(rel->rd_id))
459  {
460  /* Use appropriate error message. */
461  if (rel->rd_rel->relispartition)
462  ereport(ERROR,
463  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
464  errmsg("ROW triggers with transition tables are not supported on partitions")));
465  else
466  ereport(ERROR,
467  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
468  errmsg("ROW triggers with transition tables are not supported on inheritance children")));
469  }
470 
471  if (stmt->timing != TRIGGER_TYPE_AFTER)
472  ereport(ERROR,
473  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
474  errmsg("transition table name can only be specified for an AFTER trigger")));
475 
476  if (TRIGGER_FOR_TRUNCATE(tgtype))
477  ereport(ERROR,
478  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
479  errmsg("TRUNCATE triggers with transition tables are not supported")));
480 
481  /*
482  * We currently don't allow multi-event triggers ("INSERT OR
483  * UPDATE") with transition tables, because it's not clear how to
484  * handle INSERT ... ON CONFLICT statements which can fire both
485  * INSERT and UPDATE triggers. We show the inserted tuples to
486  * INSERT triggers and the updated tuples to UPDATE triggers, but
487  * it's not yet clear what INSERT OR UPDATE trigger should see.
488  * This restriction could be lifted if we can decide on the right
489  * semantics in a later release.
490  */
491  if (((TRIGGER_FOR_INSERT(tgtype) ? 1 : 0) +
492  (TRIGGER_FOR_UPDATE(tgtype) ? 1 : 0) +
493  (TRIGGER_FOR_DELETE(tgtype) ? 1 : 0)) != 1)
494  ereport(ERROR,
495  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
496  errmsg("transition tables cannot be specified for triggers with more than one event")));
497 
498  /*
499  * We currently don't allow column-specific triggers with
500  * transition tables. Per spec, that seems to require
501  * accumulating separate transition tables for each combination of
502  * columns, which is a lot of work for a rather marginal feature.
503  */
504  if (stmt->columns != NIL)
505  ereport(ERROR,
506  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507  errmsg("transition tables cannot be specified for triggers with column lists")));
508 
509  /*
510  * We disallow constraint triggers with transition tables, to
511  * protect the assumption that such triggers can't be deferred.
512  * See notes with AfterTriggers data structures, below.
513  *
514  * Currently this is enforced by the grammar, so just Assert here.
515  */
516  Assert(!stmt->isconstraint);
517 
518  if (tt->isNew)
519  {
520  if (!(TRIGGER_FOR_INSERT(tgtype) ||
521  TRIGGER_FOR_UPDATE(tgtype)))
522  ereport(ERROR,
523  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
524  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
525 
526  if (newtablename != NULL)
527  ereport(ERROR,
528  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
529  errmsg("NEW TABLE cannot be specified multiple times")));
530 
531  newtablename = tt->name;
532  }
533  else
534  {
535  if (!(TRIGGER_FOR_DELETE(tgtype) ||
536  TRIGGER_FOR_UPDATE(tgtype)))
537  ereport(ERROR,
538  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
539  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
540 
541  if (oldtablename != NULL)
542  ereport(ERROR,
543  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
544  errmsg("OLD TABLE cannot be specified multiple times")));
545 
546  oldtablename = tt->name;
547  }
548  }
549 
550  if (newtablename != NULL && oldtablename != NULL &&
551  strcmp(newtablename, oldtablename) == 0)
552  ereport(ERROR,
553  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
554  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
555  }
556 
557  /*
558  * Parse the WHEN clause, if any and we weren't passed an already
559  * transformed one.
560  *
561  * Note that as a side effect, we fill whenRtable when parsing. If we got
562  * an already parsed clause, this does not occur, which is what we want --
563  * no point in adding redundant dependencies below.
564  */
565  if (!whenClause && stmt->whenClause)
566  {
567  ParseState *pstate;
568  RangeTblEntry *rte;
569  List *varList;
570  ListCell *lc;
571 
572  /* Set up a pstate to parse with */
573  pstate = make_parsestate(NULL);
574  pstate->p_sourcetext = queryString;
575 
576  /*
577  * Set up RTEs for OLD and NEW references.
578  *
579  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
580  */
581  rte = addRangeTableEntryForRelation(pstate, rel,
583  makeAlias("old", NIL),
584  false, false);
585  addRTEtoQuery(pstate, rte, false, true, true);
586  rte = addRangeTableEntryForRelation(pstate, rel,
588  makeAlias("new", NIL),
589  false, false);
590  addRTEtoQuery(pstate, rte, false, true, true);
591 
592  /* Transform expression. Copy to be sure we don't modify original */
593  whenClause = transformWhereClause(pstate,
594  copyObject(stmt->whenClause),
596  "WHEN");
597  /* we have to fix its collations too */
598  assign_expr_collations(pstate, whenClause);
599 
600  /*
601  * Check for disallowed references to OLD/NEW.
602  *
603  * NB: pull_var_clause is okay here only because we don't allow
604  * subselects in WHEN clauses; it would fail to examine the contents
605  * of subselects.
606  */
607  varList = pull_var_clause(whenClause, 0);
608  foreach(lc, varList)
609  {
610  Var *var = (Var *) lfirst(lc);
611 
612  switch (var->varno)
613  {
614  case PRS2_OLD_VARNO:
615  if (!TRIGGER_FOR_ROW(tgtype))
616  ereport(ERROR,
617  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
618  errmsg("statement trigger's WHEN condition cannot reference column values"),
619  parser_errposition(pstate, var->location)));
620  if (TRIGGER_FOR_INSERT(tgtype))
621  ereport(ERROR,
622  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
623  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
624  parser_errposition(pstate, var->location)));
625  /* system columns are okay here */
626  break;
627  case PRS2_NEW_VARNO:
628  if (!TRIGGER_FOR_ROW(tgtype))
629  ereport(ERROR,
630  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
631  errmsg("statement trigger's WHEN condition cannot reference column values"),
632  parser_errposition(pstate, var->location)));
633  if (TRIGGER_FOR_DELETE(tgtype))
634  ereport(ERROR,
635  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
636  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
637  parser_errposition(pstate, var->location)));
638  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
639  ereport(ERROR,
640  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
641  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
642  parser_errposition(pstate, var->location)));
643  if (TRIGGER_FOR_BEFORE(tgtype) &&
644  var->varattno == 0 &&
645  RelationGetDescr(rel)->constr &&
646  RelationGetDescr(rel)->constr->has_generated_stored)
647  ereport(ERROR,
648  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
649  errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
650  errdetail("A whole-row reference is used and the table contains generated columns."),
651  parser_errposition(pstate, var->location)));
652  if (TRIGGER_FOR_BEFORE(tgtype) &&
653  var->varattno > 0 &&
654  TupleDescAttr(RelationGetDescr(rel), var->varattno - 1)->attgenerated)
655  ereport(ERROR,
656  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
657  errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
658  errdetail("Column \"%s\" is a generated column.",
659  NameStr(TupleDescAttr(RelationGetDescr(rel), var->varattno - 1)->attname)),
660  parser_errposition(pstate, var->location)));
661  break;
662  default:
663  /* can't happen without add_missing_from, so just elog */
664  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
665  break;
666  }
667  }
668 
669  /* we'll need the rtable for recordDependencyOnExpr */
670  whenRtable = pstate->p_rtable;
671 
672  qual = nodeToString(whenClause);
673 
674  free_parsestate(pstate);
675  }
676  else if (!whenClause)
677  {
678  whenClause = NULL;
679  whenRtable = NIL;
680  qual = NULL;
681  }
682  else
683  {
684  qual = nodeToString(whenClause);
685  whenRtable = NIL;
686  }
687 
688  /*
689  * Find and validate the trigger function.
690  */
691  if (!OidIsValid(funcoid))
692  funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
693  if (!isInternal)
694  {
695  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
696  if (aclresult != ACLCHECK_OK)
697  aclcheck_error(aclresult, OBJECT_FUNCTION,
698  NameListToString(stmt->funcname));
699  }
700  funcrettype = get_func_rettype(funcoid);
701  if (funcrettype != TRIGGEROID)
702  {
703  /*
704  * We allow OPAQUE just so we can load old dump files. When we see a
705  * trigger function declared OPAQUE, change it to TRIGGER.
706  */
707  if (funcrettype == OPAQUEOID)
708  {
710  (errmsg("changing return type of function %s from %s to %s",
711  NameListToString(stmt->funcname),
712  "opaque", "trigger")));
713  SetFunctionReturnType(funcoid, TRIGGEROID);
714  }
715  else
716  ereport(ERROR,
717  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
718  errmsg("function %s must return type %s",
719  NameListToString(stmt->funcname), "trigger")));
720  }
721 
722  /*
723  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
724  * references one of the built-in RI_FKey trigger functions, assume it is
725  * from a dump of a pre-7.3 foreign key constraint, and take steps to
726  * convert this legacy representation into a regular foreign key
727  * constraint. Ugly, but necessary for loading old dump files.
728  */
729  if (stmt->isconstraint && !isInternal &&
730  list_length(stmt->args) >= 6 &&
731  (list_length(stmt->args) % 2) == 0 &&
733  {
734  /* Keep lock on target rel until end of xact */
735  table_close(rel, NoLock);
736 
737  ConvertTriggerToFK(stmt, funcoid);
738 
739  return InvalidObjectAddress;
740  }
741 
742  /*
743  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
744  * corresponding pg_constraint entry.
745  */
746  if (stmt->isconstraint && !OidIsValid(constraintOid))
747  {
748  /* Internal callers should have made their own constraints */
749  Assert(!isInternal);
750  constraintOid = CreateConstraintEntry(stmt->trigname,
752  CONSTRAINT_TRIGGER,
753  stmt->deferrable,
754  stmt->initdeferred,
755  true,
756  InvalidOid, /* no parent */
757  RelationGetRelid(rel),
758  NULL, /* no conkey */
759  0,
760  0,
761  InvalidOid, /* no domain */
762  InvalidOid, /* no index */
763  InvalidOid, /* no foreign key */
764  NULL,
765  NULL,
766  NULL,
767  NULL,
768  0,
769  ' ',
770  ' ',
771  ' ',
772  NULL, /* no exclusion */
773  NULL, /* no check constraint */
774  NULL,
775  true, /* islocal */
776  0, /* inhcount */
777  true, /* noinherit */
778  isInternal); /* is_internal */
779  }
780 
781  /*
782  * Generate the trigger's OID now, so that we can use it in the name if
783  * needed.
784  */
785  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
786 
787  trigoid = GetNewOidWithIndex(tgrel, TriggerOidIndexId,
788  Anum_pg_trigger_oid);
789 
790  /*
791  * If trigger is internally generated, modify the provided trigger name to
792  * ensure uniqueness by appending the trigger OID. (Callers will usually
793  * supply a simple constant trigger name in these cases.)
794  */
795  if (isInternal)
796  {
797  snprintf(internaltrigname, sizeof(internaltrigname),
798  "%s_%u", stmt->trigname, trigoid);
799  trigname = internaltrigname;
800  }
801  else
802  {
803  /* user-defined trigger; use the specified trigger name as-is */
804  trigname = stmt->trigname;
805  }
806 
807  /*
808  * Scan pg_trigger for existing triggers on relation. We do this only to
809  * give a nice error message if there's already a trigger of the same
810  * name. (The unique index on tgrelid/tgname would complain anyway.) We
811  * can skip this for internally generated triggers, since the name
812  * modification above should be sufficient.
813  *
814  * NOTE that this is cool only because we have ShareRowExclusiveLock on
815  * the relation, so the trigger set won't be changing underneath us.
816  */
817  if (!isInternal)
818  {
819  ScanKeyInit(&key,
820  Anum_pg_trigger_tgrelid,
821  BTEqualStrategyNumber, F_OIDEQ,
823  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
824  NULL, 1, &key);
825  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
826  {
827  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
828 
829  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
830  ereport(ERROR,
832  errmsg("trigger \"%s\" for relation \"%s\" already exists",
833  trigname, RelationGetRelationName(rel))));
834  }
835  systable_endscan(tgscan);
836  }
837 
838  /*
839  * Build the new pg_trigger tuple.
840  *
841  * When we're creating a trigger in a partition, we mark it as internal,
842  * even though we don't do the isInternal magic in this function. This
843  * makes the triggers in partitions identical to the ones in the
844  * partitioned tables, except that they are marked internal.
845  */
846  memset(nulls, false, sizeof(nulls));
847 
848  values[Anum_pg_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
849  values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
850  values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
851  CStringGetDatum(trigname));
852  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
853  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
854  values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
855  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal || in_partition);
856  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
857  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
858  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
859  values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
860  values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
861 
862  if (stmt->args)
863  {
864  ListCell *le;
865  char *args;
866  int16 nargs = list_length(stmt->args);
867  int len = 0;
868 
869  foreach(le, stmt->args)
870  {
871  char *ar = strVal(lfirst(le));
872 
873  len += strlen(ar) + 4;
874  for (; *ar; ar++)
875  {
876  if (*ar == '\\')
877  len++;
878  }
879  }
880  args = (char *) palloc(len + 1);
881  args[0] = '\0';
882  foreach(le, stmt->args)
883  {
884  char *s = strVal(lfirst(le));
885  char *d = args + strlen(args);
886 
887  while (*s)
888  {
889  if (*s == '\\')
890  *d++ = '\\';
891  *d++ = *s++;
892  }
893  strcpy(d, "\\000");
894  }
895  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
896  values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
897  CStringGetDatum(args));
898  }
899  else
900  {
901  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
902  values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
903  CStringGetDatum(""));
904  }
905 
906  /* build column number array if it's a column-specific trigger */
907  ncolumns = list_length(stmt->columns);
908  if (ncolumns == 0)
909  columns = NULL;
910  else
911  {
912  ListCell *cell;
913  int i = 0;
914 
915  columns = (int16 *) palloc(ncolumns * sizeof(int16));
916  foreach(cell, stmt->columns)
917  {
918  char *name = strVal(lfirst(cell));
919  int16 attnum;
920  int j;
921 
922  /* Lookup column name. System columns are not allowed */
923  attnum = attnameAttNum(rel, name, false);
924  if (attnum == InvalidAttrNumber)
925  ereport(ERROR,
926  (errcode(ERRCODE_UNDEFINED_COLUMN),
927  errmsg("column \"%s\" of relation \"%s\" does not exist",
928  name, RelationGetRelationName(rel))));
929 
930  /* Check for duplicates */
931  for (j = i - 1; j >= 0; j--)
932  {
933  if (columns[j] == attnum)
934  ereport(ERROR,
935  (errcode(ERRCODE_DUPLICATE_COLUMN),
936  errmsg("column \"%s\" specified more than once",
937  name)));
938  }
939 
940  columns[i++] = attnum;
941  }
942  }
943  tgattr = buildint2vector(columns, ncolumns);
944  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
945 
946  /* set tgqual if trigger has WHEN clause */
947  if (qual)
948  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
949  else
950  nulls[Anum_pg_trigger_tgqual - 1] = true;
951 
952  if (oldtablename)
953  values[Anum_pg_trigger_tgoldtable - 1] = DirectFunctionCall1(namein,
954  CStringGetDatum(oldtablename));
955  else
956  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
957  if (newtablename)
958  values[Anum_pg_trigger_tgnewtable - 1] = DirectFunctionCall1(namein,
959  CStringGetDatum(newtablename));
960  else
961  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
962 
963  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
964 
965  /*
966  * Insert tuple into pg_trigger.
967  */
968  CatalogTupleInsert(tgrel, tuple);
969 
970  heap_freetuple(tuple);
972 
973  pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
974  pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
975  pfree(DatumGetPointer(values[Anum_pg_trigger_tgattr - 1]));
976  if (oldtablename)
977  pfree(DatumGetPointer(values[Anum_pg_trigger_tgoldtable - 1]));
978  if (newtablename)
979  pfree(DatumGetPointer(values[Anum_pg_trigger_tgnewtable - 1]));
980 
981  /*
982  * Update relation's pg_class entry; if necessary; and if not, send an SI
983  * message to make other backends (and this one) rebuild relcache entries.
984  */
985  pgrel = table_open(RelationRelationId, RowExclusiveLock);
986  tuple = SearchSysCacheCopy1(RELOID,
988  if (!HeapTupleIsValid(tuple))
989  elog(ERROR, "cache lookup failed for relation %u",
990  RelationGetRelid(rel));
991  if (!((Form_pg_class) GETSTRUCT(tuple))->relhastriggers)
992  {
993  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
994 
995  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
996 
998  }
999  else
1001 
1002  heap_freetuple(tuple);
1003  table_close(pgrel, RowExclusiveLock);
1004 
1005  /*
1006  * Record dependencies for trigger. Always place a normal dependency on
1007  * the function.
1008  */
1009  myself.classId = TriggerRelationId;
1010  myself.objectId = trigoid;
1011  myself.objectSubId = 0;
1012 
1013  referenced.classId = ProcedureRelationId;
1014  referenced.objectId = funcoid;
1015  referenced.objectSubId = 0;
1016  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1017 
1018  if (isInternal && OidIsValid(constraintOid))
1019  {
1020  /*
1021  * Internally-generated trigger for a constraint, so make it an
1022  * internal dependency of the constraint. We can skip depending on
1023  * the relation(s), as there'll be an indirect dependency via the
1024  * constraint.
1025  */
1026  referenced.classId = ConstraintRelationId;
1027  referenced.objectId = constraintOid;
1028  referenced.objectSubId = 0;
1029  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1030  }
1031  else
1032  {
1033  /*
1034  * User CREATE TRIGGER, so place dependencies. We make trigger be
1035  * auto-dropped if its relation is dropped or if the FK relation is
1036  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
1037  */
1038  referenced.classId = RelationRelationId;
1039  referenced.objectId = RelationGetRelid(rel);
1040  referenced.objectSubId = 0;
1041  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1042 
1043  if (OidIsValid(constrrelid))
1044  {
1045  referenced.classId = RelationRelationId;
1046  referenced.objectId = constrrelid;
1047  referenced.objectSubId = 0;
1048  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1049  }
1050  /* Not possible to have an index dependency in this case */
1051  Assert(!OidIsValid(indexOid));
1052 
1053  /*
1054  * If it's a user-specified constraint trigger, make the constraint
1055  * internally dependent on the trigger instead of vice versa.
1056  */
1057  if (OidIsValid(constraintOid))
1058  {
1059  referenced.classId = ConstraintRelationId;
1060  referenced.objectId = constraintOid;
1061  referenced.objectSubId = 0;
1062  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
1063  }
1064 
1065  /*
1066  * If it's a partition trigger, create the partition dependencies.
1067  */
1068  if (OidIsValid(parentTriggerOid))
1069  {
1070  ObjectAddressSet(referenced, TriggerRelationId, parentTriggerOid);
1071  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
1072  ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel));
1073  recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
1074  }
1075  }
1076 
1077  /* If column-specific trigger, add normal dependencies on columns */
1078  if (columns != NULL)
1079  {
1080  int i;
1081 
1082  referenced.classId = RelationRelationId;
1083  referenced.objectId = RelationGetRelid(rel);
1084  for (i = 0; i < ncolumns; i++)
1085  {
1086  referenced.objectSubId = columns[i];
1087  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1088  }
1089  }
1090 
1091  /*
1092  * If it has a WHEN clause, add dependencies on objects mentioned in the
1093  * expression (eg, functions, as well as any columns used).
1094  */
1095  if (whenRtable != NIL)
1096  recordDependencyOnExpr(&myself, whenClause, whenRtable,
1098 
1099  /* Post creation hook for new trigger */
1100  InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
1101  isInternal);
1102 
1103  /*
1104  * Lastly, create the trigger on child relations, if needed.
1105  */
1106  if (partition_recurse)
1107  {
1108  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1109  List *idxs = NIL;
1110  List *childTbls = NIL;
1111  ListCell *l;
1112  int i;
1113  MemoryContext oldcxt,
1114  perChildCxt;
1115 
1117  "part trig clone",
1119 
1120  /*
1121  * When a trigger is being created associated with an index, we'll
1122  * need to associate the trigger in each child partition with the
1123  * corresponding index on it.
1124  */
1125  if (OidIsValid(indexOid))
1126  {
1127  ListCell *l;
1128  List *idxs = NIL;
1129 
1131  foreach(l, idxs)
1132  childTbls = lappend_oid(childTbls,
1134  false));
1135  }
1136 
1137  oldcxt = MemoryContextSwitchTo(perChildCxt);
1138 
1139  /* Iterate to create the trigger on each existing partition */
1140  for (i = 0; i < partdesc->nparts; i++)
1141  {
1142  Oid indexOnChild = InvalidOid;
1143  ListCell *l2;
1144  CreateTrigStmt *childStmt;
1145  Relation childTbl;
1146  Node *qual;
1147  bool found_whole_row;
1148 
1149  childTbl = table_open(partdesc->oids[i], ShareRowExclusiveLock);
1150 
1151  /* Find which of the child indexes is the one on this partition */
1152  if (OidIsValid(indexOid))
1153  {
1154  forboth(l, idxs, l2, childTbls)
1155  {
1156  if (lfirst_oid(l2) == partdesc->oids[i])
1157  {
1158  indexOnChild = lfirst_oid(l);
1159  break;
1160  }
1161  }
1162  if (!OidIsValid(indexOnChild))
1163  elog(ERROR, "failed to find index matching index \"%s\" in partition \"%s\"",
1164  get_rel_name(indexOid),
1165  get_rel_name(partdesc->oids[i]));
1166  }
1167 
1168  /*
1169  * Initialize our fabricated parse node by copying the original
1170  * one, then resetting fields that we pass separately.
1171  */
1172  childStmt = (CreateTrigStmt *) copyObject(stmt);
1173  childStmt->funcname = NIL;
1174  childStmt->whenClause = NULL;
1175 
1176  /* If there is a WHEN clause, create a modified copy of it */
1177  qual = copyObject(whenClause);
1178  qual = (Node *)
1180  childTbl, rel,
1181  &found_whole_row);
1182  if (found_whole_row)
1183  elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
1184  qual = (Node *)
1186  childTbl, rel,
1187  &found_whole_row);
1188  if (found_whole_row)
1189  elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
1190 
1191  CreateTrigger(childStmt, queryString,
1192  partdesc->oids[i], refRelOid,
1193  InvalidOid, indexOnChild,
1194  funcoid, trigoid, qual,
1195  isInternal, true);
1196 
1197  table_close(childTbl, NoLock);
1198 
1199  MemoryContextReset(perChildCxt);
1200  }
1201 
1202  MemoryContextSwitchTo(oldcxt);
1203  MemoryContextDelete(perChildCxt);
1204  list_free(idxs);
1205  list_free(childTbls);
1206  }
1207 
1208  /* Keep lock on target rel until end of xact */
1209  table_close(rel, NoLock);
1210 
1211  return myself;
1212 }
signed short int16
Definition: c.h:346
#define NIL
Definition: pg_list.h:65
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:322
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3330
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:2862
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define TriggerOidIndexId
Definition: indexing.h:258
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:419
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool IsSystemRelation(Relation relation)
Definition: catalog.c:69
#define RelationGetDescr(relation)
Definition: rel.h:449
Oid GetUserId(void)
Definition: miscinit.c:380
#define PointerGetDatum(X)
Definition: postgres.h:556
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:63
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Node * whenClause
Definition: parsenodes.h:2417
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, 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, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:451
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:525
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:608
int namestrcmp(Name name, const char *str)
Definition: name.c:287
AttrNumber varattno
Definition: primnodes.h:172
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
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:1020
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:617
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:167
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
#define OidIsValid(objectId)
Definition: c.h:639
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:155
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1457
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
#define TriggerRelidNameIndexId
Definition: indexing.h:256
#define NAMEDATALEN
void assign_expr_collations(ParseState *pstate, Node *expr)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:385
RangeVar * constrrel
Definition: parsenodes.h:2424
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
void pfree(void *pointer)
Definition: mcxt.c:1056
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel, bool *found_whole_row)
Definition: partition.c:201
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2101
ItemPointerData t_self
Definition: htup.h:65
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:286
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:277
#define lfirst_node(type, lc)
Definition: pg_list.h:193
#define ACL_TRIGGER
Definition: parsenodes.h:80
int location
Definition: primnodes.h:182
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
#define CStringGetDatum(X)
Definition: postgres.h:578
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1586
#define RelationGetRelationName(relation)
Definition: rel.h:457
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
const char * p_sourcetext
Definition: parse_node.h:176
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:1242
List * transitionRels
Definition: parsenodes.h:2420
#define ereport(elevel, rest)
Definition: elog.h:141
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid rd_id
Definition: rel.h:85
#define PRS2_OLD_VARNO
Definition: primnodes.h:164
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:170
char * NameListToString(List *names)
Definition: namespace.c:3094
Definition: c.h:578
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1005
void SetFunctionReturnType(Oid funcOid, Oid newRetType)
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
TupleDesc rd_att
Definition: rel.h:84
#define BoolGetDatum(X)
Definition: postgres.h:402
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:68
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
int16 attnum
Definition: pg_attribute.h:79
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define Assert(condition)
Definition: c.h:733
#define lfirst(lc)
Definition: pg_list.h:190
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
bool relhastriggers
Definition: pg_class.h:99
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static int list_length(const List *l)
Definition: pg_list.h:169
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:71
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define CharGetDatum(X)
Definition: postgres.h:416
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4630
#define DatumGetPointer(X)
Definition: postgres.h:549
static Datum values[MAXATTR]
Definition: bootstrap.c:167
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define ACL_EXECUTE
Definition: parsenodes.h:81
void list_free(List *list)
Definition: list.c:1377
#define elog(elevel,...)
Definition: elog.h:228
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4654
int i
RangeVar * relation
Definition: parsenodes.h:2408
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:610
ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
Definition: trigger.c:162
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:83
char * nodeToString(const void *obj)
Definition: outfuncs.c:4316
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1306
#define copyObject(obj)
Definition: nodes.h:641
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RI_TRIGGER_NONE
Definition: trigger.h:272
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define snprintf
Definition: port.h:192
#define RelationGetRelid(relation)
Definition: rel.h:423
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define PRS2_NEW_VARNO
Definition: primnodes.h:165
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192
#define RelationGetPartitionDesc(relation)
Definition: rel.h:610
#define RelationGetNamespace(relation)
Definition: rel.h:464
List * p_rtable
Definition: parse_node.h:177

◆ EnableDisableTrigger()

void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system,
LOCKMODE  lockmode 
)

Definition at line 1806 of file trigger.c.

References BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CStringGetDatum, EnableDisableTrigger(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_copytuple(), heap_freetuple(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, NameStr, NoLock, PartitionDescData::nparts, ObjectIdGetDatum, PartitionDescData::oids, RelationData::rd_rel, relation_open(), RelationGetPartitionDesc, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and TriggerRelidNameIndexId.

Referenced by ATExecEnableDisableTrigger(), and EnableDisableTrigger().

1808 {
1809  Relation tgrel;
1810  int nkeys;
1811  ScanKeyData keys[2];
1812  SysScanDesc tgscan;
1813  HeapTuple tuple;
1814  bool found;
1815  bool changed;
1816 
1817  /* Scan the relevant entries in pg_triggers */
1818  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
1819 
1820  ScanKeyInit(&keys[0],
1821  Anum_pg_trigger_tgrelid,
1822  BTEqualStrategyNumber, F_OIDEQ,
1824  if (tgname)
1825  {
1826  ScanKeyInit(&keys[1],
1827  Anum_pg_trigger_tgname,
1828  BTEqualStrategyNumber, F_NAMEEQ,
1829  CStringGetDatum(tgname));
1830  nkeys = 2;
1831  }
1832  else
1833  nkeys = 1;
1834 
1835  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1836  NULL, nkeys, keys);
1837 
1838  found = changed = false;
1839 
1840  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1841  {
1842  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1843 
1844  if (oldtrig->tgisinternal)
1845  {
1846  /* system trigger ... ok to process? */
1847  if (skip_system)
1848  continue;
1849  if (!superuser())
1850  ereport(ERROR,
1851  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1852  errmsg("permission denied: \"%s\" is a system trigger",
1853  NameStr(oldtrig->tgname))));
1854  }
1855 
1856  found = true;
1857 
1858  if (oldtrig->tgenabled != fires_when)
1859  {
1860  /* need to change this one ... make a copy to scribble on */
1861  HeapTuple newtup = heap_copytuple(tuple);
1862  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1863 
1864  newtrig->tgenabled = fires_when;
1865 
1866  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1867 
1868  heap_freetuple(newtup);
1869 
1870  /*
1871  * When altering FOR EACH ROW triggers on a partitioned table, do
1872  * the same on the partitions as well.
1873  */
1874  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1875  (TRIGGER_FOR_ROW(oldtrig->tgtype)))
1876  {
1877  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1878  int i;
1879 
1880  for (i = 0; i < partdesc->nparts; i++)
1881  {
1882  Relation part;
1883 
1884  part = relation_open(partdesc->oids[i], lockmode);
1885  EnableDisableTrigger(part, NameStr(oldtrig->tgname),
1886  fires_when, skip_system, lockmode);
1887  table_close(part, NoLock); /* keep lock till commit */
1888  }
1889  }
1890 
1891  changed = true;
1892  }
1893 
1894  InvokeObjectPostAlterHook(TriggerRelationId,
1895  oldtrig->oid, 0);
1896  }
1897 
1898  systable_endscan(tgscan);
1899 
1900  table_close(tgrel, RowExclusiveLock);
1901 
1902  if (tgname && !found)
1903  ereport(ERROR,
1904  (errcode(ERRCODE_UNDEFINED_OBJECT),
1905  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1906  tgname, RelationGetRelationName(rel))));
1907 
1908  /*
1909  * If we changed anything, broadcast a SI inval message to force each
1910  * backend (including our own!) to rebuild relation's relcache entry.
1911  * Otherwise they will fail to apply the change promptly.
1912  */
1913  if (changed)
1915 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:608
bool superuser(void)
Definition: superuser.c:46
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
#define TriggerRelidNameIndexId
Definition: indexing.h:256
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
void EnableDisableTrigger(Relation rel, const char *tgname, char fires_when, bool skip_system, LOCKMODE lockmode)
Definition: trigger.c:1806
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define RelationGetRelationName(relation)
Definition: rel.h:457
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:71
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1270
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define NameStr(name)
Definition: c.h:610
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:423
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define RelationGetPartitionDesc(relation)
Definition: rel.h:610

◆ ExecARDeleteTriggers()

void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TransitionCaptureState transition_capture 
)

Definition at line 2847 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), GetTupleForTrigger(), HeapTupleIsValid, ItemPointerIsValid, LockTupleExclusive, NIL, ResultRelInfo::ri_TrigDesc, TransitionCaptureState::tcs_delete_old_table, TriggerDesc::trig_delete_after_row, and TRIGGER_EVENT_DELETE.

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2851 {
2852  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2853  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2854 
2855  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2856  (transition_capture && transition_capture->tcs_delete_old_table))
2857  {
2858  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2859  if (fdw_trigtuple == NULL)
2860  GetTupleForTrigger(estate,
2861  NULL,
2862  relinfo,
2863  tupleid,
2865  slot,
2866  NULL);
2867  else
2868  ExecForceStoreHeapTuple(fdw_trigtuple, slot, false);
2869 
2871  true, slot, NULL, NIL, NULL,
2872  transition_capture);
2873  }
2874 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define NIL
Definition: pg_list.h:65
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3308
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
bool trig_delete_after_row
Definition: reltrigger.h:66
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:733

◆ ExecARInsertTriggers()

void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2599 of file trigger.c.

References AfterTriggerSaveEvent(), ResultRelInfo::ri_TrigDesc, TransitionCaptureState::tcs_insert_new_table, TriggerDesc::trig_insert_after_row, and TRIGGER_EVENT_INSERT.

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

2602 {
2603  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2604 
2605  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2606  (transition_capture && transition_capture->tcs_insert_new_table))
2608  true, NULL, slot,
2609  recheckIndexes, NULL,
2610  transition_capture);
2611 }
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98

◆ ExecARUpdateTriggers()

void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TupleTableSlot slot,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 3134 of file trigger.c.

References AfterTriggerSaveEvent(), ExecClearTuple(), ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), GetAllUpdatedColumns, GetTupleForTrigger(), ItemPointerIsValid, LockTupleExclusive, ResultRelInfo::ri_TrigDesc, TransitionCaptureState::tcs_update_new_table, TransitionCaptureState::tcs_update_old_table, TriggerDesc::trig_update_after_row, and TRIGGER_EVENT_UPDATE.

Referenced by ExecDelete(), ExecInsert(), ExecSimpleRelationUpdate(), and ExecUpdate().

3140 {
3141  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3142  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3143 
3144  ExecClearTuple(oldslot);
3145 
3146  if ((trigdesc && trigdesc->trig_update_after_row) ||
3147  (transition_capture &&
3148  (transition_capture->tcs_update_old_table ||
3149  transition_capture->tcs_update_new_table)))
3150  {
3151  /*
3152  * Note: if the UPDATE is converted into a DELETE+INSERT as part of
3153  * update-partition-key operation, then this function is also called
3154  * separately for DELETE and INSERT to capture transition table rows.
3155  * In such case, either old tuple or new tuple can be NULL.
3156  */
3157  if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
3158  GetTupleForTrigger(estate,
3159  NULL,
3160  relinfo,
3161  tupleid,
3163  oldslot,
3164  NULL);
3165  else if (fdw_trigtuple != NULL)
3166  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
3167 
3169  true, oldslot, newslot, recheckIndexes,
3170  GetAllUpdatedColumns(relinfo, estate),
3171  transition_capture);
3172  }
3173 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3308
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
bool trig_update_after_row
Definition: reltrigger.h:61
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define GetAllUpdatedColumns(relinfo, estate)
Definition: trigger.c:78
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100

◆ ExecASDeleteTriggers()

void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2738 of file trigger.c.

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

Referenced by fireASTriggers().

2740 {
2741  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2742 
2743  if (trigdesc && trigdesc->trig_delete_after_statement)
2745  false, NULL, NULL, NIL, NULL, transition_capture);
2746 }
#define NIL
Definition: pg_list.h:65
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
bool trig_delete_after_statement
Definition: reltrigger.h:69

◆ ExecASInsertTriggers()

void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2521 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2523 {
2524  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2525 
2526  if (trigdesc && trigdesc->trig_insert_after_statement)
2528  false, NULL, NULL, NIL, NULL, transition_capture);
2529 }
#define NIL
Definition: pg_list.h:65
bool trig_insert_after_statement
Definition: reltrigger.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98

◆ ExecASTruncateTriggers()

void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3297 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

3298 {
3299  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3300 
3301  if (trigdesc && trigdesc->trig_truncate_after_statement)
3303  false, NULL, NULL, NIL, NULL, NULL);
3304 }
#define NIL
Definition: pg_list.h:65
bool trig_truncate_after_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101

◆ ExecASUpdateTriggers()

void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2990 of file trigger.c.

References AfterTriggerSaveEvent(), GetAllUpdatedColumns, NIL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_update_after_statement, and TRIGGER_EVENT_UPDATE.

Referenced by fireASTriggers().

2992 {
2993  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2994 
2995  if (trigdesc && trigdesc->trig_update_after_statement)
2997  false, NULL, NULL, NIL,
2998  GetAllUpdatedColumns(relinfo, estate),
2999  transition_capture);
3000 }
#define NIL
Definition: pg_list.h:65
bool trig_update_after_statement
Definition: reltrigger.h:64
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5707
#define GetAllUpdatedColumns(relinfo, estate)
Definition: trigger.c:78
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100

◆ ExecBRDeleteTriggers()

bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TupleTableSlot **  epqslot 
)

Definition at line 2756 of file trigger.c.

References Assert, ExecCallTriggerFunc(), ExecFetchSlotHeapTuple(), ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), GetPerTupleMemoryContext, GetTupleForTrigger(), heap_freetuple(), HeapTupleIsValid, i, ItemPointerIsValid, LockTupleExclusive, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_DELETE, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2761 {
2762  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2763  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2764  bool result = true;
2765  TriggerData LocTriggerData;
2766  HeapTuple trigtuple;
2767  bool should_free = false;
2768  int i;
2769 
2770  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2771  if (fdw_trigtuple == NULL)
2772  {
2773  TupleTableSlot *epqslot_candidate = NULL;
2774 
2775  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2776  LockTupleExclusive, slot, &epqslot_candidate))
2777  return false;
2778 
2779  /*
2780  * If the tuple was concurrently updated and the caller of this
2781  * function requested for the updated tuple, skip the trigger
2782  * execution.
2783  */
2784  if (epqslot_candidate != NULL && epqslot != NULL)
2785  {
2786  *epqslot = epqslot_candidate;
2787  return false;
2788  }
2789 
2790  trigtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2791 
2792  }
2793  else
2794  {
2795  trigtuple = fdw_trigtuple;
2796  ExecForceStoreHeapTuple(trigtuple, slot, false);
2797  }
2798 
2799  LocTriggerData.type = T_TriggerData;
2800  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2803  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2804  LocTriggerData.tg_trigtuple = NULL;
2805  LocTriggerData.tg_newtuple = NULL;
2806  LocTriggerData.tg_trigslot = NULL;
2807  LocTriggerData.tg_newslot = NULL;
2808  LocTriggerData.tg_oldtable = NULL;
2809  LocTriggerData.tg_newtable = NULL;
2810  for (i = 0; i < trigdesc->numtriggers; i++)
2811  {
2812  HeapTuple newtuple;
2813  Trigger *trigger = &trigdesc->triggers[i];
2814 
2815  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2816  TRIGGER_TYPE_ROW,
2817  TRIGGER_TYPE_BEFORE,
2818  TRIGGER_TYPE_DELETE))
2819  continue;
2820  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2821  NULL, slot, NULL))
2822  continue;
2823 
2824  LocTriggerData.tg_trigslot = slot;
2825  LocTriggerData.tg_trigtuple = trigtuple;
2826  LocTriggerData.tg_trigger = trigger;
2827  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2828  i,
2829  relinfo->ri_TrigFunctions,
2830  relinfo->ri_TrigInstrument,
2831  GetPerTupleMemoryContext(estate));
2832  if (newtuple == NULL)
2833  {
2834  result = false; /* tell caller to suppress delete */
2835  break;
2836  }
2837  if (newtuple != trigtuple)
2838  heap_freetuple(newtuple);
2839  }
2840  if (should_free)
2841  heap_freetuple(trigtuple);
2842 
2843  return result;
2844 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3308
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:733
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRInsertTriggers()

bool ExecBRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

Definition at line 2532 of file trigger.c.

References ExecCallTriggerFunc(), ExecFetchSlotHeapTuple(), ExecForceStoreHeapTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

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

2534 {
2535  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2536  HeapTuple newtuple = false;
2537  bool should_free;
2538  TriggerData LocTriggerData;
2539  int i;
2540 
2541  LocTriggerData.type = T_TriggerData;
2542  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2545  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2546  LocTriggerData.tg_trigtuple = NULL;
2547  LocTriggerData.tg_newtuple = NULL;
2548  LocTriggerData.tg_trigslot = NULL;
2549  LocTriggerData.tg_newslot = NULL;
2550  LocTriggerData.tg_oldtable = NULL;
2551  LocTriggerData.tg_newtable = NULL;
2552  for (i = 0; i < trigdesc->numtriggers; i++)
2553  {
2554  Trigger *trigger = &trigdesc->triggers[i];
2555  HeapTuple oldtuple;
2556 
2557  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2558  TRIGGER_TYPE_ROW,
2559  TRIGGER_TYPE_BEFORE,
2560  TRIGGER_TYPE_INSERT))
2561  continue;
2562  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2563  NULL, NULL, slot))
2564  continue;
2565 
2566  if (!newtuple)
2567  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2568 
2569  LocTriggerData.tg_trigslot = slot;
2570  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2571  LocTriggerData.tg_trigger = trigger;
2572  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2573  i,
2574  relinfo->ri_TrigFunctions,
2575  relinfo->ri_TrigInstrument,
2576  GetPerTupleMemoryContext(estate));
2577  if (newtuple == NULL)
2578  {
2579  if (should_free)
2580  heap_freetuple(oldtuple);
2581  return false; /* "do nothing" */
2582  }
2583  else if (newtuple != oldtuple)
2584  {
2585  ExecForceStoreHeapTuple(newtuple, slot, false);
2586 
2587  if (should_free)
2588  heap_freetuple(oldtuple);
2589 
2590  /* signal tuple should be re-fetched if used */
2591  newtuple = NULL;
2592  }
2593  }
2594 
2595  return true;
2596 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRUpdateTriggers()

bool ExecBRUpdateTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TupleTableSlot slot 
)

Definition at line 3003 of file trigger.c.

References Assert, ExecCallTriggerFunc(), ExecCopySlot(), ExecFetchSlotHeapTuple(), ExecFilterJunk(), ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), ExecMaterializeSlot(), ExecUpdateLockMode(), GetAllUpdatedColumns, GetPerTupleMemoryContext, GetTupleForTrigger(), heap_freetuple(), HeapTupleIsValid, i, ItemPointerIsValid, TriggerDesc::numtriggers, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

3008 {
3009  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3010  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3011  HeapTuple newtuple = NULL;
3012  HeapTuple trigtuple;
3013  bool should_free_trig = false;
3014  bool should_free_new = false;
3015  TriggerData LocTriggerData;
3016  int i;
3017  Bitmapset *updatedCols;
3018  LockTupleMode lockmode;
3019 
3020  /* Determine lock mode to use */
3021  lockmode = ExecUpdateLockMode(estate, relinfo);
3022 
3023  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
3024  if (fdw_trigtuple == NULL)
3025  {
3026  TupleTableSlot *epqslot_candidate = NULL;
3027 
3028  /* get a copy of the on-disk tuple we are planning to update */
3029  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
3030  lockmode, oldslot, &epqslot_candidate))
3031  return false; /* cancel the update action */
3032 
3033  /*
3034  * In READ COMMITTED isolation level it's possible that target tuple
3035  * was changed due to concurrent update. In that case we have a raw
3036  * subplan output tuple in newSlot, and need to run it through the
3037  * junk filter to produce an insertable tuple.
3038  *
3039  * Caution: more than likely, the passed-in slot is the same as the
3040  * junkfilter's output slot, so we are clobbering the original value
3041  * of slottuple by doing the filtering. This is OK since neither we
3042  * nor our caller have any more interest in the prior contents of that
3043  * slot.
3044  */
3045  if (epqslot_candidate != NULL)
3046  {
3047  TupleTableSlot *epqslot_clean;
3048 
3049  epqslot_clean = ExecFilterJunk(relinfo->ri_junkFilter, epqslot_candidate);
3050 
3051  if (newslot != epqslot_clean)
3052  ExecCopySlot(newslot, epqslot_clean);
3053  }
3054 
3055  trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
3056  }
3057  else
3058  {
3059  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
3060  trigtuple = fdw_trigtuple;
3061  }
3062 
3063  LocTriggerData.type = T_TriggerData;
3064  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3067  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3068  LocTriggerData.tg_oldtable = NULL;
3069  LocTriggerData.tg_newtable = NULL;
3070  updatedCols = GetAllUpdatedColumns(relinfo, estate);
3071  for (i = 0; i < trigdesc->numtriggers; i++)
3072  {
3073  Trigger *trigger = &trigdesc->triggers[i];
3074  HeapTuple oldtuple;
3075 
3076  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3077  TRIGGER_TYPE_ROW,
3078  TRIGGER_TYPE_BEFORE,
3079  TRIGGER_TYPE_UPDATE))
3080  continue;
3081  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3082  updatedCols, oldslot, newslot))
3083  continue;
3084 
3085  if (!newtuple)
3086  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free_new);
3087 
3088  LocTriggerData.tg_trigslot = oldslot;
3089  LocTriggerData.tg_trigtuple = trigtuple;
3090  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3091  LocTriggerData.tg_newslot = newslot;
3092  LocTriggerData.tg_trigger = trigger;
3093  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3094  i,
3095  relinfo->ri_TrigFunctions,
3096  relinfo->ri_TrigInstrument,
3097  GetPerTupleMemoryContext(estate));
3098 
3099  if (newtuple == NULL)
3100  {
3101  if (should_free_trig)
3102  heap_freetuple(trigtuple);
3103  if (should_free_new)
3104  heap_freetuple(oldtuple);
3105  return false; /* "do nothing" */
3106  }
3107  else if (newtuple != oldtuple)
3108  {
3109  ExecForceStoreHeapTuple(newtuple, newslot, false);
3110 
3111  /*
3112  * If the tuple returned by the trigger / being stored, is the old
3113  * row version, and the heap tuple passed to the trigger was
3114  * allocated locally, materialize the slot. Otherwise we might
3115  * free it while still referenced by the slot.
3116  */
3117  if (should_free_trig && newtuple == trigtuple)
3118  ExecMaterializeSlot(newslot);
3119 
3120  if (should_free_new)
3121  heap_freetuple(oldtuple);
3122 
3123  /* signal tuple should be re-fetched if used */
3124  newtuple = NULL;
3125  }
3126  }
3127  if (should_free_trig)
3128  heap_freetuple(trigtuple);
3129 
3130  return true;
3131 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:475
JunkFilter * ri_junkFilter
Definition: execnodes.h:461
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
LockTupleMode
Definition: lockoptions.h:49
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3308
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:261
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:733
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2320
#define GetAllUpdatedColumns(relinfo, estate)
Definition: trigger.c:78
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSDeleteTriggers()

void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2681 of file trigger.c.

References before_stmt_triggers_fired(), CMD_DELETE, ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, TriggerDesc::numtriggers, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TriggerDesc::trig_delete_before_statement, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_DELETE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by fireBSTriggers().

2682 {
2683  TriggerDesc *trigdesc;
2684  int i;
2685  TriggerData LocTriggerData;
2686 
2687  trigdesc = relinfo->ri_TrigDesc;
2688 
2689  if (trigdesc == NULL)
2690  return;
2691  if (!trigdesc->trig_delete_before_statement)
2692  return;
2693 
2694  /* no-op if we already fired BS triggers in this context */
2696  CMD_DELETE))
2697  return;
2698 
2699  LocTriggerData.type = T_TriggerData;
2700  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2702  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2703  LocTriggerData.tg_trigtuple = NULL;
2704  LocTriggerData.tg_newtuple = NULL;
2705  LocTriggerData.tg_trigslot = NULL;
2706  LocTriggerData.tg_newslot = NULL;
2707  LocTriggerData.tg_oldtable = NULL;
2708  LocTriggerData.tg_newtable = NULL;
2709  for (i = 0; i < trigdesc->numtriggers; i++)
2710  {
2711  Trigger *trigger = &trigdesc->triggers[i];
2712  HeapTuple newtuple;
2713 
2714  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2715  TRIGGER_TYPE_STATEMENT,
2716  TRIGGER_TYPE_BEFORE,
2717  TRIGGER_TYPE_DELETE))
2718  continue;
2719  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2720  NULL, NULL, NULL))
2721  continue;
2722 
2723  LocTriggerData.tg_trigger = trigger;
2724  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2725  i,
2726  relinfo->ri_TrigFunctions,
2727  relinfo->ri_TrigInstrument,
2728  GetPerTupleMemoryContext(estate));
2729 
2730  if (newtuple)
2731  ereport(ERROR,
2732  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2733  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2734  }
2735 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:6039
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
bool trig_delete_before_statement
Definition: reltrigger.h:68
TupleTableSlot * tg_newslot
Definition: trigger.h:39
#define ereport(elevel, rest)
Definition: elog.h:141
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
int errmsg(const char *fmt,...)
Definition: elog.c:822
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
#define RelationGetRelid(relation)
Definition: rel.h:423
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSInsertTriggers()

void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2464 of file trigger.c.

References before_stmt_triggers_fired(), CMD_INSERT, ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, TriggerDesc::numtriggers, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TriggerDesc::trig_insert_before_statement, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_INSERT, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by CopyFrom(), and fireBSTriggers().

2465 {
2466  TriggerDesc *trigdesc;
2467  int i;
2468  TriggerData LocTriggerData;
2469 
2470  trigdesc = relinfo->ri_TrigDesc;
2471 
2472  if (trigdesc == NULL)
2473  return;
2474  if (!trigdesc->trig_insert_before_statement)
2475  return;
2476 
2477  /* no-op if we already fired BS triggers in this context */
2479  CMD_INSERT))
2480  return;
2481 
2482  LocTriggerData.type = T_TriggerData;
2483  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2485  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2486  LocTriggerData.tg_trigtuple = NULL;
2487  LocTriggerData.tg_newtuple = NULL;
2488  LocTriggerData.tg_trigslot = NULL;
2489  LocTriggerData.tg_newslot = NULL;
2490  LocTriggerData.tg_oldtable = NULL;
2491  LocTriggerData.tg_newtable = NULL;
2492  for (i = 0; i < trigdesc->numtriggers; i++)
2493  {
2494  Trigger *trigger = &trigdesc->triggers[i];
2495  HeapTuple newtuple;
2496 
2497  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2498  TRIGGER_TYPE_STATEMENT,
2499  TRIGGER_TYPE_BEFORE,
2500  TRIGGER_TYPE_INSERT))
2501  continue;
2502  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2503  NULL, NULL, NULL))
2504  continue;
2505 
2506  LocTriggerData.tg_trigger = trigger;
2507  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2508  i,
2509  relinfo->ri_TrigFunctions,
2510  relinfo->ri_TrigInstrument,
2511  GetPerTupleMemoryContext(estate));
2512 
2513  if (newtuple)
2514  ereport(ERROR,
2515  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2516  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2517  }
2518 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:6039
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
#define ereport(elevel, rest)
Definition: elog.h:141
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
bool trig_insert_before_statement
Definition: reltrigger.h:58
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
int errmsg(const char *fmt,...)
Definition: elog.c:822
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
#define RelationGetRelid(relation)
Definition: rel.h:423
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSTruncateTriggers()

void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3244 of file trigger.c.

References ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TriggerDesc::trig_truncate_before_statement, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_TRUNCATE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecuteTruncateGuts().

3245 {
3246  TriggerDesc *trigdesc;
3247  int i;
3248  TriggerData LocTriggerData;
3249 
3250  trigdesc = relinfo->ri_TrigDesc;
3251 
3252  if (trigdesc == NULL)
3253  return;
3254  if (!trigdesc->trig_truncate_before_statement)
3255  return;
3256 
3257  LocTriggerData.type = T_TriggerData;
3258  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
3260  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3261  LocTriggerData.tg_trigtuple = NULL;
3262  LocTriggerData.tg_newtuple = NULL;
3263  LocTriggerData.tg_trigslot = NULL;
3264  LocTriggerData.tg_newslot = NULL;
3265  LocTriggerData.tg_oldtable = NULL;
3266  LocTriggerData.tg_newtable = NULL;
3267 
3268  for (i = 0; i < trigdesc->numtriggers; i++)
3269  {
3270  Trigger *trigger = &trigdesc->triggers[i];
3271  HeapTuple newtuple;
3272 
3273  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3274  TRIGGER_TYPE_STATEMENT,
3275  TRIGGER_TYPE_BEFORE,
3276  TRIGGER_TYPE_TRUNCATE))
3277  continue;
3278  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3279  NULL, NULL, NULL))
3280  continue;
3281 
3282  LocTriggerData.tg_trigger = trigger;
3283  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3284  i,
3285  relinfo->ri_TrigFunctions,
3286  relinfo->ri_TrigInstrument,
3287  GetPerTupleMemoryContext(estate));
3288 
3289  if (newtuple)
3290  ereport(ERROR,
3291  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3292  errmsg("BEFORE STATEMENT trigger cannot return a value")));
3293  }
3294 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
int errcode(int sqlerrcode)
Definition: elog.c:608
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
bool trig_truncate_before_statement
Definition: reltrigger.h:71
TupleTableSlot * tg_newslot
Definition: trigger.h:39
#define ereport(elevel, rest)
Definition: elog.h:141
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
int errmsg(const char *fmt,...)
Definition: elog.c:822
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSUpdateTriggers()

void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2930 of file trigger.c.

References before_stmt_triggers_fired(), CMD_UPDATE, ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetAllUpdatedColumns, GetPerTupleMemoryContext, i, TriggerDesc::numtriggers, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TriggerDesc::trig_update_before_statement, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by fireBSTriggers().

2931 {
2932  TriggerDesc *trigdesc;
2933  int i;
2934  TriggerData LocTriggerData;
2935  Bitmapset *updatedCols;
2936 
2937  trigdesc = relinfo->ri_TrigDesc;
2938 
2939  if (trigdesc == NULL)
2940  return;
2941  if (!trigdesc->trig_update_before_statement)
2942  return;
2943 
2944  /* no-op if we already fired BS triggers in this context */
2946  CMD_UPDATE))
2947  return;
2948 
2949  updatedCols = GetAllUpdatedColumns(relinfo, estate);
2950 
2951  LocTriggerData.type = T_TriggerData;
2952  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2954  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2955  LocTriggerData.tg_trigtuple = NULL;
2956  LocTriggerData.tg_newtuple = NULL;
2957  LocTriggerData.tg_trigslot = NULL;
2958  LocTriggerData.tg_newslot = NULL;
2959  LocTriggerData.tg_oldtable = NULL;
2960  LocTriggerData.tg_newtable = NULL;
2961  for (i = 0; i < trigdesc->numtriggers; i++)
2962  {
2963  Trigger *trigger = &trigdesc->triggers[i];
2964  HeapTuple newtuple;
2965 
2966  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2967  TRIGGER_TYPE_STATEMENT,
2968  TRIGGER_TYPE_BEFORE,
2969  TRIGGER_TYPE_UPDATE))
2970  continue;
2971  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2972  updatedCols, NULL, NULL))
2973  continue;
2974 
2975  LocTriggerData.tg_trigger = trigger;
2976  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2977  i,
2978  relinfo->ri_TrigFunctions,
2979  relinfo->ri_TrigInstrument,
2980  GetPerTupleMemoryContext(estate));
2981 
2982  if (newtuple)
2983  ereport(ERROR,
2984  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2985  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2986  }
2987 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
int errcode(int sqlerrcode)
Definition: elog.c:608
bool trig_update_before_statement
Definition: reltrigger.h:63
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:6039
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
#define ereport(elevel, rest)
Definition: elog.h:141
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
#define GetAllUpdatedColumns(relinfo, estate)
Definition: trigger.c:78
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
int errmsg(const char *fmt,...)
Definition: elog.c:822
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
#define RelationGetRelid(relation)
Definition: rel.h:423
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRDeleteTriggers()

bool ExecIRDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple 
)

Definition at line 2877 of file trigger.c.

References ExecCallTriggerFunc(), ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), GetPerTupleMemoryContext, heap_freetuple(), i, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_DELETE, TRIGGER_EVENT_INSTEAD, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecDelete().

2879 {
2880  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2881  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2882  TriggerData LocTriggerData;
2883  int i;
2884 
2885  LocTriggerData.type = T_TriggerData;
2886  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2889  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2890  LocTriggerData.tg_trigtuple = NULL;
2891  LocTriggerData.tg_newtuple = NULL;
2892  LocTriggerData.tg_trigslot = NULL;
2893  LocTriggerData.tg_newslot = NULL;
2894  LocTriggerData.tg_oldtable = NULL;
2895  LocTriggerData.tg_newtable = NULL;
2896 
2897  ExecForceStoreHeapTuple(trigtuple, slot, false);
2898 
2899  for (i = 0; i < trigdesc->numtriggers; i++)
2900  {
2901  HeapTuple rettuple;
2902  Trigger *trigger = &trigdesc->triggers[i];
2903 
2904  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2905  TRIGGER_TYPE_ROW,
2906  TRIGGER_TYPE_INSTEAD,
2907  TRIGGER_TYPE_DELETE))
2908  continue;
2909  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2910  NULL, slot, NULL))
2911  continue;
2912 
2913  LocTriggerData.tg_trigslot = slot;
2914  LocTriggerData.tg_trigtuple = trigtuple;
2915  LocTriggerData.tg_trigger = trigger;
2916  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2917  i,
2918  relinfo->ri_TrigFunctions,
2919  relinfo->ri_TrigInstrument,
2920  GetPerTupleMemoryContext(estate));
2921  if (rettuple == NULL)
2922  return false; /* Delete was suppressed */
2923  if (rettuple != trigtuple)
2924  heap_freetuple(rettuple);
2925  }
2926  return true;
2927 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRInsertTriggers()

bool ExecIRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

Definition at line 2614 of file trigger.c.

References ExecCallTriggerFunc(), ExecFetchSlotHeapTuple(), ExecForceStoreHeapTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_INSTEAD, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by CopyFrom(), and ExecInsert().

2616 {
2617  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2618  HeapTuple newtuple = NULL;
2619  bool should_free;
2620  TriggerData LocTriggerData;
2621  int i;
2622 
2623  LocTriggerData.type = T_TriggerData;
2624  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2627  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2628  LocTriggerData.tg_trigtuple = NULL;
2629  LocTriggerData.tg_newtuple = NULL;
2630  LocTriggerData.tg_trigslot = NULL;
2631  LocTriggerData.tg_newslot = NULL;
2632  LocTriggerData.tg_oldtable = NULL;
2633  LocTriggerData.tg_newtable = NULL;
2634  for (i = 0; i < trigdesc->numtriggers; i++)
2635  {
2636  Trigger *trigger = &trigdesc->triggers[i];
2637  HeapTuple oldtuple;
2638 
2639  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2640  TRIGGER_TYPE_ROW,
2641  TRIGGER_TYPE_INSTEAD,
2642  TRIGGER_TYPE_INSERT))
2643  continue;
2644  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2645  NULL, NULL, slot))
2646  continue;
2647 
2648  if (!newtuple)
2649  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2650 
2651  LocTriggerData.tg_trigslot = slot;
2652  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2653  LocTriggerData.tg_trigger = trigger;
2654  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2655  i,
2656  relinfo->ri_TrigFunctions,
2657  relinfo->ri_TrigInstrument,
2658  GetPerTupleMemoryContext(estate));
2659  if (newtuple == NULL)
2660  {
2661  if (should_free)
2662  heap_freetuple(oldtuple);
2663  return false; /* "do nothing" */
2664  }
2665  else if (newtuple != oldtuple)
2666  {
2667  ExecForceStoreHeapTuple(newtuple, slot, false);
2668 
2669  if (should_free)
2670  heap_freetuple(oldtuple);
2671 
2672  /* signal tuple should be re-fetched if used */
2673  newtuple = NULL;
2674  }
2675  }
2676 
2677  return true;
2678 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRUpdateTriggers()

bool ExecIRUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
TupleTableSlot slot 
)

Definition at line 3176 of file trigger.c.

References ExecCallTriggerFunc(), ExecFetchSlotHeapTuple(), ExecForceStoreHeapTuple(), ExecGetTriggerOldSlot(), GetPerTupleMemoryContext, heap_freetuple(), i, TriggerDesc::numtriggers, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newslot, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgtype, TRIGGER_EVENT_INSTEAD, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by ExecUpdate().

3178 {
3179  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3180  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3181  HeapTuple newtuple = false;
3182  bool should_free;
3183  TriggerData LocTriggerData;
3184  int i;
3185 
3186  LocTriggerData.type = T_TriggerData;
3187  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3190  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3191  LocTriggerData.tg_oldtable = NULL;
3192  LocTriggerData.tg_newtable = NULL;
3193 
3194  ExecForceStoreHeapTuple(trigtuple, oldslot, false);
3195 
3196  for (i = 0; i < trigdesc->numtriggers; i++)
3197  {
3198  Trigger *trigger = &trigdesc->triggers[i];
3199  HeapTuple oldtuple;
3200 
3201  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3202  TRIGGER_TYPE_ROW,
3203  TRIGGER_TYPE_INSTEAD,
3204  TRIGGER_TYPE_UPDATE))
3205  continue;
3206  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3207  NULL, oldslot, newslot))
3208  continue;
3209 
3210  if (!newtuple)
3211  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free);
3212 
3213  LocTriggerData.tg_trigslot = oldslot;
3214  LocTriggerData.tg_trigtuple = trigtuple;
3215  LocTriggerData.tg_newslot = newslot;
3216  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3217 
3218  LocTriggerData.tg_trigger = trigger;
3219  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3220  i,
3221  relinfo->ri_TrigFunctions,
3222  relinfo->ri_TrigInstrument,
3223  GetPerTupleMemoryContext(estate));
3224  if (newtuple == NULL)
3225  {
3226  return false; /* "do nothing" */
3227  }
3228  else if (newtuple != oldtuple)
3229  {
3230  ExecForceStoreHeapTuple(newtuple, newslot, false);
3231 
3232  if (should_free)
3233  heap_freetuple(oldtuple);
3234 
3235  /* signal tuple should be re-fetched if used */
3236  newtuple = NULL;
3237  }
3238  }
3239 
3240  return true;
3241 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3424
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:432
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1104
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1614
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2372
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:426
Relation tg_relation
Definition: trigger.h:34

◆ FindTriggerIncompatibleWithInheritance()

const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2342 of file trigger.c.

References i, TriggerDesc::numtriggers, Trigger::tgname, Trigger::tgnewtable, Trigger::tgoldtable, and TriggerDesc::triggers.

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2343 {
2344  if (trigdesc != NULL)
2345  {
2346  int i;
2347 
2348  for (i = 0; i < trigdesc->numtriggers; ++i)
2349  {
2350  Trigger *trigger = &trigdesc->triggers[i];
2351 
2352  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2353  return trigger->tgname;
2354  }
2355  }
2356 
2357  return NULL;
2358 }
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char * tgnewtable
Definition: reltrigger.h:43
int i
char * tgoldtable
Definition: reltrigger.h:42

◆ FreeTriggerDesc()

void FreeTriggerDesc ( TriggerDesc trigdesc)

Definition at line 2212 of file trigger.c.

References i, TriggerDesc::numtriggers, pfree(), Trigger::tgargs, Trigger::tgattr, Trigger::tgconstraint, Trigger::tgconstrindid, Trigger::tgconstrrelid, Trigger::tgdeferrable, Trigger::tgenabled, Trigger::tgfoid, Trigger::tginitdeferred, Trigger::tgisinternal, Trigger::tgname, Trigger::tgnargs, Trigger::tgnattr, Trigger::tgnewtable, Trigger::tgoid, Trigger::tgoldtable, Trigger::tgqual, Trigger::tgtype, and TriggerDesc::triggers.

Referenced by RelationBuildTriggers(), and RelationDestroyRelation().

2213 {
2214  Trigger *trigger;
2215  int i;
2216 
2217  if (trigdesc == NULL)
2218  return;
2219 
2220  trigger = trigdesc->triggers;
2221  for (i = 0; i < trigdesc->numtriggers; i++)
2222  {
2223  pfree(trigger->tgname);
2224  if (trigger->tgnattr > 0)
2225  pfree(trigger->tgattr);
2226  if (trigger->tgnargs > 0)
2227  {
2228  while (--(trigger->tgnargs) >= 0)
2229  pfree(trigger->tgargs[trigger->tgnargs]);
2230  pfree(trigger->tgargs);
2231  }
2232  if (trigger->tgqual)
2233  pfree(trigger->tgqual);
2234  if (trigger->tgoldtable)
2235  pfree(trigger->tgoldtable);
2236  if (trigger->tgnewtable)
2237  pfree(trigger->tgnewtable);
2238  trigger++;
2239  }
2240  pfree(trigdesc->triggers);
2241  pfree(trigdesc);
2242 }
void pfree(void *pointer)
Definition: mcxt.c:1056
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
int16 tgnattr
Definition: reltrigger.h:38
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42

◆ get_trigger_oid()

Oid get_trigger_oid ( Oid  relid,
const char *  name,
bool  missing_ok 
)

Definition at line 1576 of file trigger.c.

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_rel_name(), GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TriggerRelidNameIndexId.

Referenced by get_object_address_relobject().

1577 {
1578  Relation tgrel;
1579  ScanKeyData skey[2];
1580  SysScanDesc tgscan;
1581  HeapTuple tup;
1582  Oid oid;
1583 
1584  /*
1585  * Find the trigger, verify permissions, set up object address
1586  */
1587  tgrel = table_open(TriggerRelationId, AccessShareLock);
1588 
1589  ScanKeyInit(&skey[0],
1590  Anum_pg_trigger_tgrelid,
1591  BTEqualStrategyNumber, F_OIDEQ,
1592  ObjectIdGetDatum(relid));
1593  ScanKeyInit(&skey[1],
1594  Anum_pg_trigger_tgname,
1595  BTEqualStrategyNumber, F_NAMEEQ,
1596  CStringGetDatum(trigname));
1597 
1598  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1599  NULL, 2, skey);
1600 
1601  tup = systable_getnext(tgscan);
1602 
1603  if (!HeapTupleIsValid(tup))
1604  {
1605  if (!missing_ok)
1606  ereport(ERROR,
1607  (errcode(ERRCODE_UNDEFINED_OBJECT),
1608  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1609  trigname, get_rel_name(relid))));
1610  oid = InvalidOid;
1611  }
1612  else
1613  {
1614  oid = ((Form_pg_trigger) GETSTRUCT(tup))->oid;
1615  }
1616 
1617  systable_endscan(tgscan);
1618  table_close(tgrel, AccessShareLock);
1619  return oid;
1620 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
#define TriggerRelidNameIndexId
Definition: indexing.h:256
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:71
int errmsg(const char *fmt,...)
Definition: elog.c:822
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ MakeTransitionCaptureState()

TransitionCaptureState* MakeTransitionCaptureState ( TriggerDesc trigdesc,
Oid  relid,
CmdType  cmdType 
)

Definition at line 4660 of file trigger.c.

References AfterTriggerEnlargeQueryState(), CMD_DELETE, CMD_INSERT, CMD_UPDATE, CurrentResourceOwner, CurTransactionContext, CurTransactionResourceOwner, elog, ERROR, GetAfterTriggersTableData(), AfterTriggersData::maxquerydepth, MemoryContextSwitchTo(), AfterTriggersTableData::new_tuplestore, AfterTriggersTableData::old_tuplestore, palloc0(), AfterTriggersData::query_depth, TransitionCaptureState::tcs_delete_old_table, TransitionCaptureState::tcs_insert_new_table, TransitionCaptureState::tcs_private, TransitionCaptureState::tcs_update_new_table, TransitionCaptureState::tcs_update_old_table, TriggerDesc::trig_delete_old_table, TriggerDesc::trig_insert_new_table, TriggerDesc::trig_update_new_table, TriggerDesc::trig_update_old_table, tuplestore_begin_heap(), and work_mem.

Referenced by CopyFrom(), and ExecSetupTransitionCaptureState().

4661 {
4663  bool need_old,
4664  need_new;
4665  AfterTriggersTableData *table;
4666  MemoryContext oldcxt;
4667  ResourceOwner saveResourceOwner;
4668 
4669  if (trigdesc == NULL)
4670  return NULL;
4671 
4672  /* Detect which table(s) we need. */
4673  switch (cmdType)
4674  {
4675  case CMD_INSERT:
4676  need_old = false;
4677  need_new = trigdesc->trig_insert_new_table;
4678  break;
4679  case CMD_UPDATE:
4680  need_old = trigdesc->trig_update_old_table;
4681  need_new = trigdesc->trig_update_new_table;
4682  break;
4683  case CMD_DELETE:
4684  need_old = trigdesc->trig_delete_old_table;
4685  need_new = false;
4686  break;
4687  default:
4688  elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
4689  need_old = need_new = false; /* keep compiler quiet */
4690  break;
4691  }
4692  if (!need_old && !need_new)
4693  return NULL;
4694 
4695  /* Check state, like AfterTriggerSaveEvent. */
4696  if (afterTriggers.query_depth < 0)
4697  elog(ERROR, "MakeTransitionCaptureState() called outside of query");
4698 
4699  /* Be sure we have enough space to record events at this query depth. */
4702 
4703  /*
4704  * Find or create an AfterTriggersTableData struct to hold the
4705  * tuplestore(s). If there's a matching struct but it's marked closed,
4706  * ignore it; we need a newer one.
4707  *
4708  * Note: the AfterTriggersTableData list, as well as the tuplestores, are
4709  * allocated in the current (sub)transaction's CurTransactionContext, and
4710  * the tuplestores are managed by the (sub)transaction's resource owner.
4711  * This is sufficient lifespan because we do not allow triggers using
4712  * transition tables to be deferrable; they will be fired during
4713  * AfterTriggerEndQuery, after which it's okay to delete the data.
4714  */
4715  table = GetAfterTriggersTableData(relid, cmdType);
4716 
4717  /* Now create required tuplestore(s), if we don't have them already. */
4719  saveResourceOwner = CurrentResourceOwner;
4721 
4722  if (need_old && table->old_tuplestore == NULL)
4723  table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4724  if (need_new && table->new_tuplestore == NULL)
4725  table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4726 
4727  CurrentResourceOwner = saveResourceOwner;
4728  MemoryContextSwitchTo(oldcxt);
4729 
4730  /* Now build the TransitionCaptureState struct, in caller's context */
4732  state->tcs_delete_old_table = trigdesc->trig_delete_old_table;
4733  state->tcs_update_old_table = trigdesc->trig_update_old_table;
4734  state->tcs_update_new_table = trigdesc->trig_update_new_table;
4735  state->tcs_insert_new_table = trigdesc->trig_insert_new_table;
4736  state->tcs_private = table;
4737 
4738  return state;
4739 }