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

References AfterTriggersData::query_depth.

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

4786 {
4787  /* Increase the query stack depth */
4789 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3834

◆ AfterTriggerBeginSubXact()

void AfterTriggerBeginSubXact ( void  )

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

5054 {
5055  int my_level = GetCurrentTransactionNestLevel();
5056 
5057  /*
5058  * Allocate more space in the trans_stack if needed. (Note: because the
5059  * minimum nest level of a subtransaction is 2, we waste the first couple
5060  * entries of the array; not worth the notational effort to avoid it.)
5061  */
5062  while (my_level >= afterTriggers.maxtransdepth)
5063  {
5064  if (afterTriggers.maxtransdepth == 0)
5065  {
5066  /* Arbitrarily initialize for max of 8 subtransaction levels */
5069  8 * sizeof(AfterTriggersTransData));
5071  }
5072  else
5073  {
5074  /* repalloc will keep the stack in the same context */
5075  int new_alloc = afterTriggers.maxtransdepth * 2;
5076 
5079  new_alloc * sizeof(AfterTriggersTransData));
5080  afterTriggers.maxtransdepth = new_alloc;
5081  }
5082  }
5083 
5084  /*
5085  * Push the current information into the stack. The SET CONSTRAINTS state
5086  * is not saved until/unless changed. Likewise, we don't make a
5087  * per-subtransaction event context until needed.
5088  */
5089  afterTriggers.trans_stack[my_level].state = NULL;
5093 }
AfterTriggersTransData * trans_stack
Definition: trigger.c:3800
MemoryContext TopTransactionContext
Definition: mcxt.c:49
AfterTriggerEventList events
Definition: trigger.c:3815
CommandId firing_counter
Definition: trigger.c:3817
CommandId firing_counter
Definition: trigger.c:3789
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:3791
static AfterTriggersData afterTriggers
Definition: trigger.c:3834
SetConstraintState state
Definition: trigger.c:3814

◆ AfterTriggerBeginXact()

void AfterTriggerBeginXact ( void  )

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

4754 {
4755  /*
4756  * Initialize after-trigger state structure to empty
4757  */
4758  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4760 
4761  /*
4762  * Verify that there is no leftover state remaining. If these assertions
4763  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4764  * up properly.
4765  */
4766  Assert(afterTriggers.state == NULL);
4767  Assert(afterTriggers.query_stack == NULL);
4769  Assert(afterTriggers.event_cxt == NULL);
4770  Assert(afterTriggers.events.head == NULL);
4771  Assert(afterTriggers.trans_stack == NULL);
4773 }
uint32 CommandId
Definition: c.h:528
AfterTriggersTransData * trans_stack
Definition: trigger.c:3800
AfterTriggersQueryData * query_stack
Definition: trigger.c:3795
SetConstraintState state
Definition: trigger.c:3790
CommandId firing_counter
Definition: trigger.c:3789
#define Assert(condition)
Definition: c.h:739
AfterTriggerEventChunk * head
Definition: trigger.c:3683
MemoryContext event_cxt
Definition: trigger.c:3792
AfterTriggerEventList events
Definition: trigger.c:3791
static AfterTriggersData afterTriggers
Definition: trigger.c:3834

◆ AfterTriggerEndQuery()

void AfterTriggerEndQuery ( EState estate)

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

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

◆ AfterTriggerEndSubXact()

void AfterTriggerEndSubXact ( bool  isCommit)

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

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

◆ AfterTriggerEndXact()

void AfterTriggerEndXact ( bool  isCommit)

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

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

◆ AfterTriggerFireDeferred()

void AfterTriggerFireDeferred ( void  )

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

4950 {
4951  AfterTriggerEventList *events;
4952  bool snap_pushed = false;
4953 
4954  /* Must not be inside a query */
4956 
4957  /*
4958  * If there are any triggers to fire, make sure we have set a snapshot for
4959  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4960  * can't assume ActiveSnapshot is valid on entry.)
4961  */
4962  events = &afterTriggers.events;
4963  if (events->head != NULL)
4964  {
4966  snap_pushed = true;
4967  }
4968 
4969  /*
4970  * Run all the remaining triggers. Loop until they are all gone, in case
4971  * some trigger queues more for us to do.
4972  */
4973  while (afterTriggerMarkEvents(events, NULL, false))
4974  {
4975  CommandId firing_id = afterTriggers.firing_counter++;
4976 
4977  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4978  break; /* all fired */
4979  }
4980 
4981  /*
4982  * We don't bother freeing the event list, since it will go away anyway
4983  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4984  */
4985 
4986  if (snap_pushed)
4988 }
uint32 CommandId
Definition: c.h:528
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4461
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:3789
#define Assert(condition)
Definition: c.h:739
AfterTriggerEventChunk * head
Definition: trigger.c:3683
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4389
AfterTriggerEventList events
Definition: trigger.c:3791
static AfterTriggersData afterTriggers
Definition: trigger.c:3834

◆ AfterTriggerPendingOnRel()

bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

◆ AfterTriggerSetState()

void AfterTriggerSetState ( ConstraintsSetStmt stmt)

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

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

◆ CopyTriggerDesc()

TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

2151 {
2152  TriggerDesc *newdesc;
2153  Trigger *trigger;
2154  int i;
2155 
2156  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
2157  return NULL;
2158 
2159  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
2160  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
2161 
2162  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
2163  memcpy(trigger, trigdesc->triggers,
2164  trigdesc->numtriggers * sizeof(Trigger));
2165  newdesc->triggers = trigger;
2166 
2167  for (i = 0; i < trigdesc->numtriggers; i++)
2168  {
2169  trigger->tgname = pstrdup(trigger->tgname);
2170  if (trigger->tgnattr > 0)
2171  {
2172  int16 *newattr;
2173 
2174  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
2175  memcpy(newattr, trigger->tgattr,
2176  trigger->tgnattr * sizeof(int16));
2177  trigger->tgattr = newattr;
2178  }
2179  if (trigger->tgnargs > 0)
2180  {
2181  char **newargs;
2182  int16 j;
2183 
2184  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
2185  for (j = 0; j < trigger->tgnargs; j++)
2186  newargs[j] = pstrdup(trigger->tgargs[j]);
2187  trigger->tgargs = newargs;
2188  }
2189  if (trigger->tgqual)
2190  trigger->tgqual = pstrdup(trigger->tgqual);
2191  if (trigger->tgoldtable)
2192  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
2193  if (trigger->tgnewtable)
2194  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
2195  trigger++;
2196  }
2197 
2198  return newdesc;
2199 }
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, addNSItemToQuery(), addRangeTableEntryForRelation(), 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  ParseNamespaceItem *nsitem;
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 nsitems for OLD and NEW references.
578  *
579  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
580  */
581  nsitem = addRangeTableEntryForRelation(pstate, rel,
583  makeAlias("old", NIL),
584  false, false);
585  addNSItemToQuery(pstate, nsitem, false, true, true);
586  nsitem = addRangeTableEntryForRelation(pstate, rel,
588  makeAlias("new", NIL),
589  false, false);
590  addNSItemToQuery(pstate, nsitem, 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 
1148  childTbl = table_open(partdesc->oids[i], ShareRowExclusiveLock);
1149 
1150  /* Find which of the child indexes is the one on this partition */
1151  if (OidIsValid(indexOid))
1152  {
1153  forboth(l, idxs, l2, childTbls)
1154  {
1155  if (lfirst_oid(l2) == partdesc->oids[i])
1156  {
1157  indexOnChild = lfirst_oid(l);
1158  break;
1159  }
1160  }
1161  if (!OidIsValid(indexOnChild))
1162  elog(ERROR, "failed to find index matching index \"%s\" in partition \"%s\"",
1163  get_rel_name(indexOid),
1164  get_rel_name(partdesc->oids[i]));
1165  }
1166 
1167  /*
1168  * Initialize our fabricated parse node by copying the original
1169  * one, then resetting fields that we pass separately.
1170  */
1171  childStmt = (CreateTrigStmt *) copyObject(stmt);
1172  childStmt->funcname = NIL;
1173  childStmt->whenClause = NULL;
1174 
1175  /* If there is a WHEN clause, create a modified copy of it */
1176  qual = copyObject(whenClause);
1177  qual = (Node *)
1179  childTbl, rel);
1180  qual = (Node *)
1182  childTbl, rel);
1183 
1184  CreateTrigger(childStmt, queryString,
1185  partdesc->oids[i], refRelOid,
1186  InvalidOid, indexOnChild,
1187  funcoid, trigoid, qual,
1188  isInternal, true);
1189 
1190  table_close(childTbl, NoLock);
1191 
1192  MemoryContextReset(perChildCxt);
1193  }
1194 
1195  MemoryContextSwitchTo(oldcxt);
1196  MemoryContextDelete(perChildCxt);
1197  list_free(idxs);
1198  list_free(childTbls);
1199  }
1200 
1201  /* Keep lock on target rel until end of xact */
1202  table_close(rel, NoLock);
1203 
1204  return myself;
1205 }
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:3379
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:1069
#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:454
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:2437
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:50
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
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
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:186
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:615
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:181
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
#define OidIsValid(objectId)
Definition: c.h:645
#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
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
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:2444
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
#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:2103
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:196
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define CStringGetDatum(X)
Definition: postgres.h:578
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1586
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:462
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
const char * p_sourcetext
Definition: parse_node.h:179
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:1235
List * transitionRels
Definition: parsenodes.h:2440
#define ereport(elevel, rest)
Definition: elog.h:141
Oid rd_id
Definition: rel.h:86
#define PRS2_OLD_VARNO
Definition: primnodes.h:178
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:184
char * NameListToString(List *names)
Definition: namespace.c:3094
Definition: c.h:584
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:153
TupleDesc rd_att
Definition: rel.h:85
#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:739
#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:4629
#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:4653
int i
RangeVar * relation
Definition: parsenodes.h:2428
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:616
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:4325
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
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:198
#define RelationGetRelid(relation)
Definition: rel.h:428
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define PRS2_NEW_VARNO
Definition: primnodes.h:179
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192
#define RelationGetNamespace(relation)
Definition: rel.h:469
List * p_rtable
Definition: parse_node.h:180

◆ EnableDisableTrigger()

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

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

1801 {
1802  Relation tgrel;
1803  int nkeys;
1804  ScanKeyData keys[2];
1805  SysScanDesc tgscan;
1806  HeapTuple tuple;
1807  bool found;
1808  bool changed;
1809 
1810  /* Scan the relevant entries in pg_triggers */
1811  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
1812 
1813  ScanKeyInit(&keys[0],
1814  Anum_pg_trigger_tgrelid,
1815  BTEqualStrategyNumber, F_OIDEQ,
1817  if (tgname)
1818  {
1819  ScanKeyInit(&keys[1],
1820  Anum_pg_trigger_tgname,
1821  BTEqualStrategyNumber, F_NAMEEQ,
1822  CStringGetDatum(tgname));
1823  nkeys = 2;
1824  }
1825  else
1826  nkeys = 1;
1827 
1828  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1829  NULL, nkeys, keys);
1830 
1831  found = changed = false;
1832 
1833  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1834  {
1835  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1836 
1837  if (oldtrig->tgisinternal)
1838  {
1839  /* system trigger ... ok to process? */
1840  if (skip_system)
1841  continue;
1842  if (!superuser())
1843  ereport(ERROR,
1844  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1845  errmsg("permission denied: \"%s\" is a system trigger",
1846  NameStr(oldtrig->tgname))));
1847  }
1848 
1849  found = true;
1850 
1851  if (oldtrig->tgenabled != fires_when)
1852  {
1853  /* need to change this one ... make a copy to scribble on */
1854  HeapTuple newtup = heap_copytuple(tuple);
1855  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1856 
1857  newtrig->tgenabled = fires_when;
1858 
1859  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1860 
1861  heap_freetuple(newtup);
1862 
1863  /*
1864  * When altering FOR EACH ROW triggers on a partitioned table, do
1865  * the same on the partitions as well.
1866  */
1867  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1868  (TRIGGER_FOR_ROW(oldtrig->tgtype)))
1869  {
1870  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1871  int i;
1872 
1873  for (i = 0; i < partdesc->nparts; i++)
1874  {
1875  Relation part;
1876 
1877  part = relation_open(partdesc->oids[i], lockmode);
1878  EnableDisableTrigger(part, NameStr(oldtrig->tgname),
1879  fires_when, skip_system, lockmode);
1880  table_close(part, NoLock); /* keep lock till commit */
1881  }
1882  }
1883 
1884  changed = true;
1885  }
1886 
1887  InvokeObjectPostAlterHook(TriggerRelationId,
1888  oldtrig->oid, 0);
1889  }
1890 
1891  systable_endscan(tgscan);
1892 
1893  table_close(tgrel, RowExclusiveLock);
1894 
1895  if (tgname && !found)
1896  ereport(ERROR,
1897  (errcode(ERRCODE_UNDEFINED_OBJECT),
1898  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1899  tgname, RelationGetRelationName(rel))));
1900 
1901  /*
1902  * If we changed anything, broadcast a SI inval message to force each
1903  * backend (including our own!) to rebuild relation's relcache entry.
1904  * Otherwise they will fail to apply the change promptly.
1905  */
1906  if (changed)
1908 }
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:84
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:1799
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#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:616
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:428
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ ExecARDeleteTriggers()

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

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

2844 {
2845  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2846  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2847 
2848  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2849  (transition_capture && transition_capture->tcs_delete_old_table))
2850  {
2851  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2852  if (fdw_trigtuple == NULL)
2853  GetTupleForTrigger(estate,
2854  NULL,
2855  relinfo,
2856  tupleid,
2858  slot,
2859  NULL);
2860  else
2861  ExecForceStoreHeapTuple(fdw_trigtuple, slot, false);
2862 
2864  true, slot, NULL, NIL, NULL,
2865  transition_capture);
2866  }
2867 }
#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:3301
#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:422
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:5710
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739

◆ ExecARInsertTriggers()

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

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

2595 {
2596  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2597 
2598  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2599  (transition_capture && transition_capture->tcs_insert_new_table))
2601  true, NULL, slot,
2602  recheckIndexes, NULL,
2603  transition_capture);
2604 }
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
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:5710
#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 3127 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().

3133 {
3134  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3135  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3136 
3137  ExecClearTuple(oldslot);
3138 
3139  if ((trigdesc && trigdesc->trig_update_after_row) ||
3140  (transition_capture &&
3141  (transition_capture->tcs_update_old_table ||
3142  transition_capture->tcs_update_new_table)))
3143  {
3144  /*
3145  * Note: if the UPDATE is converted into a DELETE+INSERT as part of
3146  * update-partition-key operation, then this function is also called
3147  * separately for DELETE and INSERT to capture transition table rows.
3148  * In such case, either old tuple or new tuple can be NULL.
3149  */
3150  if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
3151  GetTupleForTrigger(estate,
3152  NULL,
3153  relinfo,
3154  tupleid,
3156  oldslot,
3157  NULL);
3158  else if (fdw_trigtuple != NULL)
3159  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
3160 
3162  true, oldslot, newslot, recheckIndexes,
3163  GetAllUpdatedColumns(relinfo, estate),
3164  transition_capture);
3165  }
3166 }
#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:3301
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:422
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:5710
#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 2731 of file trigger.c.

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

Referenced by fireASTriggers().

2733 {
2734  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2735 
2736  if (trigdesc && trigdesc->trig_delete_after_statement)
2738  false, NULL, NULL, NIL, NULL, transition_capture);
2739 }
#define NIL
Definition: pg_list.h:65
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
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:5710
bool trig_delete_after_statement
Definition: reltrigger.h:69

◆ ExecASInsertTriggers()

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

Definition at line 2514 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2516 {
2517  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2518 
2519  if (trigdesc && trigdesc->trig_insert_after_statement)
2521  false, NULL, NULL, NIL, NULL, transition_capture);
2522 }
#define NIL
Definition: pg_list.h:65
bool trig_insert_after_statement
Definition: reltrigger.h:59
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
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:5710
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98

◆ ExecASTruncateTriggers()

void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3290 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

3291 {
3292  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3293 
3294  if (trigdesc && trigdesc->trig_truncate_after_statement)
3296  false, NULL, NULL, NIL, NULL, NULL);
3297 }
#define NIL
Definition: pg_list.h:65
bool trig_truncate_after_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
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:5710
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101

◆ ExecASUpdateTriggers()

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

Definition at line 2983 of file trigger.c.

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

Referenced by fireASTriggers().

2985 {
2986  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2987 
2988  if (trigdesc && trigdesc->trig_update_after_statement)
2990  false, NULL, NULL, NIL,
2991  GetAllUpdatedColumns(relinfo, estate),
2992  transition_capture);
2993 }
#define NIL
Definition: pg_list.h:65
bool trig_update_after_statement
Definition: reltrigger.h:64
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:422
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:5710
#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 2749 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().

2754 {
2755  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2756  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2757  bool result = true;
2758  TriggerData LocTriggerData;
2759  HeapTuple trigtuple;
2760  bool should_free = false;
2761  int i;
2762 
2763  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2764  if (fdw_trigtuple == NULL)
2765  {
2766  TupleTableSlot *epqslot_candidate = NULL;
2767 
2768  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2769  LockTupleExclusive, slot, &epqslot_candidate))
2770  return false;
2771 
2772  /*
2773  * If the tuple was concurrently updated and the caller of this
2774  * function requested for the updated tuple, skip the trigger
2775  * execution.
2776  */
2777  if (epqslot_candidate != NULL && epqslot != NULL)
2778  {
2779  *epqslot = epqslot_candidate;
2780  return false;
2781  }
2782 
2783  trigtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2784 
2785  }
2786  else
2787  {
2788  trigtuple = fdw_trigtuple;
2789  ExecForceStoreHeapTuple(trigtuple, slot, false);
2790  }
2791 
2792  LocTriggerData.type = T_TriggerData;
2793  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2796  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2797  LocTriggerData.tg_trigtuple = NULL;
2798  LocTriggerData.tg_newtuple = NULL;
2799  LocTriggerData.tg_trigslot = NULL;
2800  LocTriggerData.tg_newslot = NULL;
2801  LocTriggerData.tg_oldtable = NULL;
2802  LocTriggerData.tg_newtable = NULL;
2803  for (i = 0; i < trigdesc->numtriggers; i++)
2804  {
2805  HeapTuple newtuple;
2806  Trigger *trigger = &trigdesc->triggers[i];
2807 
2808  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2809  TRIGGER_TYPE_ROW,
2810  TRIGGER_TYPE_BEFORE,
2811  TRIGGER_TYPE_DELETE))
2812  continue;
2813  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2814  NULL, slot, NULL))
2815  continue;
2816 
2817  LocTriggerData.tg_trigslot = slot;
2818  LocTriggerData.tg_trigtuple = trigtuple;
2819  LocTriggerData.tg_trigger = trigger;
2820  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2821  i,
2822  relinfo->ri_TrigFunctions,
2823  relinfo->ri_TrigInstrument,
2824  GetPerTupleMemoryContext(estate));
2825  if (newtuple == NULL)
2826  {
2827  result = false; /* tell caller to suppress delete */
2828  break;
2829  }
2830  if (newtuple != trigtuple)
2831  heap_freetuple(newtuple);
2832  }
2833  if (should_free)
2834  heap_freetuple(trigtuple);
2835 
2836  return result;
2837 }
#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:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3301
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:739
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRInsertTriggers()

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

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

2527 {
2528  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2529  HeapTuple newtuple = NULL;
2530  bool should_free;
2531  TriggerData LocTriggerData;
2532  int i;
2533 
2534  LocTriggerData.type = T_TriggerData;
2535  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2538  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2539  LocTriggerData.tg_trigtuple = NULL;
2540  LocTriggerData.tg_newtuple = NULL;
2541  LocTriggerData.tg_trigslot = NULL;
2542  LocTriggerData.tg_newslot = NULL;
2543  LocTriggerData.tg_oldtable = NULL;
2544  LocTriggerData.tg_newtable = NULL;
2545  for (i = 0; i < trigdesc->numtriggers; i++)
2546  {
2547  Trigger *trigger = &trigdesc->triggers[i];
2548  HeapTuple oldtuple;
2549 
2550  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2551  TRIGGER_TYPE_ROW,
2552  TRIGGER_TYPE_BEFORE,
2553  TRIGGER_TYPE_INSERT))
2554  continue;
2555  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2556  NULL, NULL, slot))
2557  continue;
2558 
2559  if (!newtuple)
2560  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2561 
2562  LocTriggerData.tg_trigslot = slot;
2563  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2564  LocTriggerData.tg_trigger = trigger;
2565  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2566  i,
2567  relinfo->ri_TrigFunctions,
2568  relinfo->ri_TrigInstrument,
2569  GetPerTupleMemoryContext(estate));
2570  if (newtuple == NULL)
2571  {
2572  if (should_free)
2573  heap_freetuple(oldtuple);
2574  return false; /* "do nothing" */
2575  }
2576  else if (newtuple != oldtuple)
2577  {
2578  ExecForceStoreHeapTuple(newtuple, slot, false);
2579 
2580  if (should_free)
2581  heap_freetuple(oldtuple);
2582 
2583  /* signal tuple should be re-fetched if used */
2584  newtuple = NULL;
2585  }
2586  }
2587 
2588  return true;
2589 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
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 2996 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().

3001 {
3002  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3003  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3004  HeapTuple newtuple = NULL;
3005  HeapTuple trigtuple;
3006  bool should_free_trig = false;
3007  bool should_free_new = false;
3008  TriggerData LocTriggerData;
3009  int i;
3010  Bitmapset *updatedCols;
3011  LockTupleMode lockmode;
3012 
3013  /* Determine lock mode to use */
3014  lockmode = ExecUpdateLockMode(estate, relinfo);
3015 
3016  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
3017  if (fdw_trigtuple == NULL)
3018  {
3019  TupleTableSlot *epqslot_candidate = NULL;
3020 
3021  /* get a copy of the on-disk tuple we are planning to update */
3022  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
3023  lockmode, oldslot, &epqslot_candidate))
3024  return false; /* cancel the update action */
3025 
3026  /*
3027  * In READ COMMITTED isolation level it's possible that target tuple
3028  * was changed due to concurrent update. In that case we have a raw
3029  * subplan output tuple in epqslot_candidate, and need to run it
3030  * through the junk filter to produce an insertable tuple.
3031  *
3032  * Caution: more than likely, the passed-in slot is the same as the
3033  * junkfilter's output slot, so we are clobbering the original value
3034  * of slottuple by doing the filtering. This is OK since neither we
3035  * nor our caller have any more interest in the prior contents of that
3036  * slot.
3037  */
3038  if (epqslot_candidate != NULL)
3039  {
3040  TupleTableSlot *epqslot_clean;
3041 
3042  epqslot_clean = ExecFilterJunk(relinfo->ri_junkFilter, epqslot_candidate);
3043 
3044  if (newslot != epqslot_clean)
3045  ExecCopySlot(newslot, epqslot_clean);
3046  }
3047 
3048  trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
3049  }
3050  else
3051  {
3052  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
3053  trigtuple = fdw_trigtuple;
3054  }
3055 
3056  LocTriggerData.type = T_TriggerData;
3057  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3060  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3061  LocTriggerData.tg_oldtable = NULL;
3062  LocTriggerData.tg_newtable = NULL;
3063  updatedCols = GetAllUpdatedColumns(relinfo, estate);
3064  for (i = 0; i < trigdesc->numtriggers; i++)
3065  {
3066  Trigger *trigger = &trigdesc->triggers[i];
3067  HeapTuple oldtuple;
3068 
3069  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3070  TRIGGER_TYPE_ROW,
3071  TRIGGER_TYPE_BEFORE,
3072  TRIGGER_TYPE_UPDATE))
3073  continue;
3074  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3075  updatedCols, oldslot, newslot))
3076  continue;
3077 
3078  if (!newtuple)
3079  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free_new);
3080 
3081  LocTriggerData.tg_trigslot = oldslot;
3082  LocTriggerData.tg_trigtuple = trigtuple;
3083  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3084  LocTriggerData.tg_newslot = newslot;
3085  LocTriggerData.tg_trigger = trigger;
3086  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3087  i,
3088  relinfo->ri_TrigFunctions,
3089  relinfo->ri_TrigInstrument,
3090  GetPerTupleMemoryContext(estate));
3091 
3092  if (newtuple == NULL)
3093  {
3094  if (should_free_trig)
3095  heap_freetuple(trigtuple);
3096  if (should_free_new)
3097  heap_freetuple(oldtuple);
3098  return false; /* "do nothing" */
3099  }
3100  else if (newtuple != oldtuple)
3101  {
3102  ExecForceStoreHeapTuple(newtuple, newslot, false);
3103 
3104  /*
3105  * If the tuple returned by the trigger / being stored, is the old
3106  * row version, and the heap tuple passed to the trigger was
3107  * allocated locally, materialize the slot. Otherwise we might
3108  * free it while still referenced by the slot.
3109  */
3110  if (should_free_trig && newtuple == trigtuple)
3111  ExecMaterializeSlot(newslot);
3112 
3113  if (should_free_new)
3114  heap_freetuple(oldtuple);
3115 
3116  /* signal tuple should be re-fetched if used */
3117  newtuple = NULL;
3118  }
3119  }
3120  if (should_free_trig)
3121  heap_freetuple(trigtuple);
3122 
3123  return true;
3124 }
#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:460
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
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:3417
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:3301
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:739
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2311
#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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSDeleteTriggers()

void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2675 {
2676  TriggerDesc *trigdesc;
2677  int i;
2678  TriggerData LocTriggerData;
2679 
2680  trigdesc = relinfo->ri_TrigDesc;
2681 
2682  if (trigdesc == NULL)
2683  return;
2684  if (!trigdesc->trig_delete_before_statement)
2685  return;
2686 
2687  /* no-op if we already fired BS triggers in this context */
2689  CMD_DELETE))
2690  return;
2691 
2692  LocTriggerData.type = T_TriggerData;
2693  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2695  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2696  LocTriggerData.tg_trigtuple = NULL;
2697  LocTriggerData.tg_newtuple = NULL;
2698  LocTriggerData.tg_trigslot = NULL;
2699  LocTriggerData.tg_newslot = NULL;
2700  LocTriggerData.tg_oldtable = NULL;
2701  LocTriggerData.tg_newtable = NULL;
2702  for (i = 0; i < trigdesc->numtriggers; i++)
2703  {
2704  Trigger *trigger = &trigdesc->triggers[i];
2705  HeapTuple newtuple;
2706 
2707  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2708  TRIGGER_TYPE_STATEMENT,
2709  TRIGGER_TYPE_BEFORE,
2710  TRIGGER_TYPE_DELETE))
2711  continue;
2712  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2713  NULL, NULL, NULL))
2714  continue;
2715 
2716  LocTriggerData.tg_trigger = trigger;
2717  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2718  i,
2719  relinfo->ri_TrigFunctions,
2720  relinfo->ri_TrigInstrument,
2721  GetPerTupleMemoryContext(estate));
2722 
2723  if (newtuple)
2724  ereport(ERROR,
2725  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2726  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2727  }
2728 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:6042
#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:422
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:2365
#define RelationGetRelid(relation)
Definition: rel.h:428
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSInsertTriggers()

void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2458 {
2459  TriggerDesc *trigdesc;
2460  int i;
2461  TriggerData LocTriggerData;
2462 
2463  trigdesc = relinfo->ri_TrigDesc;
2464 
2465  if (trigdesc == NULL)
2466  return;
2467  if (!trigdesc->trig_insert_before_statement)
2468  return;
2469 
2470  /* no-op if we already fired BS triggers in this context */
2472  CMD_INSERT))
2473  return;
2474 
2475  LocTriggerData.type = T_TriggerData;
2476  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2478  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2479  LocTriggerData.tg_trigtuple = NULL;
2480  LocTriggerData.tg_newtuple = NULL;
2481  LocTriggerData.tg_trigslot = NULL;
2482  LocTriggerData.tg_newslot = NULL;
2483  LocTriggerData.tg_oldtable = NULL;
2484  LocTriggerData.tg_newtable = NULL;
2485  for (i = 0; i < trigdesc->numtriggers; i++)
2486  {
2487  Trigger *trigger = &trigdesc->triggers[i];
2488  HeapTuple newtuple;
2489 
2490  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2491  TRIGGER_TYPE_STATEMENT,
2492  TRIGGER_TYPE_BEFORE,
2493  TRIGGER_TYPE_INSERT))
2494  continue;
2495  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2496  NULL, NULL, NULL))
2497  continue;
2498 
2499  LocTriggerData.tg_trigger = trigger;
2500  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2501  i,
2502  relinfo->ri_TrigFunctions,
2503  relinfo->ri_TrigInstrument,
2504  GetPerTupleMemoryContext(estate));
2505 
2506  if (newtuple)
2507  ereport(ERROR,
2508  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2509  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2510  }
2511 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:6042
#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:422
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:2365
#define RelationGetRelid(relation)
Definition: rel.h:428
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSTruncateTriggers()

void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

3238 {
3239  TriggerDesc *trigdesc;
3240  int i;
3241  TriggerData LocTriggerData;
3242 
3243  trigdesc = relinfo->ri_TrigDesc;
3244 
3245  if (trigdesc == NULL)
3246  return;
3247  if (!trigdesc->trig_truncate_before_statement)
3248  return;
3249 
3250  LocTriggerData.type = T_TriggerData;
3251  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
3253  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3254  LocTriggerData.tg_trigtuple = NULL;
3255  LocTriggerData.tg_newtuple = NULL;
3256  LocTriggerData.tg_trigslot = NULL;
3257  LocTriggerData.tg_newslot = NULL;
3258  LocTriggerData.tg_oldtable = NULL;
3259  LocTriggerData.tg_newtable = NULL;
3260 
3261  for (i = 0; i < trigdesc->numtriggers; i++)
3262  {
3263  Trigger *trigger = &trigdesc->triggers[i];
3264  HeapTuple newtuple;
3265 
3266  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3267  TRIGGER_TYPE_STATEMENT,
3268  TRIGGER_TYPE_BEFORE,
3269  TRIGGER_TYPE_TRUNCATE))
3270  continue;
3271  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3272  NULL, NULL, NULL))
3273  continue;
3274 
3275  LocTriggerData.tg_trigger = trigger;
3276  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3277  i,
3278  relinfo->ri_TrigFunctions,
3279  relinfo->ri_TrigInstrument,
3280  GetPerTupleMemoryContext(estate));
3281 
3282  if (newtuple)
3283  ereport(ERROR,
3284  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3285  errmsg("BEFORE STATEMENT trigger cannot return a value")));
3286  }
3287 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSUpdateTriggers()

void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2924 {
2925  TriggerDesc *trigdesc;
2926  int i;
2927  TriggerData LocTriggerData;
2928  Bitmapset *updatedCols;
2929 
2930  trigdesc = relinfo->ri_TrigDesc;
2931 
2932  if (trigdesc == NULL)
2933  return;
2934  if (!trigdesc->trig_update_before_statement)
2935  return;
2936 
2937  /* no-op if we already fired BS triggers in this context */
2939  CMD_UPDATE))
2940  return;
2941 
2942  updatedCols = GetAllUpdatedColumns(relinfo, estate);
2943 
2944  LocTriggerData.type = T_TriggerData;
2945  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2947  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2948  LocTriggerData.tg_trigtuple = NULL;
2949  LocTriggerData.tg_newtuple = NULL;
2950  LocTriggerData.tg_trigslot = NULL;
2951  LocTriggerData.tg_newslot = NULL;
2952  LocTriggerData.tg_oldtable = NULL;
2953  LocTriggerData.tg_newtable = NULL;
2954  for (i = 0; i < trigdesc->numtriggers; i++)
2955  {
2956  Trigger *trigger = &trigdesc->triggers[i];
2957  HeapTuple newtuple;
2958 
2959  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2960  TRIGGER_TYPE_STATEMENT,
2961  TRIGGER_TYPE_BEFORE,
2962  TRIGGER_TYPE_UPDATE))
2963  continue;
2964  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2965  updatedCols, NULL, NULL))
2966  continue;
2967 
2968  LocTriggerData.tg_trigger = trigger;
2969  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2970  i,
2971  relinfo->ri_TrigFunctions,
2972  relinfo->ri_TrigInstrument,
2973  GetPerTupleMemoryContext(estate));
2974 
2975  if (newtuple)
2976  ereport(ERROR,
2977  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2978  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2979  }
2980 }
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:6042
#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:422
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:2365
#define RelationGetRelid(relation)
Definition: rel.h:428
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRDeleteTriggers()

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

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

2872 {
2873  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2874  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2875  TriggerData LocTriggerData;
2876  int i;
2877 
2878  LocTriggerData.type = T_TriggerData;
2879  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2882  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2883  LocTriggerData.tg_trigtuple = NULL;
2884  LocTriggerData.tg_newtuple = NULL;
2885  LocTriggerData.tg_trigslot = NULL;
2886  LocTriggerData.tg_newslot = NULL;
2887  LocTriggerData.tg_oldtable = NULL;
2888  LocTriggerData.tg_newtable = NULL;
2889 
2890  ExecForceStoreHeapTuple(trigtuple, slot, false);
2891 
2892  for (i = 0; i < trigdesc->numtriggers; i++)
2893  {
2894  HeapTuple rettuple;
2895  Trigger *trigger = &trigdesc->triggers[i];
2896 
2897  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2898  TRIGGER_TYPE_ROW,
2899  TRIGGER_TYPE_INSTEAD,
2900  TRIGGER_TYPE_DELETE))
2901  continue;
2902  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2903  NULL, slot, NULL))
2904  continue;
2905 
2906  LocTriggerData.tg_trigslot = slot;
2907  LocTriggerData.tg_trigtuple = trigtuple;
2908  LocTriggerData.tg_trigger = trigger;
2909  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2910  i,
2911  relinfo->ri_TrigFunctions,
2912  relinfo->ri_TrigInstrument,
2913  GetPerTupleMemoryContext(estate));
2914  if (rettuple == NULL)
2915  return false; /* Delete was suppressed */
2916  if (rettuple != trigtuple)
2917  heap_freetuple(rettuple);
2918  }
2919  return true;
2920 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRInsertTriggers()

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

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

2609 {
2610  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2611  HeapTuple newtuple = NULL;
2612  bool should_free;
2613  TriggerData LocTriggerData;
2614  int i;
2615 
2616  LocTriggerData.type = T_TriggerData;
2617  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2620  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2621  LocTriggerData.tg_trigtuple = NULL;
2622  LocTriggerData.tg_newtuple = NULL;
2623  LocTriggerData.tg_trigslot = NULL;
2624  LocTriggerData.tg_newslot = NULL;
2625  LocTriggerData.tg_oldtable = NULL;
2626  LocTriggerData.tg_newtable = NULL;
2627  for (i = 0; i < trigdesc->numtriggers; i++)
2628  {
2629  Trigger *trigger = &trigdesc->triggers[i];
2630  HeapTuple oldtuple;
2631 
2632  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2633  TRIGGER_TYPE_ROW,
2634  TRIGGER_TYPE_INSTEAD,
2635  TRIGGER_TYPE_INSERT))
2636  continue;
2637  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2638  NULL, NULL, slot))
2639  continue;
2640 
2641  if (!newtuple)
2642  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2643 
2644  LocTriggerData.tg_trigslot = slot;
2645  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2646  LocTriggerData.tg_trigger = trigger;
2647  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2648  i,
2649  relinfo->ri_TrigFunctions,
2650  relinfo->ri_TrigInstrument,
2651  GetPerTupleMemoryContext(estate));
2652  if (newtuple == NULL)
2653  {
2654  if (should_free)
2655  heap_freetuple(oldtuple);
2656  return false; /* "do nothing" */
2657  }
2658  else if (newtuple != oldtuple)
2659  {
2660  ExecForceStoreHeapTuple(newtuple, slot, false);
2661 
2662  if (should_free)
2663  heap_freetuple(oldtuple);
2664 
2665  /* signal tuple should be re-fetched if used */
2666  newtuple = NULL;
2667  }
2668  }
2669 
2670  return true;
2671 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRUpdateTriggers()

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

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

3171 {
3172  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3173  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
3174  HeapTuple newtuple = NULL;
3175  bool should_free;
3176  TriggerData LocTriggerData;
3177  int i;
3178 
3179  LocTriggerData.type = T_TriggerData;
3180  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3183  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3184  LocTriggerData.tg_oldtable = NULL;
3185  LocTriggerData.tg_newtable = NULL;
3186 
3187  ExecForceStoreHeapTuple(trigtuple, oldslot, false);
3188 
3189  for (i = 0; i < trigdesc->numtriggers; i++)
3190  {
3191  Trigger *trigger = &trigdesc->triggers[i];
3192  HeapTuple oldtuple;
3193 
3194  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3195  TRIGGER_TYPE_ROW,
3196  TRIGGER_TYPE_INSTEAD,
3197  TRIGGER_TYPE_UPDATE))
3198  continue;
3199  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3200  NULL, oldslot, newslot))
3201  continue;
3202 
3203  if (!newtuple)
3204  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free);
3205 
3206  LocTriggerData.tg_trigslot = oldslot;
3207  LocTriggerData.tg_trigtuple = trigtuple;
3208  LocTriggerData.tg_newslot = newslot;
3209  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3210 
3211  LocTriggerData.tg_trigger = trigger;
3212  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3213  i,
3214  relinfo->ri_TrigFunctions,
3215  relinfo->ri_TrigInstrument,
3216  GetPerTupleMemoryContext(estate));
3217  if (newtuple == NULL)
3218  {
3219  return false; /* "do nothing" */
3220  }
3221  else if (newtuple != oldtuple)
3222  {
3223  ExecForceStoreHeapTuple(newtuple, newslot, false);
3224 
3225  if (should_free)
3226  heap_freetuple(oldtuple);
3227 
3228  /* signal tuple should be re-fetched if used */
3229  newtuple = NULL;
3230  }
3231  }
3232 
3233  return true;
3234 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:410
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3417
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:431
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:422
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:2365
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:425
Relation tg_relation
Definition: trigger.h:34

◆ FindTriggerIncompatibleWithInheritance()

const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2335 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2336 {
2337  if (trigdesc != NULL)
2338  {
2339  int i;
2340 
2341  for (i = 0; i < trigdesc->numtriggers; ++i)
2342  {
2343  Trigger *trigger = &trigdesc->triggers[i];
2344 
2345  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2346  return trigger->tgname;
2347  }
2348  }
2349 
2350  return NULL;
2351 }
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 2205 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().

2206 {
2207  Trigger *trigger;
2208  int i;
2209 
2210  if (trigdesc == NULL)
2211  return;
2212 
2213  trigger = trigdesc->triggers;
2214  for (i = 0; i < trigdesc->numtriggers; i++)
2215  {
2216  pfree(trigger->tgname);
2217  if (trigger->tgnattr > 0)
2218  pfree(trigger->tgattr);
2219  if (trigger->tgnargs > 0)
2220  {
2221  while (--(trigger->tgnargs) >= 0)
2222  pfree(trigger->tgargs[trigger->tgnargs]);
2223  pfree(trigger->tgargs);
2224  }
2225  if (trigger->tgqual)
2226  pfree(trigger->tgqual);
2227  if (trigger->tgoldtable)
2228  pfree(trigger->tgoldtable);
2229  if (trigger->tgnewtable)
2230  pfree(trigger->tgnewtable);
2231  trigger++;
2232  }
2233  pfree(trigdesc->triggers);
2234  pfree(trigdesc);
2235 }
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 1569 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().

1570 {
1571  Relation tgrel;
1572  ScanKeyData skey[2];
1573  SysScanDesc tgscan;
1574  HeapTuple tup;
1575  Oid oid;
1576 
1577  /*
1578  * Find the trigger, verify permissions, set up object address
1579  */
1580  tgrel = table_open(TriggerRelationId, AccessShareLock);
1581 
1582  ScanKeyInit(&skey[0],
1583  Anum_pg_trigger_tgrelid,
1584  BTEqualStrategyNumber, F_OIDEQ,
1585  ObjectIdGetDatum(relid));
1586  ScanKeyInit(&skey[1],
1587  Anum_pg_trigger_tgname,
1588  BTEqualStrategyNumber, F_NAMEEQ,
1589  CStringGetDatum(trigname));
1590 
1591  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1592  NULL, 2, skey);
1593 
1594  tup = systable_getnext(tgscan);
1595 
1596  if (!HeapTupleIsValid(tup))
1597  {
1598  if (!missing_ok)
1599  ereport(ERROR,
1600  (errcode(ERRCODE_UNDEFINED_OBJECT),
1601  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1602  trigname, get_rel_name(relid))));
1603  oid = InvalidOid;
1604  }
1605  else
1606  {
1607  oid = ((Form_pg_trigger) GETSTRUCT(tup))->oid;
1608  }
1609 
1610  systable_endscan(tgscan);
1611  table_close(tgrel, AccessShareLock);
1612  return oid;
1613 }
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 4663 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().

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