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)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecIRInsertTriggers (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)
 
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)
 
TupleTableSlotExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecIRUpdateTriggers (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, HeapTuple old_row, HeapTuple new_row)
 
bool RI_FKey_fk_upd_check_required (Trigger *trigger, Relation fk_rel, HeapTuple old_row, HeapTuple new_row)
 
bool RI_Initial_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 268 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 269 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 267 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

#define TRIGGER_FIRES_ON_ORIGIN   'O'

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

References AfterTriggersData::query_depth.

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

4766 {
4767  /* Increase the query stack depth */
4769 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerBeginSubXact()

void AfterTriggerBeginSubXact ( void  )

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

5034 {
5035  int my_level = GetCurrentTransactionNestLevel();
5036 
5037  /*
5038  * Allocate more space in the trans_stack if needed. (Note: because the
5039  * minimum nest level of a subtransaction is 2, we waste the first couple
5040  * entries of the array; not worth the notational effort to avoid it.)
5041  */
5042  while (my_level >= afterTriggers.maxtransdepth)
5043  {
5044  if (afterTriggers.maxtransdepth == 0)
5045  {
5046  /* Arbitrarily initialize for max of 8 subtransaction levels */
5049  8 * sizeof(AfterTriggersTransData));
5051  }
5052  else
5053  {
5054  /* repalloc will keep the stack in the same context */
5055  int new_alloc = afterTriggers.maxtransdepth * 2;
5056 
5059  new_alloc * sizeof(AfterTriggersTransData));
5060  afterTriggers.maxtransdepth = new_alloc;
5061  }
5062  }
5063 
5064  /*
5065  * Push the current information into the stack. The SET CONSTRAINTS state
5066  * is not saved until/unless changed. Likewise, we don't make a
5067  * per-subtransaction event context until needed.
5068  */
5069  afterTriggers.trans_stack[my_level].state = NULL;
5073 }
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:753
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:3841
SetConstraintState state
Definition: trigger.c:3822

◆ AfterTriggerBeginXact()

void AfterTriggerBeginXact ( void  )

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

4734 {
4735  /*
4736  * Initialize after-trigger state structure to empty
4737  */
4738  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4740 
4741  /*
4742  * Verify that there is no leftover state remaining. If these assertions
4743  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4744  * up properly.
4745  */
4746  Assert(afterTriggers.state == NULL);
4747  Assert(afterTriggers.query_stack == NULL);
4749  Assert(afterTriggers.event_cxt == NULL);
4750  Assert(afterTriggers.events.head == NULL);
4751  Assert(afterTriggers.trans_stack == NULL);
4753 }
uint32 CommandId
Definition: c.h:488
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:699
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:3841

◆ AfterTriggerEndQuery()

void AfterTriggerEndQuery ( EState estate)

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

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

◆ AfterTriggerEndSubXact()

void AfterTriggerEndSubXact ( bool  isCommit)

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

5082 {
5083  int my_level = GetCurrentTransactionNestLevel();
5085  AfterTriggerEvent event;
5086  AfterTriggerEventChunk *chunk;
5087  CommandId subxact_firing_id;
5088 
5089  /*
5090  * Pop the prior state if needed.
5091  */
5092  if (isCommit)
5093  {
5094  Assert(my_level < afterTriggers.maxtransdepth);
5095  /* If we saved a prior state, we don't need it anymore */
5096  state = afterTriggers.trans_stack[my_level].state;
5097  if (state != NULL)
5098  pfree(state);
5099  /* this avoids double pfree if error later: */
5100  afterTriggers.trans_stack[my_level].state = NULL;
5103  }
5104  else
5105  {
5106  /*
5107  * Aborting. It is possible subxact start failed before calling
5108  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
5109  * trans_stack levels that aren't there.
5110  */
5111  if (my_level >= afterTriggers.maxtransdepth)
5112  return;
5113 
5114  /*
5115  * Release query-level storage for queries being aborted, and restore
5116  * query_depth to its pre-subxact value. This assumes that a
5117  * subtransaction will not add events to query levels started in a
5118  * earlier transaction state.
5119  */
5121  {
5125  }
5128 
5129  /*
5130  * Restore the global deferred-event list to its former length,
5131  * discarding any events queued by the subxact.
5132  */
5134  &afterTriggers.trans_stack[my_level].events);
5135 
5136  /*
5137  * Restore the trigger state. If the saved state is NULL, then this
5138  * subxact didn't save it, so it doesn't need restoring.
5139  */
5140  state = afterTriggers.trans_stack[my_level].state;
5141  if (state != NULL)
5142  {
5144  afterTriggers.state = state;
5145  }
5146  /* this avoids double pfree if error later: */
5147  afterTriggers.trans_stack[my_level].state = NULL;
5148 
5149  /*
5150  * Scan for any remaining deferred events that were marked DONE or IN
5151  * PROGRESS by this subxact or a child, and un-mark them. We can
5152  * recognize such events because they have a firing ID greater than or
5153  * equal to the firing_counter value we saved at subtransaction start.
5154  * (This essentially assumes that the current subxact includes all
5155  * subxacts started after it.)
5156  */
5157  subxact_firing_id = afterTriggers.trans_stack[my_level].firing_counter;
5159  {
5160  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5161 
5162  if (event->ate_flags &
5164  {
5165  if (evtshared->ats_firing_id >= subxact_firing_id)
5166  event->ate_flags &=
5168  }
5169  }
5170  }
5171 }
uint32 CommandId
Definition: c.h:488
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:753
#define Assert(condition)
Definition: c.h:699
Definition: regguts.h:298
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:4084
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:4876
static AfterTriggersData afterTriggers
Definition: trigger.c:3841
SetConstraintState state
Definition: trigger.c:3822

◆ AfterTriggerEndXact()

void AfterTriggerEndXact ( bool  isCommit)

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

4986 {
4987  /*
4988  * Forget the pending-events list.
4989  *
4990  * Since all the info is in TopTransactionContext or children thereof, we
4991  * don't really need to do anything to reclaim memory. However, the
4992  * pending-events list could be large, and so it's useful to discard it as
4993  * soon as possible --- especially if we are aborting because we ran out
4994  * of memory for the list!
4995  */
4997  {
4999  afterTriggers.event_cxt = NULL;
5000  afterTriggers.events.head = NULL;
5001  afterTriggers.events.tail = NULL;
5002  afterTriggers.events.tailfree = NULL;
5003  }
5004 
5005  /*
5006  * Forget any subtransaction state as well. Since this can't be very
5007  * large, we let the eventual reset of TopTransactionContext free the
5008  * memory instead of doing it here.
5009  */
5010  afterTriggers.trans_stack = NULL;
5012 
5013 
5014  /*
5015  * Forget the query stack and constraint-related state information. As
5016  * with the subtransaction state information, we don't bother freeing the
5017  * memory here.
5018  */
5019  afterTriggers.query_stack = NULL;
5021  afterTriggers.state = NULL;
5022 
5023  /* No more afterTriggers manipulation until next transaction starts. */
5025 }
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:3841

◆ AfterTriggerFireDeferred()

void AfterTriggerFireDeferred ( void  )

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

4930 {
4931  AfterTriggerEventList *events;
4932  bool snap_pushed = false;
4933 
4934  /* Must not be inside a query */
4936 
4937  /*
4938  * If there are any triggers to fire, make sure we have set a snapshot for
4939  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4940  * can't assume ActiveSnapshot is valid on entry.)
4941  */
4942  events = &afterTriggers.events;
4943  if (events->head != NULL)
4944  {
4946  snap_pushed = true;
4947  }
4948 
4949  /*
4950  * Run all the remaining triggers. Loop until they are all gone, in case
4951  * some trigger queues more for us to do.
4952  */
4953  while (afterTriggerMarkEvents(events, NULL, false))
4954  {
4955  CommandId firing_id = afterTriggers.firing_counter++;
4956 
4957  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4958  break; /* all fired */
4959  }
4960 
4961  /*
4962  * We don't bother freeing the event list, since it will go away anyway
4963  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4964  */
4965 
4966  if (snap_pushed)
4968 }
uint32 CommandId
Definition: c.h:488
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4444
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
CommandId firing_counter
Definition: trigger.c:3797
#define Assert(condition)
Definition: c.h:699
AfterTriggerEventChunk * head
Definition: trigger.c:3691
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4372
AfterTriggerEventList events
Definition: trigger.c:3799
static AfterTriggersData afterTriggers
Definition: trigger.c:3841

◆ AfterTriggerPendingOnRel()

bool AfterTriggerPendingOnRel ( Oid  relid)

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

5629 {
5630  AfterTriggerEvent event;
5631  AfterTriggerEventChunk *chunk;
5632  int depth;
5633 
5634  /* Scan queued events */
5636  {
5637  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5638 
5639  /*
5640  * We can ignore completed events. (Even if a DONE flag is rolled
5641  * back by subxact abort, it's OK because the effects of the TRUNCATE
5642  * or whatever must get rolled back too.)
5643  */
5644  if (event->ate_flags & AFTER_TRIGGER_DONE)
5645  continue;
5646 
5647  if (evtshared->ats_relid == relid)
5648  return true;
5649  }
5650 
5651  /*
5652  * Also scan events queued by incomplete queries. This could only matter
5653  * if TRUNCATE/etc is executed by a function or trigger within an updating
5654  * query on the same relation, which is pretty perverse, but let's check.
5655  */
5656  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5657  {
5659  {
5660  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5661 
5662  if (event->ate_flags & AFTER_TRIGGER_DONE)
5663  continue;
5664 
5665  if (evtshared->ats_relid == relid)
5666  return true;
5667  }
5668  }
5669 
5670  return false;
5671 }
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:3841

◆ AfterTriggerSetState()

void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 5305 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(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, i, IsSubTransaction(), 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(), AfterTriggersData::trans_stack, TriggerConstraintIndexId, and SetConstraintStateData::trigstates.

Referenced by standard_ProcessUtility().

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

◆ CopyTriggerDesc()

TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

2139 {
2140  TriggerDesc *newdesc;
2141  Trigger *trigger;
2142  int i;
2143 
2144  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
2145  return NULL;
2146 
2147  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
2148  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
2149 
2150  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
2151  memcpy(trigger, trigdesc->triggers,
2152  trigdesc->numtriggers * sizeof(Trigger));
2153  newdesc->triggers = trigger;
2154 
2155  for (i = 0; i < trigdesc->numtriggers; i++)
2156  {
2157  trigger->tgname = pstrdup(trigger->tgname);
2158  if (trigger->tgnattr > 0)
2159  {
2160  int16 *newattr;
2161 
2162  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
2163  memcpy(newattr, trigger->tgattr,
2164  trigger->tgnattr * sizeof(int16));
2165  trigger->tgattr = newattr;
2166  }
2167  if (trigger->tgnargs > 0)
2168  {
2169  char **newargs;
2170  int16 j;
2171 
2172  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
2173  for (j = 0; j < trigger->tgnargs; j++)
2174  newargs[j] = pstrdup(trigger->tgargs[j]);
2175  trigger->tgargs = newargs;
2176  }
2177  if (trigger->tgqual)
2178  trigger->tgqual = pstrdup(trigger->tgqual);
2179  if (trigger->tgoldtable)
2180  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
2181  if (trigger->tgnewtable)
2182  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
2183  trigger++;
2184  }
2185 
2186  return newdesc;
2187 }
signed short int16
Definition: c.h:312
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 159 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_INTERNAL_AUTO, DEPENDENCY_NORMAL, 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(), GetNewOid(), GETSTRUCT, GetUserId(), has_superclass(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleIsValid, HeapTupleSetOid, i, IndexGetRelation(), CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, 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(), 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, 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, CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, TRIGGER_FIRES_ON_ORIGIN, TriggerRelidNameIndexId, CreateTrigStmt::trigname, values, Var::varattno, Var::varno, WARNING, and CreateTrigStmt::whenClause.

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

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

◆ EnableDisableTrigger()

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

Definition at line 1787 of file trigger.c.

References BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CStringGetDatum, EnableDisableTrigger(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_copytuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, 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, and TriggerRelidNameIndexId.

Referenced by ATExecEnableDisableTrigger(), and EnableDisableTrigger().

1789 {
1790  Relation tgrel;
1791  int nkeys;
1792  ScanKeyData keys[2];
1793  SysScanDesc tgscan;
1794  HeapTuple tuple;
1795  bool found;
1796  bool changed;
1797 
1798  /* Scan the relevant entries in pg_triggers */
1799  tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
1800 
1801  ScanKeyInit(&keys[0],
1802  Anum_pg_trigger_tgrelid,
1803  BTEqualStrategyNumber, F_OIDEQ,
1805  if (tgname)
1806  {
1807  ScanKeyInit(&keys[1],
1808  Anum_pg_trigger_tgname,
1809  BTEqualStrategyNumber, F_NAMEEQ,
1810  CStringGetDatum(tgname));
1811  nkeys = 2;
1812  }
1813  else
1814  nkeys = 1;
1815 
1816  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1817  NULL, nkeys, keys);
1818 
1819  found = changed = false;
1820 
1821  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1822  {
1823  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1824 
1825  if (oldtrig->tgisinternal)
1826  {
1827  /* system trigger ... ok to process? */
1828  if (skip_system)
1829  continue;
1830  if (!superuser())
1831  ereport(ERROR,
1832  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1833  errmsg("permission denied: \"%s\" is a system trigger",
1834  NameStr(oldtrig->tgname))));
1835  }
1836 
1837  found = true;
1838 
1839  if (oldtrig->tgenabled != fires_when)
1840  {
1841  /* need to change this one ... make a copy to scribble on */
1842  HeapTuple newtup = heap_copytuple(tuple);
1843  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1844 
1845  newtrig->tgenabled = fires_when;
1846 
1847  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1848 
1849  heap_freetuple(newtup);
1850 
1851  /*
1852  * When altering FOR EACH ROW triggers on a partitioned table, do
1853  * the same on the partitions as well.
1854  */
1855  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1856  (TRIGGER_FOR_ROW(oldtrig->tgtype)))
1857  {
1858  PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1859  int i;
1860 
1861  for (i = 0; i < partdesc->nparts; i++)
1862  {
1863  Relation part;
1864 
1865  part = relation_open(partdesc->oids[i], lockmode);
1866  EnableDisableTrigger(part, NameStr(oldtrig->tgname),
1867  fires_when, skip_system, lockmode);
1868  heap_close(part, NoLock); /* keep lock till commit */
1869  }
1870  }
1871 
1872  changed = true;
1873  }
1874 
1875  InvokeObjectPostAlterHook(TriggerRelationId,
1876  HeapTupleGetOid(tuple), 0);
1877  }
1878 
1879  systable_endscan(tgscan);
1880 
1881  heap_close(tgrel, RowExclusiveLock);
1882 
1883  if (tgname && !found)
1884  ereport(ERROR,
1885  (errcode(ERRCODE_UNDEFINED_OBJECT),
1886  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1887  tgname, RelationGetRelationName(rel))));
1888 
1889  /*
1890  * If we changed anything, broadcast a SI inval message to force each
1891  * backend (including our own!) to rebuild relation's relcache entry.
1892  * Otherwise they will fail to apply the change promptly.
1893  */
1894  if (changed)
1896 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
#define TriggerRelidNameIndexId
Definition: indexing.h:250
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
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:1787
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:561
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:70
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define RelationGetPartitionDesc(relation)
Definition: rel.h:595

◆ ExecARDeleteTriggers()

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

Definition at line 2799 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), heap_freetuple(), 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().

2803 {
2804  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2805 
2806  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2807  (transition_capture && transition_capture->tcs_delete_old_table))
2808  {
2809  HeapTuple trigtuple;
2810 
2811  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2812  if (fdw_trigtuple == NULL)
2813  trigtuple = GetTupleForTrigger(estate,
2814  NULL,
2815  relinfo,
2816  tupleid,
2818  NULL);
2819  else
2820  trigtuple = fdw_trigtuple;
2821 
2823  true, trigtuple, NULL, NIL, NULL,
2824  transition_capture);
2825  if (trigtuple != fdw_trigtuple)
2826  heap_freetuple(trigtuple);
2827  }
2828 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
bool trig_delete_after_row
Definition: reltrigger.h:66
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3239

◆ ExecARInsertTriggers()

void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

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

2584 {
2585  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2586 
2587  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2588  (transition_capture && transition_capture->tcs_insert_new_table))
2590  true, NULL, trigtuple,
2591  recheckIndexes, NULL,
2592  transition_capture);
2593 }
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98

◆ ExecARUpdateTriggers()

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

Definition at line 3068 of file trigger.c.

References AfterTriggerSaveEvent(), GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), 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().

3074 {
3075  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3076 
3077  if ((trigdesc && trigdesc->trig_update_after_row) ||
3078  (transition_capture &&
3079  (transition_capture->tcs_update_old_table ||
3080  transition_capture->tcs_update_new_table)))
3081  {
3082  HeapTuple trigtuple;
3083 
3084  /*
3085  * Note: if the UPDATE is converted into a DELETE+INSERT as part of
3086  * update-partition-key operation, then this function is also called
3087  * separately for DELETE and INSERT to capture transition table rows.
3088  * In such case, either old tuple or new tuple can be NULL.
3089  */
3090  if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
3091  trigtuple = GetTupleForTrigger(estate,
3092  NULL,
3093  relinfo,
3094  tupleid,
3096  NULL);
3097  else
3098  trigtuple = fdw_trigtuple;
3099 
3101  true, trigtuple, newtuple, recheckIndexes,
3102  GetUpdatedColumns(relinfo, estate),
3103  transition_capture);
3104  if (trigtuple != fdw_trigtuple)
3105  heap_freetuple(trigtuple);
3106  }
3107 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
bool trig_update_after_row
Definition: reltrigger.h:61
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:77
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3239

◆ ExecASDeleteTriggers()

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

Definition at line 2719 of file trigger.c.

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

Referenced by fireASTriggers().

2721 {
2722  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2723 
2724  if (trigdesc && trigdesc->trig_delete_after_statement)
2726  false, NULL, NULL, NIL, NULL, transition_capture);
2727 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
bool trig_delete_after_statement
Definition: reltrigger.h:69

◆ ExecASInsertTriggers()

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

Definition at line 2504 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2506 {
2507  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2508 
2509  if (trigdesc && trigdesc->trig_insert_after_statement)
2511  false, NULL, NULL, NIL, NULL, transition_capture);
2512 }
#define NIL
Definition: pg_list.h:69
bool trig_insert_after_statement
Definition: reltrigger.h:59
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98

◆ ExecASTruncateTriggers()

void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3228 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

3229 {
3230  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3231 
3232  if (trigdesc && trigdesc->trig_truncate_after_statement)
3234  false, NULL, NULL, NIL, NULL, NULL);
3235 }
#define NIL
Definition: pg_list.h:69
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
bool trig_truncate_after_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101

◆ ExecASUpdateTriggers()

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

Definition at line 2938 of file trigger.c.

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

Referenced by fireASTriggers().

2940 {
2941  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2942 
2943  if (trigdesc && trigdesc->trig_update_after_statement)
2945  false, NULL, NULL, NIL,
2946  GetUpdatedColumns(relinfo, estate),
2947  transition_capture);
2948 }
#define NIL
Definition: pg_list.h:69
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5698
bool trig_update_after_statement
Definition: reltrigger.h:64
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:77
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100

◆ ExecBRDeleteTriggers()

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

Definition at line 2730 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2734 {
2735  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2736  bool result = true;
2737  TriggerData LocTriggerData;
2738  HeapTuple trigtuple;
2739  HeapTuple newtuple;
2740  TupleTableSlot *newSlot;
2741  int i;
2742 
2743  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2744  if (fdw_trigtuple == NULL)
2745  {
2746  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2747  LockTupleExclusive, &newSlot);
2748  if (trigtuple == NULL)
2749  return false;
2750  }
2751  else
2752  trigtuple = fdw_trigtuple;
2753 
2754  LocTriggerData.type = T_TriggerData;
2755  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2758  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2759  LocTriggerData.tg_newtuple = NULL;
2760  LocTriggerData.tg_oldtable = NULL;
2761  LocTriggerData.tg_newtable = NULL;
2762  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2763  for (i = 0; i < trigdesc->numtriggers; i++)
2764  {
2765  Trigger *trigger = &trigdesc->triggers[i];
2766 
2767  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2768  TRIGGER_TYPE_ROW,
2769  TRIGGER_TYPE_BEFORE,
2770  TRIGGER_TYPE_DELETE))
2771  continue;
2772  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2773  NULL, trigtuple, NULL))
2774  continue;
2775 
2776  LocTriggerData.tg_trigtuple = trigtuple;
2777  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2778  LocTriggerData.tg_trigger = trigger;
2779  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2780  i,
2781  relinfo->ri_TrigFunctions,
2782  relinfo->ri_TrigInstrument,
2783  GetPerTupleMemoryContext(estate));
2784  if (newtuple == NULL)
2785  {
2786  result = false; /* tell caller to suppress delete */
2787  break;
2788  }
2789  if (newtuple != trigtuple)
2790  heap_freetuple(newtuple);
2791  }
2792  if (trigtuple != fdw_trigtuple)
2793  heap_freetuple(trigtuple);
2794 
2795  return result;
2796 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
Relation ri_RelationDesc
Definition: execnodes.h:397
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3239
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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRInsertTriggers()

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

Definition at line 2515 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, TriggerDesc::numtriggers, RelationGetDescr, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, TupleTableSlot::tts_tupleDescriptor, and TriggerData::type.

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

2517 {
2518  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2519  HeapTuple slottuple = ExecMaterializeSlot(slot);
2520  HeapTuple newtuple = slottuple;
2521  HeapTuple oldtuple;
2522  TriggerData LocTriggerData;
2523  int i;
2524 
2525  LocTriggerData.type = T_TriggerData;
2526  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2529  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2530  LocTriggerData.tg_newtuple = NULL;
2531  LocTriggerData.tg_oldtable = NULL;
2532  LocTriggerData.tg_newtable = NULL;
2533  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2534  for (i = 0; i < trigdesc->numtriggers; i++)
2535  {
2536  Trigger *trigger = &trigdesc->triggers[i];
2537 
2538  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2539  TRIGGER_TYPE_ROW,
2540  TRIGGER_TYPE_BEFORE,
2541  TRIGGER_TYPE_INSERT))
2542  continue;
2543  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2544  NULL, NULL, newtuple))
2545  continue;
2546 
2547  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2548  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2549  LocTriggerData.tg_trigger = trigger;
2550  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2551  i,
2552  relinfo->ri_TrigFunctions,
2553  relinfo->ri_TrigInstrument,
2554  GetPerTupleMemoryContext(estate));
2555  if (oldtuple != newtuple && oldtuple != slottuple)
2556  heap_freetuple(oldtuple);
2557  if (newtuple == NULL)
2558  return NULL; /* "do nothing" */
2559  }
2560 
2561  if (newtuple != slottuple)
2562  {
2563  /*
2564  * Return the modified tuple using the es_trig_tuple_slot. We assume
2565  * the tuple was allocated in per-tuple memory context, and therefore
2566  * will go away by itself. The tuple table slot should not try to
2567  * clear it.
2568  */
2569  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2570  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2571 
2572  if (newslot->tts_tupleDescriptor != tupdesc)
2573  ExecSetSlotDescriptor(newslot, tupdesc);
2574  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2575  slot = newslot;
2576  }
2577  return slot;
2578 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
Relation ri_RelationDesc
Definition: execnodes.h:397
#define RelationGetDescr(relation)
Definition: rel.h:433
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:512
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:281
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:781
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
#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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRUpdateTriggers()

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

Definition at line 2951 of file trigger.c.

References Assert, EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecFilterJunk(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), ExecUpdateLockMode(), GetPerTupleMemoryContext, GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), HeapTupleIsValid, i, InvalidBuffer, ItemPointerIsValid, TriggerDesc::numtriggers, RelationGetDescr, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, TupleTableSlot::tts_tupleDescriptor, and TriggerData::type.

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2956 {
2957  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2958  HeapTuple slottuple = ExecMaterializeSlot(slot);
2959  HeapTuple newtuple = slottuple;
2960  TriggerData LocTriggerData;
2961  HeapTuple trigtuple;
2962  HeapTuple oldtuple;
2963  TupleTableSlot *newSlot;
2964  int i;
2965  Bitmapset *updatedCols;
2966  LockTupleMode lockmode;
2967 
2968  /* Determine lock mode to use */
2969  lockmode = ExecUpdateLockMode(estate, relinfo);
2970 
2971  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2972  if (fdw_trigtuple == NULL)
2973  {
2974  /* get a copy of the on-disk tuple we are planning to update */
2975  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2976  lockmode, &newSlot);
2977  if (trigtuple == NULL)
2978  return NULL; /* cancel the update action */
2979  }
2980  else
2981  {
2982  trigtuple = fdw_trigtuple;
2983  newSlot = NULL;
2984  }
2985 
2986  /*
2987  * In READ COMMITTED isolation level it's possible that target tuple was
2988  * changed due to concurrent update. In that case we have a raw subplan
2989  * output tuple in newSlot, and need to run it through the junk filter to
2990  * produce an insertable tuple.
2991  *
2992  * Caution: more than likely, the passed-in slot is the same as the
2993  * junkfilter's output slot, so we are clobbering the original value of
2994  * slottuple by doing the filtering. This is OK since neither we nor our
2995  * caller have any more interest in the prior contents of that slot.
2996  */
2997  if (newSlot != NULL)
2998  {
2999  slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
3000  slottuple = ExecMaterializeSlot(slot);
3001  newtuple = slottuple;
3002  }
3003 
3004 
3005  LocTriggerData.type = T_TriggerData;
3006  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3009  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3010  LocTriggerData.tg_oldtable = NULL;
3011  LocTriggerData.tg_newtable = NULL;
3012  updatedCols = GetUpdatedColumns(relinfo, estate);
3013  for (i = 0; i < trigdesc->numtriggers; i++)
3014  {
3015  Trigger *trigger = &trigdesc->triggers[i];
3016 
3017  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3018  TRIGGER_TYPE_ROW,
3019  TRIGGER_TYPE_BEFORE,
3020  TRIGGER_TYPE_UPDATE))
3021  continue;
3022  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3023  updatedCols, trigtuple, newtuple))
3024  continue;
3025 
3026  LocTriggerData.tg_trigtuple = trigtuple;
3027  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3028  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3029  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3030  LocTriggerData.tg_trigger = trigger;
3031  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3032  i,
3033  relinfo->ri_TrigFunctions,
3034  relinfo->ri_TrigInstrument,
3035  GetPerTupleMemoryContext(estate));
3036  if (oldtuple != newtuple && oldtuple != slottuple)
3037  heap_freetuple(oldtuple);
3038  if (newtuple == NULL)
3039  {
3040  if (trigtuple != fdw_trigtuple)
3041  heap_freetuple(trigtuple);
3042  return NULL; /* "do nothing" */
3043  }
3044  }
3045  if (trigtuple != fdw_trigtuple && trigtuple != newtuple)
3046  heap_freetuple(trigtuple);
3047 
3048  if (newtuple != slottuple)
3049  {
3050  /*
3051  * Return the modified tuple using the es_trig_tuple_slot. We assume
3052  * the tuple was allocated in per-tuple memory context, and therefore
3053  * will go away by itself. The tuple table slot should not try to
3054  * clear it.
3055  */
3056  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
3057  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
3058 
3059  if (newslot->tts_tupleDescriptor != tupdesc)
3060  ExecSetSlotDescriptor(newslot, tupdesc);
3061  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
3062  slot = newslot;
3063  }
3064  return slot;
3065 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
JunkFilter * ri_junkFilter
Definition: execnodes.h:439
Relation ri_RelationDesc
Definition: execnodes.h:397
#define RelationGetDescr(relation)
Definition: rel.h:433
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
HeapTuple tg_trigtuple
Definition: trigger.h:35
LockTupleMode
Definition: heapam.h:38
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:512
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:281
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:77
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2379
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:781
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3239
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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSDeleteTriggers()

void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2662 of file trigger.c.

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

Referenced by fireBSTriggers().

2663 {
2664  TriggerDesc *trigdesc;
2665  int i;
2666  TriggerData LocTriggerData;
2667 
2668  trigdesc = relinfo->ri_TrigDesc;
2669 
2670  if (trigdesc == NULL)
2671  return;
2672  if (!trigdesc->trig_delete_before_statement)
2673  return;
2674 
2675  /* no-op if we already fired BS triggers in this context */
2677  CMD_DELETE))
2678  return;
2679 
2680  LocTriggerData.type = T_TriggerData;
2681  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2683  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2684  LocTriggerData.tg_trigtuple = NULL;
2685  LocTriggerData.tg_newtuple = NULL;
2686  LocTriggerData.tg_oldtable = NULL;
2687  LocTriggerData.tg_newtable = NULL;
2688  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2689  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2690  for (i = 0; i < trigdesc->numtriggers; i++)
2691  {
2692  Trigger *trigger = &trigdesc->triggers[i];
2693  HeapTuple newtuple;
2694 
2695  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2696  TRIGGER_TYPE_STATEMENT,
2697  TRIGGER_TYPE_BEFORE,
2698  TRIGGER_TYPE_DELETE))
2699  continue;
2700  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2701  NULL, NULL, NULL))
2702  continue;
2703 
2704  LocTriggerData.tg_trigger = trigger;
2705  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2706  i,
2707  relinfo->ri_TrigFunctions,
2708  relinfo->ri_TrigInstrument,
2709  GetPerTupleMemoryContext(estate));
2710 
2711  if (newtuple)
2712  ereport(ERROR,
2713  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2714  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2715  }
2716 }
Relation ri_RelationDesc
Definition: execnodes.h:397
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:6010
#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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
bool trig_delete_before_statement
Definition: reltrigger.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
int errmsg(const char *fmt,...)
Definition: elog.c:797
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:2353
#define RelationGetRelid(relation)
Definition: rel.h:407
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSInsertTriggers()

void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2447 of file trigger.c.

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

Referenced by CopyFrom(), and fireBSTriggers().

2448 {
2449  TriggerDesc *trigdesc;
2450  int i;
2451  TriggerData LocTriggerData;
2452 
2453  trigdesc = relinfo->ri_TrigDesc;
2454 
2455  if (trigdesc == NULL)
2456  return;
2457  if (!trigdesc->trig_insert_before_statement)
2458  return;
2459 
2460  /* no-op if we already fired BS triggers in this context */
2462  CMD_INSERT))
2463  return;
2464 
2465  LocTriggerData.type = T_TriggerData;
2466  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2468  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2469  LocTriggerData.tg_trigtuple = NULL;
2470  LocTriggerData.tg_newtuple = NULL;
2471  LocTriggerData.tg_oldtable = NULL;
2472  LocTriggerData.tg_newtable = NULL;
2473  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2474  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2475  for (i = 0; i < trigdesc->numtriggers; i++)
2476  {
2477  Trigger *trigger = &trigdesc->triggers[i];
2478  HeapTuple newtuple;
2479 
2480  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2481  TRIGGER_TYPE_STATEMENT,
2482  TRIGGER_TYPE_BEFORE,
2483  TRIGGER_TYPE_INSERT))
2484  continue;
2485  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2486  NULL, NULL, NULL))
2487  continue;
2488 
2489  LocTriggerData.tg_trigger = trigger;
2490  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2491  i,
2492  relinfo->ri_TrigFunctions,
2493  relinfo->ri_TrigInstrument,
2494  GetPerTupleMemoryContext(estate));
2495 
2496  if (newtuple)
2497  ereport(ERROR,
2498  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2499  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2500  }
2501 }
Relation ri_RelationDesc
Definition: execnodes.h:397
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:6010
#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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
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:494
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
int errmsg(const char *fmt,...)
Definition: elog.c:797
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:2353
#define RelationGetRelid(relation)
Definition: rel.h:407
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSTruncateTriggers()

void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3176 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

3177 {
3178  TriggerDesc *trigdesc;
3179  int i;
3180  TriggerData LocTriggerData;
3181 
3182  trigdesc = relinfo->ri_TrigDesc;
3183 
3184  if (trigdesc == NULL)
3185  return;
3186  if (!trigdesc->trig_truncate_before_statement)
3187  return;
3188 
3189  LocTriggerData.type = T_TriggerData;
3190  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
3192  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3193  LocTriggerData.tg_trigtuple = NULL;
3194  LocTriggerData.tg_newtuple = NULL;
3195  LocTriggerData.tg_oldtable = NULL;
3196  LocTriggerData.tg_newtable = NULL;
3197  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3198  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3199  for (i = 0; i < trigdesc->numtriggers; i++)
3200  {
3201  Trigger *trigger = &trigdesc->triggers[i];
3202  HeapTuple newtuple;
3203 
3204  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3205  TRIGGER_TYPE_STATEMENT,
3206  TRIGGER_TYPE_BEFORE,
3207  TRIGGER_TYPE_TRUNCATE))
3208  continue;
3209  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3210  NULL, NULL, NULL))
3211  continue;
3212 
3213  LocTriggerData.tg_trigger = trigger;
3214  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3215  i,
3216  relinfo->ri_TrigFunctions,
3217  relinfo->ri_TrigInstrument,
3218  GetPerTupleMemoryContext(estate));
3219 
3220  if (newtuple)
3221  ereport(ERROR,
3222  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3223  errmsg("BEFORE STATEMENT trigger cannot return a value")));
3224  }
3225 }
Relation ri_RelationDesc
Definition: execnodes.h:397
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
bool trig_truncate_before_statement
Definition: reltrigger.h:71
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
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:494
int errmsg(const char *fmt,...)
Definition: elog.c:797
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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSUpdateTriggers()

void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2878 of file trigger.c.

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

Referenced by fireBSTriggers().

2879 {
2880  TriggerDesc *trigdesc;
2881  int i;
2882  TriggerData LocTriggerData;
2883  Bitmapset *updatedCols;
2884 
2885  trigdesc = relinfo->ri_TrigDesc;
2886 
2887  if (trigdesc == NULL)
2888  return;
2889  if (!trigdesc->trig_update_before_statement)
2890  return;
2891 
2892  /* no-op if we already fired BS triggers in this context */
2894  CMD_UPDATE))
2895  return;
2896 
2897  updatedCols = GetUpdatedColumns(relinfo, estate);
2898 
2899  LocTriggerData.type = T_TriggerData;
2900  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2902  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2903  LocTriggerData.tg_trigtuple = NULL;
2904  LocTriggerData.tg_newtuple = NULL;
2905  LocTriggerData.tg_oldtable = NULL;
2906  LocTriggerData.tg_newtable = NULL;
2907  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2908  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2909  for (i = 0; i < trigdesc->numtriggers; i++)
2910  {
2911  Trigger *trigger = &trigdesc->triggers[i];
2912  HeapTuple newtuple;
2913 
2914  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2915  TRIGGER_TYPE_STATEMENT,
2916  TRIGGER_TYPE_BEFORE,
2917  TRIGGER_TYPE_UPDATE))
2918  continue;
2919  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2920  updatedCols, NULL, NULL))
2921  continue;
2922 
2923  LocTriggerData.tg_trigger = trigger;
2924  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2925  i,
2926  relinfo->ri_TrigFunctions,
2927  relinfo->ri_TrigInstrument,
2928  GetPerTupleMemoryContext(estate));
2929 
2930  if (newtuple)
2931  ereport(ERROR,
2932  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2933  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2934  }
2935 }
Relation ri_RelationDesc
Definition: execnodes.h:397
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
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:6010
#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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:77
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:494
int errmsg(const char *fmt,...)
Definition: elog.c:797
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:2353
#define RelationGetRelid(relation)
Definition: rel.h:407
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRDeleteTriggers()

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

Definition at line 2831 of file trigger.c.

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

Referenced by ExecDelete().

2833 {
2834  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2835  TriggerData LocTriggerData;
2836  HeapTuple rettuple;
2837  int i;
2838 
2839  LocTriggerData.type = T_TriggerData;
2840  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2843  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2844  LocTriggerData.tg_newtuple = NULL;
2845  LocTriggerData.tg_oldtable = NULL;
2846  LocTriggerData.tg_newtable = NULL;
2847  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2848  for (i = 0; i < trigdesc->numtriggers; i++)
2849  {
2850  Trigger *trigger = &trigdesc->triggers[i];
2851 
2852  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2853  TRIGGER_TYPE_ROW,
2854  TRIGGER_TYPE_INSTEAD,
2855  TRIGGER_TYPE_DELETE))
2856  continue;
2857  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2858  NULL, trigtuple, NULL))
2859  continue;
2860 
2861  LocTriggerData.tg_trigtuple = trigtuple;
2862  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2863  LocTriggerData.tg_trigger = trigger;
2864  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2865  i,
2866  relinfo->ri_TrigFunctions,
2867  relinfo->ri_TrigInstrument,
2868  GetPerTupleMemoryContext(estate));
2869  if (rettuple == NULL)
2870  return false; /* Delete was suppressed */
2871  if (rettuple != trigtuple)
2872  heap_freetuple(rettuple);
2873  }
2874  return true;
2875 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
Relation ri_RelationDesc
Definition: execnodes.h:397
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRInsertTriggers()

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

Definition at line 2596 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, TriggerDesc::numtriggers, RelationGetDescr, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_INSTEAD, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, TupleTableSlot::tts_tupleDescriptor, and TriggerData::type.

Referenced by CopyFrom(), and ExecInsert().

2598 {
2599  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2600  HeapTuple slottuple = ExecMaterializeSlot(slot);
2601  HeapTuple newtuple = slottuple;
2602  HeapTuple oldtuple;
2603  TriggerData LocTriggerData;
2604  int i;
2605 
2606  LocTriggerData.type = T_TriggerData;
2607  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2610  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2611  LocTriggerData.tg_newtuple = NULL;
2612  LocTriggerData.tg_oldtable = NULL;
2613  LocTriggerData.tg_newtable = NULL;
2614  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2615  for (i = 0; i < trigdesc->numtriggers; i++)
2616  {
2617  Trigger *trigger = &trigdesc->triggers[i];
2618 
2619  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2620  TRIGGER_TYPE_ROW,
2621  TRIGGER_TYPE_INSTEAD,
2622  TRIGGER_TYPE_INSERT))
2623  continue;
2624  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2625  NULL, NULL, newtuple))
2626  continue;
2627 
2628  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2629  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2630  LocTriggerData.tg_trigger = trigger;
2631  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2632  i,
2633  relinfo->ri_TrigFunctions,
2634  relinfo->ri_TrigInstrument,
2635  GetPerTupleMemoryContext(estate));
2636  if (oldtuple != newtuple && oldtuple != slottuple)
2637  heap_freetuple(oldtuple);
2638  if (newtuple == NULL)
2639  return NULL; /* "do nothing" */
2640  }
2641 
2642  if (newtuple != slottuple)
2643  {
2644  /*
2645  * Return the modified tuple using the es_trig_tuple_slot. We assume
2646  * the tuple was allocated in per-tuple memory context, and therefore
2647  * will go away by itself. The tuple table slot should not try to
2648  * clear it.
2649  */
2650  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2651  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2652 
2653  if (newslot->tts_tupleDescriptor != tupdesc)
2654  ExecSetSlotDescriptor(newslot, tupdesc);
2655  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2656  slot = newslot;
2657  }
2658  return slot;
2659 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
Relation ri_RelationDesc
Definition: execnodes.h:397
#define RelationGetDescr(relation)
Definition: rel.h:433
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:512
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:281
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:781
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
#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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRUpdateTriggers()

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

Definition at line 3110 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, TriggerDesc::numtriggers, RelationGetDescr, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_newtable, TriggerData::tg_newtuple, TriggerData::tg_newtuplebuf, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, TriggerData::tg_trigtuplebuf, Trigger::tgtype, TRIGGER_EVENT_INSTEAD, TRIGGER_EVENT_ROW, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, TupleTableSlot::tts_tupleDescriptor, and TriggerData::type.

Referenced by ExecUpdate().

3112 {
3113  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3114  HeapTuple slottuple = ExecMaterializeSlot(slot);
3115  HeapTuple newtuple = slottuple;
3116  TriggerData LocTriggerData;
3117  HeapTuple oldtuple;
3118  int i;
3119 
3120  LocTriggerData.type = T_TriggerData;
3121  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
3124  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3125  LocTriggerData.tg_oldtable = NULL;
3126  LocTriggerData.tg_newtable = NULL;
3127  for (i = 0; i < trigdesc->numtriggers; i++)
3128  {
3129  Trigger *trigger = &trigdesc->triggers[i];
3130 
3131  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3132  TRIGGER_TYPE_ROW,
3133  TRIGGER_TYPE_INSTEAD,
3134  TRIGGER_TYPE_UPDATE))
3135  continue;
3136  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3137  NULL, trigtuple, newtuple))
3138  continue;
3139 
3140  LocTriggerData.tg_trigtuple = trigtuple;
3141  LocTriggerData.tg_newtuple = oldtuple = newtuple;
3142  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3143  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3144  LocTriggerData.tg_trigger = trigger;
3145  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3146  i,
3147  relinfo->ri_TrigFunctions,
3148  relinfo->ri_TrigInstrument,
3149  GetPerTupleMemoryContext(estate));
3150  if (oldtuple != newtuple && oldtuple != slottuple)
3151  heap_freetuple(oldtuple);
3152  if (newtuple == NULL)
3153  return NULL; /* "do nothing" */
3154  }
3155 
3156  if (newtuple != slottuple)
3157  {
3158  /*
3159  * Return the modified tuple using the es_trig_tuple_slot. We assume
3160  * the tuple was allocated in per-tuple memory context, and therefore
3161  * will go away by itself. The tuple table slot should not try to
3162  * clear it.
3163  */
3164  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
3165  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
3166 
3167  if (newslot->tts_tupleDescriptor != tupdesc)
3168  ExecSetSlotDescriptor(newslot, tupdesc);
3169  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
3170  slot = newslot;
3171  }
3172  return slot;
3173 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:356
Relation ri_RelationDesc
Definition: execnodes.h:397
#define RelationGetDescr(relation)
Definition: rel.h:433
Buffer tg_newtuplebuf
Definition: trigger.h:39
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:418
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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
Buffer tg_trigtuplebuf
Definition: trigger.h:38
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:512
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:409
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:281
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3388
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:781
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:494
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:2353
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:412
Relation tg_relation
Definition: trigger.h:34

◆ FindTriggerIncompatibleWithInheritance()

const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2323 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2324 {
2325  if (trigdesc != NULL)
2326  {
2327  int i;
2328 
2329  for (i = 0; i < trigdesc->numtriggers; ++i)
2330  {
2331  Trigger *trigger = &trigdesc->triggers[i];
2332 
2333  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2334  return trigger->tgname;
2335  }
2336  }
2337 
2338  return NULL;
2339 }
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 2193 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().

2194 {
2195  Trigger *trigger;
2196  int i;
2197 
2198  if (trigdesc == NULL)
2199  return;
2200 
2201  trigger = trigdesc->triggers;
2202  for (i = 0; i < trigdesc->numtriggers; i++)
2203  {
2204  pfree(trigger->tgname);
2205  if (trigger->tgnattr > 0)
2206  pfree(trigger->tgattr);
2207  if (trigger->tgnargs > 0)
2208  {
2209  while (--(trigger->tgnargs) >= 0)
2210  pfree(trigger->tgargs[trigger->tgnargs]);
2211  pfree(trigger->tgargs);
2212  }
2213  if (trigger->tgqual)
2214  pfree(trigger->tgqual);
2215  if (trigger->tgoldtable)
2216  pfree(trigger->tgoldtable);
2217  if (trigger->tgnewtable)
2218  pfree(trigger->tgnewtable);
2219  trigger++;
2220  }
2221  pfree(trigdesc->triggers);
2222  pfree(trigdesc);
2223 }
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 1559 of file trigger.c.

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_rel_name(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and TriggerRelidNameIndexId.

Referenced by get_object_address_relobject().

1560 {
1561  Relation tgrel;
1562  ScanKeyData skey[2];
1563  SysScanDesc tgscan;
1564  HeapTuple tup;
1565  Oid oid;
1566 
1567  /*
1568  * Find the trigger, verify permissions, set up object address
1569  */
1570  tgrel = heap_open(TriggerRelationId, AccessShareLock);
1571 
1572  ScanKeyInit(&skey[0],
1573  Anum_pg_trigger_tgrelid,
1574  BTEqualStrategyNumber, F_OIDEQ,
1575  ObjectIdGetDatum(relid));
1576  ScanKeyInit(&skey[1],
1577  Anum_pg_trigger_tgname,
1578  BTEqualStrategyNumber, F_NAMEEQ,
1579  CStringGetDatum(trigname));
1580 
1581  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1582  NULL, 2, skey);
1583 
1584  tup = systable_getnext(tgscan);
1585 
1586  if (!HeapTupleIsValid(tup))
1587  {
1588  if (!missing_ok)
1589  ereport(ERROR,
1590  (errcode(ERRCODE_UNDEFINED_OBJECT),
1591  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1592  trigname, get_rel_name(relid))));
1593  oid = InvalidOid;
1594  }
1595  else
1596  {
1597  oid = HeapTupleGetOid(tup);
1598  }
1599 
1600  systable_endscan(tgscan);
1601  heap_close(tgrel, AccessShareLock);
1602  return oid;
1603 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
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:331
#define TriggerRelidNameIndexId
Definition: indexing.h:250
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define CStringGetDatum(X)
Definition: postgres.h:561
#define ereport(elevel, rest)
Definition: elog.h:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
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 4643 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().

4644 {
4646  bool need_old,
4647  need_new;
4648  AfterTriggersTableData *table;
4649  MemoryContext oldcxt;
4650  ResourceOwner saveResourceOwner;
4651 
4652  if (trigdesc == NULL)
4653  return NULL;
4654 
4655  /* Detect which table(s) we need. */
4656  switch (cmdType)
4657  {
4658  case CMD_INSERT:
4659  need_old = false;
4660  need_new = trigdesc->trig_insert_new_table;
4661  break;
4662  case CMD_UPDATE:
4663  need_old = trigdesc->trig_update_old_table;
4664  need_new = trigdesc->trig_update_new_table;
4665  break;
4666  case CMD_DELETE:
4667  need_old = trigdesc->trig_delete_old_table;
4668  need_new = false;
4669  break;
4670  default:
4671  elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
4672  need_old = need_new = false; /* keep compiler quiet */
4673  break;
4674  }
4675  if (!need_old && !need_new)
4676  return NULL;
4677 
4678  /* Check state, like AfterTriggerSaveEvent. */
4679  if (afterTriggers.query_depth < 0)
4680  elog(ERROR, "MakeTransitionCaptureState() called outside of query");
4681 
4682  /* Be sure we have enough space to record events at this query depth. */
4685 
4686  /*
4687  * Find or create an AfterTriggersTableData struct to hold the
4688  * tuplestore(s). If there's a matching struct but it's marked closed,
4689  * ignore it; we need a newer one.
4690  *
4691  * Note: the AfterTriggersTableData list, as well as the tuplestores, are
4692  * allocated in the current (sub)transaction's CurTransactionContext, and
4693  * the tuplestores are managed by the (sub)transaction's resource owner.
4694  * This is sufficient lifespan because we do not allow triggers using
4695  * transition tables to be deferrable; they will be fired during
4696  * AfterTriggerEndQuery, after which it's okay to delete the data.
4697  */
4698  table = GetAfterTriggersTableData(relid, cmdType);
4699 
4700  /* Now create required tuplestore(s), if we don't have them already. */
4702  saveResourceOwner = CurrentResourceOwner;
4704 
4705  if (need_old && table->old_tuplestore == NULL)
4706  table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4707  if (need_new && table->new_tuplestore == NULL)
4708  table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4709 
4710  CurrentResourceOwner = saveResourceOwner;
4711  MemoryContextSwitchTo(oldcxt);
4712 
4713  /* Now build the TransitionCaptureState struct, in caller's context */
4715  state->tcs_delete_old_table = trigdesc->trig_delete_old_table;
4716  state->tcs_update_old_table = trigdesc->trig_update_old_table;
4717  state->tcs_update_new_table = trigdesc->trig_update_new_table;
4718  state->tcs_insert_new_table = trigdesc->trig_insert_new_table;
4719  state->tcs_private = table;
4720 
4721  return state;
4722 }
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:141
ResourceOwner CurrentResourceOwner
Definition: resowner.c:140
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext CurTransactionContext
Definition: mcxt.c:50
Tuplestorestate * old_tuplestore
Definition: trigger.c:3837
bool trig_update_new_table
Definition: