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

◆ TriggerEvent

Definition at line 28 of file trigger.h.

Function Documentation

◆ AfterTriggerBeginQuery()

void AfterTriggerBeginQuery ( void  )

Definition at line 4783 of file trigger.c.

References AfterTriggersData::query_depth.

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

4784 {
4785  /* Increase the query stack depth */
4787 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3842

◆ AfterTriggerBeginSubXact()

void AfterTriggerBeginSubXact ( void  )

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

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

◆ AfterTriggerBeginXact()

void AfterTriggerBeginXact ( void  )

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

4752 {
4753  /*
4754  * Initialize after-trigger state structure to empty
4755  */
4756  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4758 
4759  /*
4760  * Verify that there is no leftover state remaining. If these assertions
4761  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4762  * up properly.
4763  */
4764  Assert(afterTriggers.state == NULL);
4765  Assert(afterTriggers.query_stack == NULL);
4767  Assert(afterTriggers.event_cxt == NULL);
4768  Assert(afterTriggers.events.head == NULL);
4769  Assert(afterTriggers.trans_stack == NULL);
4771 }
uint32 CommandId
Definition: c.h:521
AfterTriggersTransData * trans_stack
Definition: trigger.c:3808
AfterTriggersQueryData * query_stack
Definition: trigger.c:3803
SetConstraintState state
Definition: trigger.c:3798
CommandId firing_counter
Definition: trigger.c:3797
#define Assert(condition)
Definition: c.h:732
AfterTriggerEventChunk * head
Definition: trigger.c:3691
MemoryContext event_cxt
Definition: trigger.c:3800
AfterTriggerEventList events
Definition: trigger.c:3799
static AfterTriggersData afterTriggers
Definition: trigger.c:3842

◆ AfterTriggerEndQuery()

void AfterTriggerEndQuery ( EState estate)

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

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

◆ AfterTriggerEndSubXact()

void AfterTriggerEndSubXact ( bool  isCommit)

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

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

◆ AfterTriggerEndXact()

void AfterTriggerEndXact ( bool  isCommit)

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

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

◆ AfterTriggerFireDeferred()

void AfterTriggerFireDeferred ( void  )

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

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

◆ AfterTriggerPendingOnRel()

bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

◆ AfterTriggerSetState()

void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 5323 of file trigger.c.

References AccessShareLock, afterTriggerInvokeEvents(), afterTriggerMarkEvents(), SetConstraintStateData::all_isdeferred, SetConstraintStateData::all_isset, BTEqualStrategyNumber, RangeVar::catalogname, ConstraintNameNspIndexId, ConstraintParentIndexId, ConstraintsSetStmt::constraints, CStringGetDatum, ConstraintsSetStmt::deferred, elog, 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().

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

◆ CopyTriggerDesc()

TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

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

◆ CreateTrigger()

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

Definition at line 162 of file trigger.c.

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

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

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

◆ EnableDisableTrigger()

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

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

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

◆ ExecARDeleteTriggers()

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

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

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

◆ ExecARInsertTriggers()

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

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

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

◆ ExecARUpdateTriggers()

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

Definition at line 3134 of file trigger.c.

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

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

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

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

Referenced by fireASTriggers().

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

◆ ExecASInsertTriggers()

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

Definition at line 2524 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

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

◆ ExecASTruncateTriggers()

void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3297 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

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

◆ ExecASUpdateTriggers()

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

Definition at line 2993 of file trigger.c.

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

Referenced by fireASTriggers().

2995 {
2996  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2997 
2998  if (trigdesc && trigdesc->trig_update_after_statement)
3000  false, NULL, NULL, NIL,
3001  GetAllUpdatedColumns(relinfo, estate),
3002  transition_capture);
3003 }
#define NIL
Definition: pg_list.h:65
bool trig_update_after_statement
Definition: reltrigger.h:64
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:423
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5718
#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 2759 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().

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

◆ ExecBRInsertTriggers()

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

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

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

◆ ExecBRUpdateTriggers()

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

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

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

◆ ExecBSDeleteTriggers()

void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

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

◆ ExecBSInsertTriggers()

void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

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

◆ ExecBSTruncateTriggers()

void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3244 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

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

◆ ExecBSUpdateTriggers()

void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

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

◆ ExecIRDeleteTriggers()

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

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

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

◆ ExecIRInsertTriggers()

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

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

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

◆ ExecIRUpdateTriggers()

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

Definition at line 3176 of file trigger.c.

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

Referenced by ExecUpdate().

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

◆ FindTriggerIncompatibleWithInheritance()

const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2343 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2344 {
2345  if (trigdesc != NULL)
2346  {
2347  int i;
2348 
2349  for (i = 0; i < trigdesc->numtriggers; ++i)
2350  {
2351  Trigger *trigger = &trigdesc->triggers[i];
2352 
2353  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2354  return trigger->tgname;
2355  }
2356  }
2357 
2358  return NULL;
2359 }
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 2213 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().

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

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

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