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

Go to the source code of this file.

Data Structures

struct  TriggerData
 
struct  TransitionCaptureState
 

Macros

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

Typedefs

typedef uint32 TriggerEvent
 
typedef struct TriggerData TriggerData
 
typedef struct TransitionCaptureState TransitionCaptureState
 

Functions

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

Variables

PGDLLIMPORT int SessionReplicationRole
 

Macro Definition Documentation

◆ AFTER_TRIGGER_DEFERRABLE

#define AFTER_TRIGGER_DEFERRABLE   0x00000020

Definition at line 106 of file trigger.h.

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

◆ AFTER_TRIGGER_INITDEFERRED

#define AFTER_TRIGGER_INITDEFERRED   0x00000040

Definition at line 107 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 264 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 265 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

◆ RI_TRIGGER_PK

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

Definition at line 263 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 141 of file trigger.h.

◆ SESSION_REPLICATION_ROLE_ORIGIN

#define SESSION_REPLICATION_ROLE_ORIGIN   0

Definition at line 139 of file trigger.h.

◆ SESSION_REPLICATION_ROLE_REPLICA

#define SESSION_REPLICATION_ROLE_REPLICA   1

Definition at line 140 of file trigger.h.

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

◆ TRIGGER_DISABLED

#define TRIGGER_DISABLED   'D'

Definition at line 151 of file trigger.h.

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

◆ TRIGGER_EVENT_AFTER

#define TRIGGER_EVENT_AFTER   0x00000000

Definition at line 100 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 101 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 102 of file trigger.h.

◆ TRIGGER_EVENT_TRUNCATE

#define TRIGGER_EVENT_TRUNCATE   0x00000003

Definition at line 94 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), ExecASTruncateTriggers(), and ExecBSTruncateTriggers().

◆ 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 149 of file trigger.h.

Referenced by ATExecCmd().

◆ TRIGGER_FIRES_ON_ORIGIN

◆ TRIGGER_FIRES_ON_REPLICA

#define TRIGGER_FIRES_ON_REPLICA   'R'

Definition at line 150 of file trigger.h.

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

Typedef Documentation

◆ TransitionCaptureState

◆ TriggerData

typedef struct TriggerData TriggerData

◆ TriggerEvent

Definition at line 28 of file trigger.h.

Function Documentation

◆ AfterTriggerBeginQuery()

void AfterTriggerBeginQuery ( void  )

Definition at line 4520 of file trigger.c.

References AfterTriggersData::query_depth.

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

4521 {
4522  /* Increase the query stack depth */
4524 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerBeginSubXact()

void AfterTriggerBeginSubXact ( void  )

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

4791 {
4792  int my_level = GetCurrentTransactionNestLevel();
4793 
4794  /*
4795  * Allocate more space in the trans_stack if needed. (Note: because the
4796  * minimum nest level of a subtransaction is 2, we waste the first couple
4797  * entries of the array; not worth the notational effort to avoid it.)
4798  */
4799  while (my_level >= afterTriggers.maxtransdepth)
4800  {
4801  if (afterTriggers.maxtransdepth == 0)
4802  {
4803  /* Arbitrarily initialize for max of 8 subtransaction levels */
4806  8 * sizeof(AfterTriggersTransData));
4808  }
4809  else
4810  {
4811  /* repalloc will keep the stack in the same context */
4812  int new_alloc = afterTriggers.maxtransdepth * 2;
4813 
4816  new_alloc * sizeof(AfterTriggersTransData));
4817  afterTriggers.maxtransdepth = new_alloc;
4818  }
4819  }
4820 
4821  /*
4822  * Push the current information into the stack. The SET CONSTRAINTS state
4823  * is not saved until/unless changed. Likewise, we don't make a
4824  * per-subtransaction event context until needed.
4825  */
4826  afterTriggers.trans_stack[my_level].state = NULL;
4830 }
AfterTriggersTransData * trans_stack
Definition: trigger.c:3497
MemoryContext TopTransactionContext
Definition: mcxt.c:53
AfterTriggerEventList events
Definition: trigger.c:3512
CommandId firing_counter
Definition: trigger.c:3514
CommandId firing_counter
Definition: trigger.c:3486
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
AfterTriggerEventList events
Definition: trigger.c:3488
static AfterTriggersData afterTriggers
Definition: trigger.c:3531
SetConstraintState state
Definition: trigger.c:3511

◆ AfterTriggerBeginXact()

void AfterTriggerBeginXact ( void  )

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

4489 {
4490  /*
4491  * Initialize after-trigger state structure to empty
4492  */
4493  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4495 
4496  /*
4497  * Verify that there is no leftover state remaining. If these assertions
4498  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4499  * up properly.
4500  */
4501  Assert(afterTriggers.state == NULL);
4502  Assert(afterTriggers.query_stack == NULL);
4504  Assert(afterTriggers.event_cxt == NULL);
4505  Assert(afterTriggers.events.head == NULL);
4506  Assert(afterTriggers.trans_stack == NULL);
4508 }
uint32 CommandId
Definition: c.h:601
AfterTriggersTransData * trans_stack
Definition: trigger.c:3497
AfterTriggersQueryData * query_stack
Definition: trigger.c:3492
SetConstraintState state
Definition: trigger.c:3487
CommandId firing_counter
Definition: trigger.c:3486
#define Assert(condition)
Definition: c.h:804
AfterTriggerEventChunk * head
Definition: trigger.c:3380
MemoryContext event_cxt
Definition: trigger.c:3489
AfterTriggerEventList events
Definition: trigger.c:3488
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerEndQuery()

void AfterTriggerEndQuery ( EState estate)

Definition at line 4540 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 CopyFrom(), ExecuteTruncateGuts(), finish_estate(), and standard_ExecutorFinish().

4541 {
4543 
4544  /* Must be inside a query, too */
4546 
4547  /*
4548  * If we never even got as far as initializing the event stack, there
4549  * certainly won't be any events, so exit quickly.
4550  */
4552  {
4554  return;
4555  }
4556 
4557  /*
4558  * Process all immediate-mode triggers queued by the query, and move the
4559  * deferred ones to the main list of deferred events.
4560  *
4561  * Notice that we decide which ones will be fired, and put the deferred
4562  * ones on the main list, before anything is actually fired. This ensures
4563  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4564  * IMMEDIATE: all events we have decided to defer will be available for it
4565  * to fire.
4566  *
4567  * We loop in case a trigger queues more events at the same query level.
4568  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4569  * will instead fire any triggers in a dedicated query level. Foreign key
4570  * enforcement triggers do add to the current query level, thanks to their
4571  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4572  * C-language triggers might do likewise.
4573  *
4574  * If we find no firable events, we don't have to increment
4575  * firing_counter.
4576  */
4578 
4579  for (;;)
4580  {
4582  {
4583  CommandId firing_id = afterTriggers.firing_counter++;
4584  AfterTriggerEventChunk *oldtail = qs->events.tail;
4585 
4586  if (afterTriggerInvokeEvents(&qs->events, firing_id, estate, false))
4587  break; /* all fired */
4588 
4589  /*
4590  * Firing a trigger could result in query_stack being repalloc'd,
4591  * so we must recalculate qs after each afterTriggerInvokeEvents
4592  * call. Furthermore, it's unsafe to pass delete_ok = true here,
4593  * because that could cause afterTriggerInvokeEvents to try to
4594  * access qs->events after the stack has been repalloc'd.
4595  */
4597 
4598  /*
4599  * We'll need to scan the events list again. To reduce the cost
4600  * of doing so, get rid of completely-fired chunks. We know that
4601  * all events were marked IN_PROGRESS or DONE at the conclusion of
4602  * afterTriggerMarkEvents, so any still-interesting events must
4603  * have been added after that, and so must be in the chunk that
4604  * was then the tail chunk, or in later chunks. So, zap all
4605  * chunks before oldtail. This is approximately the same set of
4606  * events we would have gotten rid of by passing delete_ok = true.
4607  */
4608  Assert(oldtail != NULL);
4609  while (qs->events.head != oldtail)
4611  }
4612  else
4613  break;
4614  }
4615 
4616  /* Release query-level-local storage, including tuplestores if any */
4618 
4620 }
uint32 CommandId
Definition: c.h:601
static void afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs)
Definition: trigger.c:3818
AfterTriggersQueryData * query_stack
Definition: trigger.c:3492
AfterTriggerEventChunk * tail
Definition: trigger.c:3381
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
CommandId firing_counter
Definition: trigger.c:3486
#define Assert(condition)
Definition: c.h:804
AfterTriggerEventChunk * head
Definition: trigger.c:3380
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4086
AfterTriggerEventList events
Definition: trigger.c:3488
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4631
AfterTriggerEventList events
Definition: trigger.c:3503
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerEndSubXact()

void AfterTriggerEndSubXact ( bool  isCommit)

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

4839 {
4840  int my_level = GetCurrentTransactionNestLevel();
4842  AfterTriggerEvent event;
4843  AfterTriggerEventChunk *chunk;
4844  CommandId subxact_firing_id;
4845 
4846  /*
4847  * Pop the prior state if needed.
4848  */
4849  if (isCommit)
4850  {
4851  Assert(my_level < afterTriggers.maxtransdepth);
4852  /* If we saved a prior state, we don't need it anymore */
4853  state = afterTriggers.trans_stack[my_level].state;
4854  if (state != NULL)
4855  pfree(state);
4856  /* this avoids double pfree if error later: */
4857  afterTriggers.trans_stack[my_level].state = NULL;
4860  }
4861  else
4862  {
4863  /*
4864  * Aborting. It is possible subxact start failed before calling
4865  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4866  * trans_stack levels that aren't there.
4867  */
4868  if (my_level >= afterTriggers.maxtransdepth)
4869  return;
4870 
4871  /*
4872  * Release query-level storage for queries being aborted, and restore
4873  * query_depth to its pre-subxact value. This assumes that a
4874  * subtransaction will not add events to query levels started in a
4875  * earlier transaction state.
4876  */
4878  {
4882  }
4885 
4886  /*
4887  * Restore the global deferred-event list to its former length,
4888  * discarding any events queued by the subxact.
4889  */
4891  &afterTriggers.trans_stack[my_level].events);
4892 
4893  /*
4894  * Restore the trigger state. If the saved state is NULL, then this
4895  * subxact didn't save it, so it doesn't need restoring.
4896  */
4897  state = afterTriggers.trans_stack[my_level].state;
4898  if (state != NULL)
4899  {
4901  afterTriggers.state = state;
4902  }
4903  /* this avoids double pfree if error later: */
4904  afterTriggers.trans_stack[my_level].state = NULL;
4905 
4906  /*
4907  * Scan for any remaining deferred events that were marked DONE or IN
4908  * PROGRESS by this subxact or a child, and un-mark them. We can
4909  * recognize such events because they have a firing ID greater than or
4910  * equal to the firing_counter value we saved at subtransaction start.
4911  * (This essentially assumes that the current subxact includes all
4912  * subxacts started after it.)
4913  */
4914  subxact_firing_id = afterTriggers.trans_stack[my_level].firing_counter;
4916  {
4917  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4918 
4919  if (event->ate_flags &
4921  {
4922  if (evtshared->ats_firing_id >= subxact_firing_id)
4923  event->ate_flags &=
4925  }
4926  }
4927  }
4928 }
uint32 CommandId
Definition: c.h:601
AfterTriggersTransData * trans_stack
Definition: trigger.c:3497
TriggerFlags ate_flags
Definition: trigger.c:3331
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3306
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3393
AfterTriggerEventList events
Definition: trigger.c:3512
AfterTriggersQueryData * query_stack
Definition: trigger.c:3492
CommandId firing_counter
Definition: trigger.c:3514
#define GetTriggerSharedData(evt)
Definition: trigger.c:3356
void pfree(void *pointer)
Definition: mcxt.c:1169
SetConstraintState state
Definition: trigger.c:3487
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3778
CommandId ats_firing_id
Definition: trigger.c:3322
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3307
AfterTriggerEventList events
Definition: trigger.c:3488
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4631
static AfterTriggersData afterTriggers
Definition: trigger.c:3531
SetConstraintState state
Definition: trigger.c:3511

◆ AfterTriggerEndXact()

void AfterTriggerEndXact ( bool  isCommit)

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

4743 {
4744  /*
4745  * Forget the pending-events list.
4746  *
4747  * Since all the info is in TopTransactionContext or children thereof, we
4748  * don't really need to do anything to reclaim memory. However, the
4749  * pending-events list could be large, and so it's useful to discard it as
4750  * soon as possible --- especially if we are aborting because we ran out
4751  * of memory for the list!
4752  */
4754  {
4756  afterTriggers.event_cxt = NULL;
4757  afterTriggers.events.head = NULL;
4758  afterTriggers.events.tail = NULL;
4759  afterTriggers.events.tailfree = NULL;
4760  }
4761 
4762  /*
4763  * Forget any subtransaction state as well. Since this can't be very
4764  * large, we let the eventual reset of TopTransactionContext free the
4765  * memory instead of doing it here.
4766  */
4767  afterTriggers.trans_stack = NULL;
4769 
4770 
4771  /*
4772  * Forget the query stack and constraint-related state information. As
4773  * with the subtransaction state information, we don't bother freeing the
4774  * memory here.
4775  */
4776  afterTriggers.query_stack = NULL;
4778  afterTriggers.state = NULL;
4779 
4780  /* No more afterTriggers manipulation until next transaction starts. */
4782 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
AfterTriggersTransData * trans_stack
Definition: trigger.c:3497
AfterTriggersQueryData * query_stack
Definition: trigger.c:3492
AfterTriggerEventChunk * tail
Definition: trigger.c:3381
SetConstraintState state
Definition: trigger.c:3487
AfterTriggerEventChunk * head
Definition: trigger.c:3380
MemoryContext event_cxt
Definition: trigger.c:3489
AfterTriggerEventList events
Definition: trigger.c:3488
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerFireDeferred()

void AfterTriggerFireDeferred ( void  )

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

4687 {
4688  AfterTriggerEventList *events;
4689  bool snap_pushed = false;
4690 
4691  /* Must not be inside a query */
4693 
4694  /*
4695  * If there are any triggers to fire, make sure we have set a snapshot for
4696  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4697  * can't assume ActiveSnapshot is valid on entry.)
4698  */
4699  events = &afterTriggers.events;
4700  if (events->head != NULL)
4701  {
4703  snap_pushed = true;
4704  }
4705 
4706  /*
4707  * Run all the remaining triggers. Loop until they are all gone, in case
4708  * some trigger queues more for us to do.
4709  */
4710  while (afterTriggerMarkEvents(events, NULL, false))
4711  {
4712  CommandId firing_id = afterTriggers.firing_counter++;
4713 
4714  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4715  break; /* all fired */
4716  }
4717 
4718  /*
4719  * We don't bother freeing the event list, since it will go away anyway
4720  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4721  */
4722 
4723  if (snap_pushed)
4725 }
uint32 CommandId
Definition: c.h:601
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
CommandId firing_counter
Definition: trigger.c:3486
#define Assert(condition)
Definition: c.h:804
AfterTriggerEventChunk * head
Definition: trigger.c:3380
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4086
AfterTriggerEventList events
Definition: trigger.c:3488
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerPendingOnRel()

bool AfterTriggerPendingOnRel ( Oid  relid)

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

5378 {
5379  AfterTriggerEvent event;
5380  AfterTriggerEventChunk *chunk;
5381  int depth;
5382 
5383  /* Scan queued events */
5385  {
5386  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5387 
5388  /*
5389  * We can ignore completed events. (Even if a DONE flag is rolled
5390  * back by subxact abort, it's OK because the effects of the TRUNCATE
5391  * or whatever must get rolled back too.)
5392  */
5393  if (event->ate_flags & AFTER_TRIGGER_DONE)
5394  continue;
5395 
5396  if (evtshared->ats_relid == relid)
5397  return true;
5398  }
5399 
5400  /*
5401  * Also scan events queued by incomplete queries. This could only matter
5402  * if TRUNCATE/etc is executed by a function or trigger within an updating
5403  * query on the same relation, which is pretty perverse, but let's check.
5404  */
5405  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5406  {
5408  {
5409  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5410 
5411  if (event->ate_flags & AFTER_TRIGGER_DONE)
5412  continue;
5413 
5414  if (evtshared->ats_relid == relid)
5415  return true;
5416  }
5417  }
5418 
5419  return false;
5420 }
TriggerFlags ate_flags
Definition: trigger.c:3331
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3306
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3393
AfterTriggersQueryData * query_stack
Definition: trigger.c:3492
#define GetTriggerSharedData(evt)
Definition: trigger.c:3356
AfterTriggerEventList events
Definition: trigger.c:3488
AfterTriggerEventList events
Definition: trigger.c:3503
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ AfterTriggerSetState()

void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 5062 of file trigger.c.

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

Referenced by standard_ProcessUtility().

5063 {
5064  int my_level = GetCurrentTransactionNestLevel();
5065 
5066  /* If we haven't already done so, initialize our state. */
5067  if (afterTriggers.state == NULL)
5069 
5070  /*
5071  * If in a subtransaction, and we didn't save the current state already,
5072  * save it so it can be restored if the subtransaction aborts.
5073  */
5074  if (my_level > 1 &&
5075  afterTriggers.trans_stack[my_level].state == NULL)
5076  {
5077  afterTriggers.trans_stack[my_level].state =
5079  }
5080 
5081  /*
5082  * Handle SET CONSTRAINTS ALL ...
5083  */
5084  if (stmt->constraints == NIL)
5085  {
5086  /*
5087  * Forget any previous SET CONSTRAINTS commands in this transaction.
5088  */
5090 
5091  /*
5092  * Set the per-transaction ALL state to known.
5093  */
5094  afterTriggers.state->all_isset = true;
5096  }
5097  else
5098  {
5099  Relation conrel;
5100  Relation tgrel;
5101  List *conoidlist = NIL;
5102  List *tgoidlist = NIL;
5103  ListCell *lc;
5104 
5105  /*
5106  * Handle SET CONSTRAINTS constraint-name [, ...]
5107  *
5108  * First, identify all the named constraints and make a list of their
5109  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
5110  * the same name within a schema, the specifications are not
5111  * necessarily unique. Our strategy is to target all matching
5112  * constraints within the first search-path schema that has any
5113  * matches, but disregard matches in schemas beyond the first match.
5114  * (This is a bit odd but it's the historical behavior.)
5115  *
5116  * A constraint in a partitioned table may have corresponding
5117  * constraints in the partitions. Grab those too.
5118  */
5119  conrel = table_open(ConstraintRelationId, AccessShareLock);
5120 
5121  foreach(lc, stmt->constraints)
5122  {
5123  RangeVar *constraint = lfirst(lc);
5124  bool found;
5125  List *namespacelist;
5126  ListCell *nslc;
5127 
5128  if (constraint->catalogname)
5129  {
5130  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
5131  ereport(ERROR,
5132  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5133  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
5134  constraint->catalogname, constraint->schemaname,
5135  constraint->relname)));
5136  }
5137 
5138  /*
5139  * If we're given the schema name with the constraint, look only
5140  * in that schema. If given a bare constraint name, use the
5141  * search path to find the first matching constraint.
5142  */
5143  if (constraint->schemaname)
5144  {
5145  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
5146  false);
5147 
5148  namespacelist = list_make1_oid(namespaceId);
5149  }
5150  else
5151  {
5152  namespacelist = fetch_search_path(true);
5153  }
5154 
5155  found = false;
5156  foreach(nslc, namespacelist)
5157  {
5158  Oid namespaceId = lfirst_oid(nslc);
5159  SysScanDesc conscan;
5160  ScanKeyData skey[2];
5161  HeapTuple tup;
5162 
5163  ScanKeyInit(&skey[0],
5164  Anum_pg_constraint_conname,
5165  BTEqualStrategyNumber, F_NAMEEQ,
5166  CStringGetDatum(constraint->relname));
5167  ScanKeyInit(&skey[1],
5168  Anum_pg_constraint_connamespace,
5169  BTEqualStrategyNumber, F_OIDEQ,
5170  ObjectIdGetDatum(namespaceId));
5171 
5172  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
5173  true, NULL, 2, skey);
5174 
5175  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
5176  {
5178 
5179  if (con->condeferrable)
5180  conoidlist = lappend_oid(conoidlist, con->oid);
5181  else if (stmt->deferred)
5182  ereport(ERROR,
5183  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5184  errmsg("constraint \"%s\" is not deferrable",
5185  constraint->relname)));
5186  found = true;
5187  }
5188 
5189  systable_endscan(conscan);
5190 
5191  /*
5192  * Once we've found a matching constraint we do not search
5193  * later parts of the search path.
5194  */
5195  if (found)
5196  break;
5197  }
5198 
5199  list_free(namespacelist);
5200 
5201  /*
5202  * Not found ?
5203  */
5204  if (!found)
5205  ereport(ERROR,
5206  (errcode(ERRCODE_UNDEFINED_OBJECT),
5207  errmsg("constraint \"%s\" does not exist",
5208  constraint->relname)));
5209  }
5210 
5211  /*
5212  * Scan for any possible descendants of the constraints. We append
5213  * whatever we find to the same list that we're scanning; this has the
5214  * effect that we create new scans for those, too, so if there are
5215  * further descendents, we'll also catch them.
5216  */
5217  foreach(lc, conoidlist)
5218  {
5219  Oid parent = lfirst_oid(lc);
5220  ScanKeyData key;
5221  SysScanDesc scan;
5222  HeapTuple tuple;
5223 
5224  ScanKeyInit(&key,
5225  Anum_pg_constraint_conparentid,
5226  BTEqualStrategyNumber, F_OIDEQ,
5227  ObjectIdGetDatum(parent));
5228 
5229  scan = systable_beginscan(conrel, ConstraintParentIndexId, true, NULL, 1, &key);
5230 
5231  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
5232  {
5234 
5235  conoidlist = lappend_oid(conoidlist, con->oid);
5236  }
5237 
5238  systable_endscan(scan);
5239  }
5240 
5241  table_close(conrel, AccessShareLock);
5242 
5243  /*
5244  * Now, locate the trigger(s) implementing each of these constraints,
5245  * and make a list of their OIDs.
5246  */
5247  tgrel = table_open(TriggerRelationId, AccessShareLock);
5248 
5249  foreach(lc, conoidlist)
5250  {
5251  Oid conoid = lfirst_oid(lc);
5252  ScanKeyData skey;
5253  SysScanDesc tgscan;
5254  HeapTuple htup;
5255 
5256  ScanKeyInit(&skey,
5257  Anum_pg_trigger_tgconstraint,
5258  BTEqualStrategyNumber, F_OIDEQ,
5259  ObjectIdGetDatum(conoid));
5260 
5261  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
5262  NULL, 1, &skey);
5263 
5264  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
5265  {
5266  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
5267 
5268  /*
5269  * Silently skip triggers that are marked as non-deferrable in
5270  * pg_trigger. This is not an error condition, since a
5271  * deferrable RI constraint may have some non-deferrable
5272  * actions.
5273  */
5274  if (pg_trigger->tgdeferrable)
5275  tgoidlist = lappend_oid(tgoidlist, pg_trigger->oid);
5276  }
5277 
5278  systable_endscan(tgscan);
5279  }
5280 
5281  table_close(tgrel, AccessShareLock);
5282 
5283  /*
5284  * Now we can set the trigger states of individual triggers for this
5285  * xact.
5286  */
5287  foreach(lc, tgoidlist)
5288  {
5289  Oid tgoid = lfirst_oid(lc);
5291  bool found = false;
5292  int i;
5293 
5294  for (i = 0; i < state->numstates; i++)
5295  {
5296  if (state->trigstates[i].sct_tgoid == tgoid)
5297  {
5298  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5299  found = true;
5300  break;
5301  }
5302  }
5303  if (!found)
5304  {
5306  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
5307  }
5308  }
5309  }
5310 
5311  /*
5312  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
5313  * checks against that constraint must be made when the SET CONSTRAINTS
5314  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
5315  * apply retroactively. We've updated the constraints state, so scan the
5316  * list of previously deferred events to fire any that have now become
5317  * immediate.
5318  *
5319  * Obviously, if this was SET ... DEFERRED then it can't have converted
5320  * any unfired events to immediate, so we need do nothing in that case.
5321  */
5322  if (!stmt->deferred)
5323  {
5325  bool snapshot_set = false;
5326 
5327  while (afterTriggerMarkEvents(events, NULL, true))
5328  {
5329  CommandId firing_id = afterTriggers.firing_counter++;
5330 
5331  /*
5332  * Make sure a snapshot has been established in case trigger
5333  * functions need one. Note that we avoid setting a snapshot if
5334  * we don't find at least one trigger that has to be fired now.
5335  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
5336  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
5337  * at the start of a transaction it's not possible for any trigger
5338  * events to be queued yet.)
5339  */
5340  if (!snapshot_set)
5341  {
5343  snapshot_set = true;
5344  }
5345 
5346  /*
5347  * We can delete fired events if we are at top transaction level,
5348  * but we'd better not if inside a subtransaction, since the
5349  * subtransaction could later get rolled back.
5350  */
5351  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5352  !IsSubTransaction()))
5353  break; /* all fired */
5354  }
5355 
5356  if (snapshot_set)
5358  }
5359 }
#define NIL
Definition: pg_list.h:65
uint32 CommandId
Definition: c.h:601
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2892
AfterTriggersTransData * trans_stack
Definition: trigger.c:3497
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define TriggerConstraintIndexId
Definition: pg_trigger.h:85
#define ConstraintNameNspIndexId
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3260
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
Definition: trigger.c:5032
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
char * schemaname
Definition: primnodes.h:67
char * relname
Definition: primnodes.h:68
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
SetConstraintState state
Definition: trigger.c:3487
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2155
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
#define CStringGetDatum(X)
Definition: postgres.h:622
static SetConstraintState SetConstraintStateCreate(int numalloc)
Definition: trigger.c:4987
#define list_make1_oid(x1)
Definition: pg_list.h:236
Oid MyDatabaseId
Definition: globals.c:88
CommandId firing_counter
Definition: trigger.c:3486
#define ereport(elevel,...)
Definition: elog.h:157
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:857
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:169
Definition: regguts.h:317
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
bool IsSubTransaction(void)
Definition: xact.c:4756
int errmsg(const char *fmt,...)
Definition: elog.c:909
void list_free(List *list)
Definition: list.c:1391
int i
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4086
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3488
#define ConstraintParentIndexId
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4382
static AfterTriggersData afterTriggers
Definition: trigger.c:3531
char * catalogname
Definition: primnodes.h:66
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
SetConstraintState state
Definition: trigger.c:3511
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:5012

◆ CopyTriggerDesc()

TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1867 {
1868  TriggerDesc *newdesc;
1869  Trigger *trigger;
1870  int i;
1871 
1872  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1873  return NULL;
1874 
1875  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1876  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1877 
1878  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1879  memcpy(trigger, trigdesc->triggers,
1880  trigdesc->numtriggers * sizeof(Trigger));
1881  newdesc->triggers = trigger;
1882 
1883  for (i = 0; i < trigdesc->numtriggers; i++)
1884  {
1885  trigger->tgname = pstrdup(trigger->tgname);
1886  if (trigger->tgnattr > 0)
1887  {
1888  int16 *newattr;
1889 
1890  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1891  memcpy(newattr, trigger->tgattr,
1892  trigger->tgnattr * sizeof(int16));
1893  trigger->tgattr = newattr;
1894  }
1895  if (trigger->tgnargs > 0)
1896  {
1897  char **newargs;
1898  int16 j;
1899 
1900  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1901  for (j = 0; j < trigger->tgnargs; j++)
1902  newargs[j] = pstrdup(trigger->tgargs[j]);
1903  trigger->tgargs = newargs;
1904  }
1905  if (trigger->tgqual)
1906  trigger->tgqual = pstrdup(trigger->tgqual);
1907  if (trigger->tgoldtable)
1908  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1909  if (trigger->tgnewtable)
1910  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1911  trigger++;
1912  }
1913 
1914  return newdesc;
1915 }
signed short int16
Definition: c.h:428
char * pstrdup(const char *in)
Definition: mcxt.c:1299
char * tgqual
Definition: reltrigger.h:42
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:49
int numtriggers
Definition: reltrigger.h:50
char ** tgargs
Definition: reltrigger.h:41
int16 * tgattr
Definition: reltrigger.h:40
char * tgnewtable
Definition: reltrigger.h:44
int16 tgnattr
Definition: reltrigger.h:39
void * palloc(Size size)
Definition: mcxt.c:1062
int i
int16 tgnargs
Definition: reltrigger.h:38
char * tgoldtable
Definition: reltrigger.h:43

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

References AccessShareLock, ACL_EXECUTE, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, allowSystemTableMods, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), attnum, BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CacheInvalidateRelcacheByTuple(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CommandCounterIncrement(), CreateTrigStmt::constrrel, copyObject, CreateConstraintEntry(), CreateTrigger(), CStringGetDatum, CStringGetTextDatum, CurrentMemoryContext, DatumGetPointer, CreateTrigStmt::deferrable, deleteDependencyRecordsFor(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, find_all_inheritors(), find_inheritance_children(), forboth, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), has_superclass(), heap_copytuple(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, IndexGetRelation(), CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, 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(), NameStr, NIL, nodeToString(), NoLock, PartitionDescData::nparts, OBJECT_FUNCTION, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, PartitionDescData::oids, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_id, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetDescr, RelationGetNamespace, RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, RELOID, CreateTrigStmt::replace, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, ShareRowExclusiveLock, snprintf, strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), table_openrv(), CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, TRIGGER_FIRES_ON_ORIGIN, TriggerOidIndexId, TriggerRelidNameIndexId, CreateTrigStmt::trigname, TupleDescAttr, values, Var::varattno, Var::varno, and CreateTrigStmt::whenClause.

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

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

◆ EnableDisableTrigger()

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

Definition at line 1535 of file trigger.c.

References BTEqualStrategyNumber, CacheInvalidateRelcache(), CatalogTupleUpdate(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_copytuple(), heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, NameStr, ObjectIdGetDatum, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and TriggerRelidNameIndexId.

Referenced by ATExecEnableDisableTrigger().

1537 {
1538  Relation tgrel;
1539  int nkeys;
1540  ScanKeyData keys[2];
1541  SysScanDesc tgscan;
1542  HeapTuple tuple;
1543  bool found;
1544  bool changed;
1545 
1546  /* Scan the relevant entries in pg_triggers */
1547  tgrel = table_open(TriggerRelationId, RowExclusiveLock);
1548 
1549  ScanKeyInit(&keys[0],
1550  Anum_pg_trigger_tgrelid,
1551  BTEqualStrategyNumber, F_OIDEQ,
1553  if (tgname)
1554  {
1555  ScanKeyInit(&keys[1],
1556  Anum_pg_trigger_tgname,
1557  BTEqualStrategyNumber, F_NAMEEQ,
1558  CStringGetDatum(tgname));
1559  nkeys = 2;
1560  }
1561  else
1562  nkeys = 1;
1563 
1564  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1565  NULL, nkeys, keys);
1566 
1567  found = changed = false;
1568 
1569  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1570  {
1571  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1572 
1573  if (oldtrig->tgisinternal)
1574  {
1575  /* system trigger ... ok to process? */
1576  if (skip_system)
1577  continue;
1578  if (!superuser())
1579  ereport(ERROR,
1580  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1581  errmsg("permission denied: \"%s\" is a system trigger",
1582  NameStr(oldtrig->tgname))));
1583  }
1584 
1585  found = true;
1586 
1587  if (oldtrig->tgenabled != fires_when)
1588  {
1589  /* need to change this one ... make a copy to scribble on */
1590  HeapTuple newtup = heap_copytuple(tuple);
1591  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1592 
1593  newtrig->tgenabled = fires_when;
1594 
1595  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1596 
1597  heap_freetuple(newtup);
1598 
1599  changed = true;
1600  }
1601 
1602  InvokeObjectPostAlterHook(TriggerRelationId,
1603  oldtrig->oid, 0);
1604  }
1605 
1606  systable_endscan(tgscan);
1607 
1608  table_close(tgrel, RowExclusiveLock);
1609 
1610  if (tgname && !found)
1611  ereport(ERROR,
1612  (errcode(ERRCODE_UNDEFINED_OBJECT),
1613  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1614  tgname, RelationGetRelationName(rel))));
1615 
1616  /*
1617  * If we changed anything, broadcast a SI inval message to force each
1618  * backend (including our own!) to rebuild relation's relcache entry.
1619  * Otherwise they will fail to apply the change promptly.
1620  */
1621  if (changed)
1623 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define TriggerRelidNameIndexId
Definition: pg_trigger.h:87
int errcode(int sqlerrcode)
Definition: elog.c:698
bool superuser(void)
Definition: superuser.c:46
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:622
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1278
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define NameStr(name)
Definition: c.h:681
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:457
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ ExecARDeleteTriggers()

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

Definition at line 2543 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2547 {
2548  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2549 
2550  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2551  (transition_capture && transition_capture->tcs_delete_old_table))
2552  {
2553  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2554 
2555  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2556  if (fdw_trigtuple == NULL)
2557  GetTupleForTrigger(estate,
2558  NULL,
2559  relinfo,
2560  tupleid,
2562  slot,
2563  NULL);
2564  else
2565  ExecForceStoreHeapTuple(fdw_trigtuple, slot, false);
2566 
2568  true, slot, NULL, NIL, NULL,
2569  transition_capture);
2570  }
2571 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define NIL
Definition: pg_list.h:65
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:2997
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:92
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
bool trig_delete_after_row
Definition: reltrigger.h:67
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804

◆ ExecARInsertTriggers()

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

Definition at line 2313 of file trigger.c.

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

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

2316 {
2317  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2318 
2319  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2320  (transition_capture && transition_capture->tcs_insert_new_table))
2322  true, NULL, slot,
2323  recheckIndexes, NULL,
2324  transition_capture);
2325 }
bool trig_insert_after_row
Definition: reltrigger.h:57
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:91

◆ ExecARUpdateTriggers()

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

Definition at line 2827 of file trigger.c.

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

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

2833 {
2834  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2835 
2836  if ((trigdesc && trigdesc->trig_update_after_row) ||
2837  (transition_capture &&
2838  (transition_capture->tcs_update_old_table ||
2839  transition_capture->tcs_update_new_table)))
2840  {
2841  /*
2842  * Note: if the UPDATE is converted into a DELETE+INSERT as part of
2843  * update-partition-key operation, then this function is also called
2844  * separately for DELETE and INSERT to capture transition table rows.
2845  * In such case, either old tuple or new tuple can be NULL.
2846  */
2847  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
2848 
2849  if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
2850  GetTupleForTrigger(estate,
2851  NULL,
2852  relinfo,
2853  tupleid,
2855  oldslot,
2856  NULL);
2857  else if (fdw_trigtuple != NULL)
2858  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
2859  else
2860  ExecClearTuple(oldslot);
2861 
2863  true, oldslot, newslot, recheckIndexes,
2864  ExecGetAllUpdatedCols(relinfo, estate),
2865  transition_capture);
2866  }
2867 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:2997
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1347
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
bool trig_update_after_row
Definition: reltrigger.h:62
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:93

◆ ExecASDeleteTriggers()

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

Definition at line 2440 of file trigger.c.

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

Referenced by fireASTriggers().

2442 {
2443  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2444 
2445  if (trigdesc && trigdesc->trig_delete_after_statement)
2447  false, NULL, NULL, NIL, NULL, transition_capture);
2448 }
#define NIL
Definition: pg_list.h:65
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:92
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
bool trig_delete_after_statement
Definition: reltrigger.h:70

◆ ExecASInsertTriggers()

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

Definition at line 2226 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2228 {
2229  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2230 
2231  if (trigdesc && trigdesc->trig_insert_after_statement)
2233  false, NULL, NULL, NIL, NULL, transition_capture);
2234 }
#define NIL
Definition: pg_list.h:65
bool trig_insert_after_statement
Definition: reltrigger.h:60
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:91

◆ ExecASTruncateTriggers()

void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2983 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

2984 {
2985  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2986 
2987  if (trigdesc && trigdesc->trig_truncate_after_statement)
2989  false, NULL, NULL, NIL, NULL, NULL);
2990 }
#define NIL
Definition: pg_list.h:65
bool trig_truncate_after_statement
Definition: reltrigger.h:73
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:94

◆ ExecASUpdateTriggers()

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

Definition at line 2679 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, ExecGetAllUpdatedCols(), NIL, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_update_after_statement, and TRIGGER_EVENT_UPDATE.

Referenced by fireASTriggers().

2681 {
2682  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2683 
2684  /* statement-level triggers operate on the parent table */
2685  Assert(relinfo->ri_RootResultRelInfo == NULL);
2686 
2687  if (trigdesc && trigdesc->trig_update_after_statement)
2689  false, NULL, NULL, NIL,
2690  ExecGetAllUpdatedCols(relinfo, estate),
2691  transition_capture);
2692 }
#define NIL
Definition: pg_list.h:65
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1347
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:511
bool trig_update_after_statement
Definition: reltrigger.h:65
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, TupleTableSlot *oldtup, TupleTableSlot *newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5447
#define Assert(condition)
Definition: c.h:804
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:93

◆ ExecBRDeleteTriggers()

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

Definition at line 2458 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2463 {
2464  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2465  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2466  bool result = true;
2467  TriggerData LocTriggerData = {0};
2468  HeapTuple trigtuple;
2469  bool should_free = false;
2470  int i;
2471 
2472  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2473  if (fdw_trigtuple == NULL)
2474  {
2475  TupleTableSlot *epqslot_candidate = NULL;
2476 
2477  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2478  LockTupleExclusive, slot, &epqslot_candidate))
2479  return false;
2480 
2481  /*
2482  * If the tuple was concurrently updated and the caller of this
2483  * function requested for the updated tuple, skip the trigger
2484  * execution.
2485  */
2486  if (epqslot_candidate != NULL && epqslot != NULL)
2487  {
2488  *epqslot = epqslot_candidate;
2489  return false;
2490  }
2491 
2492  trigtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2493 
2494  }
2495  else
2496  {
2497  trigtuple = fdw_trigtuple;
2498  ExecForceStoreHeapTuple(trigtuple, slot, false);
2499  }
2500 
2501  LocTriggerData.type = T_TriggerData;
2502  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2505  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2506  for (i = 0; i < trigdesc->numtriggers; i++)
2507  {
2508  HeapTuple newtuple;
2509  Trigger *trigger = &trigdesc->triggers[i];
2510 
2511  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2512  TRIGGER_TYPE_ROW,
2513  TRIGGER_TYPE_BEFORE,
2514  TRIGGER_TYPE_DELETE))
2515  continue;
2516  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2517  NULL, slot, NULL))
2518  continue;
2519 
2520  LocTriggerData.tg_trigslot = slot;
2521  LocTriggerData.tg_trigtuple = trigtuple;
2522  LocTriggerData.tg_trigger = trigger;
2523  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2524  i,
2525  relinfo->ri_TrigFunctions,
2526  relinfo->ri_TrigInstrument,
2527  GetPerTupleMemoryContext(estate));
2528  if (newtuple == NULL)
2529  {
2530  result = false; /* tell caller to suppress delete */
2531  break;
2532  }
2533  if (newtuple != trigtuple)
2534  heap_freetuple(newtuple);
2535  }
2536  if (should_free)
2537  heap_freetuple(trigtuple);
2538 
2539  return result;
2540 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:2997
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:92
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1644
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecBRInsertTriggers()

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

Definition at line 2237 of file trigger.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, ExecCallTriggerFunc(), ExecFetchSlotHeapTuple(), ExecForceStoreHeapTuple(), ExecPartitionCheck(), get_namespace_name(), GetPerTupleMemoryContext, heap_freetuple(), i, TriggerDesc::numtriggers, RelationGetNamespace, RelationGetRelationName, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigslot, TriggerData::tg_trigtuple, Trigger::tgisclone, Trigger::tgname, Trigger::tgtype, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_INSERT, TRIGGER_EVENT_ROW, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

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

2239 {
2240  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2241  HeapTuple newtuple = NULL;
2242  bool should_free;
2243  TriggerData LocTriggerData = {0};
2244  int i;
2245 
2246  LocTriggerData.type = T_TriggerData;
2247  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2250  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2251  for (i = 0; i < trigdesc->numtriggers; i++)
2252  {
2253  Trigger *trigger = &trigdesc->triggers[i];
2254  HeapTuple oldtuple;
2255 
2256  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2257  TRIGGER_TYPE_ROW,
2258  TRIGGER_TYPE_BEFORE,
2259  TRIGGER_TYPE_INSERT))
2260  continue;
2261  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2262  NULL, NULL, slot))
2263  continue;
2264 
2265  if (!newtuple)
2266  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2267 
2268  LocTriggerData.tg_trigslot = slot;
2269  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2270  LocTriggerData.tg_trigger = trigger;
2271  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2272  i,
2273  relinfo->ri_TrigFunctions,
2274  relinfo->ri_TrigInstrument,
2275  GetPerTupleMemoryContext(estate));
2276  if (newtuple == NULL)
2277  {
2278  if (should_free)
2279  heap_freetuple(oldtuple);
2280  return false; /* "do nothing" */
2281  }
2282  else if (newtuple != oldtuple)
2283  {
2284  ExecForceStoreHeapTuple(newtuple, slot, false);
2285 
2286  /*
2287  * After a tuple in a partition goes through a trigger, the user
2288  * could have changed the partition key enough that the tuple no
2289  * longer fits the partition. Verify that.
2290  */
2291  if (trigger->tgisclone &&
2292  !ExecPartitionCheck(relinfo, slot, estate, false))
2293  ereport(ERROR,
2294  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2295  errmsg("moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported"),
2296  errdetail("Before executing trigger \"%s\", the row was to be in partition \"%s.%s\".",
2297  trigger->tgname,
2300 
2301  if (should_free)
2302  heap_freetuple(oldtuple);
2303 
2304  /* signal tuple should be re-fetched if used */
2305  newtuple = NULL;
2306  }
2307  }
2308 
2309  return true;
2310 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
int errcode(int sqlerrcode)
Definition: elog.c:698
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define ERROR
Definition: elog.h:46
char * tgname
Definition: reltrigger.h:27
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:491
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1644
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
bool tgisclone
Definition: reltrigger.h:32
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define ereport(elevel,...)
Definition: elog.h:157
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:91
int errmsg(const char *fmt,...)
Definition: elog.c:909
NodeTag type
Definition: trigger.h:32
int i
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
Definition: execMain.c:1697
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ ExecBRUpdateTriggers()

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

Definition at line 2695 of file trigger.c.

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

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2700 {
2701  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2702  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
2703  HeapTuple newtuple = NULL;
2704  HeapTuple trigtuple;
2705  bool should_free_trig = false;
2706  bool should_free_new = false;
2707  TriggerData LocTriggerData = {0};
2708  int i;
2709  Bitmapset *updatedCols;
2710  LockTupleMode lockmode;
2711 
2712  /* Determine lock mode to use */
2713  lockmode = ExecUpdateLockMode(estate, relinfo);
2714 
2715  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2716  if (fdw_trigtuple == NULL)
2717  {
2718  TupleTableSlot *epqslot_candidate = NULL;
2719 
2720  /* get a copy of the on-disk tuple we are planning to update */
2721  if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2722  lockmode, oldslot, &epqslot_candidate))
2723  return false; /* cancel the update action */
2724 
2725  /*
2726  * In READ COMMITTED isolation level it's possible that target tuple
2727  * was changed due to concurrent update. In that case we have a raw
2728  * subplan output tuple in epqslot_candidate, and need to form a new
2729  * insertable tuple using ExecGetUpdateNewTuple to replace the one we
2730  * received in newslot. Neither we nor our callers have any further
2731  * interest in the passed-in tuple, so it's okay to overwrite newslot
2732  * with the newer data.
2733  *
2734  * (Typically, newslot was also generated by ExecGetUpdateNewTuple, so
2735  * that epqslot_clean will be that same slot and the copy step below
2736  * is not needed.)
2737  */
2738  if (epqslot_candidate != NULL)
2739  {
2740  TupleTableSlot *epqslot_clean;
2741 
2742  epqslot_clean = ExecGetUpdateNewTuple(relinfo, epqslot_candidate,
2743  oldslot);
2744 
2745  if (newslot != epqslot_clean)
2746  ExecCopySlot(newslot, epqslot_clean);
2747  }
2748 
2749  trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig);
2750  }
2751  else
2752  {
2753  ExecForceStoreHeapTuple(fdw_trigtuple, oldslot, false);
2754  trigtuple = fdw_trigtuple;
2755  }
2756 
2757  LocTriggerData.type = T_TriggerData;
2758  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2761  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2762  updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
2763  LocTriggerData.tg_updatedcols = updatedCols;
2764  for (i = 0; i < trigdesc->numtriggers; i++)
2765  {
2766  Trigger *trigger = &trigdesc->triggers[i];
2767  HeapTuple oldtuple;
2768 
2769  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2770  TRIGGER_TYPE_ROW,
2771  TRIGGER_TYPE_BEFORE,
2772  TRIGGER_TYPE_UPDATE))
2773  continue;
2774  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2775  updatedCols, oldslot, newslot))
2776  continue;
2777 
2778  if (!newtuple)
2779  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free_new);
2780 
2781  LocTriggerData.tg_trigslot = oldslot;
2782  LocTriggerData.tg_trigtuple = trigtuple;
2783  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2784  LocTriggerData.tg_newslot = newslot;
2785  LocTriggerData.tg_trigger = trigger;
2786  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2787  i,
2788  relinfo->ri_TrigFunctions,
2789  relinfo->ri_TrigInstrument,
2790  GetPerTupleMemoryContext(estate));
2791 
2792  if (newtuple == NULL)
2793  {
2794  if (should_free_trig)
2795  heap_freetuple(trigtuple);
2796  if (should_free_new)
2797  heap_freetuple(oldtuple);
2798  return false; /* "do nothing" */
2799  }
2800  else if (newtuple != oldtuple)
2801  {
2802  ExecForceStoreHeapTuple(newtuple, newslot, false);
2803 
2804  /*
2805  * If the tuple returned by the trigger / being stored, is the old
2806  * row version, and the heap tuple passed to the trigger was
2807  * allocated locally, materialize the slot. Otherwise we might
2808  * free it while still referenced by the slot.
2809  */
2810  if (should_free_trig && newtuple == trigtuple)
2811  ExecMaterializeSlot(newslot);
2812 
2813  if (should_free_new)
2814  heap_freetuple(oldtuple);
2815 
2816  /* signal tuple should be re-fetched if used */
2817  newtuple = NULL;
2818  }
2819  }
2820  if (should_free_trig)
2821  heap_freetuple(trigtuple);
2822 
2823  return true;
2824 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:475
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
LockTupleMode
Definition: lockoptions.h:49
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **newSlot)
Definition: trigger.c:2997
TupleTableSlot * ExecGetUpdateNewTuple(ResultRelInfo *relinfo, TupleTableSlot *planSlot, TupleTableSlot *oldSlot)
const Bitmapset * tg_updatedcols
Definition: trigger.h:42
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1347
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1644
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:443
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2240
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:93
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSDeleteTriggers()

void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2389 of file trigger.c.

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

Referenced by fireBSTriggers().

2390 {
2391  TriggerDesc *trigdesc;
2392  int i;
2393  TriggerData LocTriggerData = {0};
2394 
2395  trigdesc = relinfo->ri_TrigDesc;
2396 
2397  if (trigdesc == NULL)
2398  return;
2399  if (!trigdesc->trig_delete_before_statement)
2400  return;
2401 
2402  /* no-op if we already fired BS triggers in this context */
2404  CMD_DELETE))
2405  return;
2406 
2407  LocTriggerData.type = T_TriggerData;
2408  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2410  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2411  for (i = 0; i < trigdesc->numtriggers; i++)
2412  {
2413  Trigger *trigger = &trigdesc->triggers[i];
2414  HeapTuple newtuple;
2415 
2416  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2417  TRIGGER_TYPE_STATEMENT,
2418  TRIGGER_TYPE_BEFORE,
2419  TRIGGER_TYPE_DELETE))
2420  continue;
2421  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2422  NULL, NULL, NULL))
2423  continue;
2424 
2425  LocTriggerData.tg_trigger = trigger;
2426  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2427  i,
2428  relinfo->ri_TrigFunctions,
2429  relinfo->ri_TrigInstrument,
2430  GetPerTupleMemoryContext(estate));
2431 
2432  if (newtuple)
2433  ereport(ERROR,
2434  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2435  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2436  }
2437 }
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:92
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
int errcode(int sqlerrcode)
Definition: elog.c:698
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5765
#define ERROR
Definition: elog.h:46
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
bool trig_delete_before_statement
Definition: reltrigger.h:69
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define ereport(elevel,...)
Definition: elog.h:157
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
int errmsg(const char *fmt,...)
Definition: elog.c:909
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
#define RelationGetRelid(relation)
Definition: rel.h:457
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSInsertTriggers()

void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2175 of file trigger.c.

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

Referenced by CopyFrom(), and fireBSTriggers().

2176 {
2177  TriggerDesc *trigdesc;
2178  int i;
2179  TriggerData LocTriggerData = {0};
2180 
2181  trigdesc = relinfo->ri_TrigDesc;
2182 
2183  if (trigdesc == NULL)
2184  return;
2185  if (!trigdesc->trig_insert_before_statement)
2186  return;
2187 
2188  /* no-op if we already fired BS triggers in this context */
2190  CMD_INSERT))
2191  return;
2192 
2193  LocTriggerData.type = T_TriggerData;
2194  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2196  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2197  for (i = 0; i < trigdesc->numtriggers; i++)
2198  {
2199  Trigger *trigger = &trigdesc->triggers[i];
2200  HeapTuple newtuple;
2201 
2202  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2203  TRIGGER_TYPE_STATEMENT,
2204  TRIGGER_TYPE_BEFORE,
2205  TRIGGER_TYPE_INSERT))
2206  continue;
2207  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2208  NULL, NULL, NULL))
2209  continue;
2210 
2211  LocTriggerData.tg_trigger = trigger;
2212  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2213  i,
2214  relinfo->ri_TrigFunctions,
2215  relinfo->ri_TrigInstrument,
2216  GetPerTupleMemoryContext(estate));
2217 
2218  if (newtuple)
2219  ereport(ERROR,
2220  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2221  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2222  }
2223 }
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
int errcode(int sqlerrcode)
Definition: elog.c:698
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5765
#define ERROR
Definition: elog.h:46
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define ereport(elevel,...)
Definition: elog.h:157
TriggerEvent tg_event
Definition: trigger.h:33
bool trig_insert_before_statement
Definition: reltrigger.h:59
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:91
int errmsg(const char *fmt,...)
Definition: elog.c:909
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
#define RelationGetRelid(relation)
Definition: rel.h:457
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSTruncateTriggers()

void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2936 of file trigger.c.

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

Referenced by ExecuteTruncateGuts().

2937 {
2938  TriggerDesc *trigdesc;
2939  int i;
2940  TriggerData LocTriggerData = {0};
2941 
2942  trigdesc = relinfo->ri_TrigDesc;
2943 
2944  if (trigdesc == NULL)
2945  return;
2946  if (!trigdesc->trig_truncate_before_statement)
2947  return;
2948 
2949  LocTriggerData.type = T_TriggerData;
2950  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
2952  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2953 
2954  for (i = 0; i < trigdesc->numtriggers; i++)
2955  {
2956  Trigger *trigger = &trigdesc->triggers[i];
2957  HeapTuple newtuple;
2958 
2959  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2960  TRIGGER_TYPE_STATEMENT,
2961  TRIGGER_TYPE_BEFORE,
2962  TRIGGER_TYPE_TRUNCATE))
2963  continue;
2964  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2965  NULL, NULL, NULL))
2966  continue;
2967 
2968  LocTriggerData.tg_trigger = trigger;
2969  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2970  i,
2971  relinfo->ri_TrigFunctions,
2972  relinfo->ri_TrigInstrument,
2973  GetPerTupleMemoryContext(estate));
2974 
2975  if (newtuple)
2976  ereport(ERROR,
2977  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2978  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2979  }
2980 }
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
bool trig_truncate_before_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define ereport(elevel,...)
Definition: elog.h:157
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:94
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
int errmsg(const char *fmt,...)
Definition: elog.c:909
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecBSUpdateTriggers()

void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2621 of file trigger.c.

References Assert, before_stmt_triggers_fired(), CMD_UPDATE, ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), ExecGetAllUpdatedCols(), GetPerTupleMemoryContext, i, TriggerDesc::numtriggers, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, T_TriggerData, TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_updatedcols, Trigger::tgtype, TriggerDesc::trig_update_before_statement, TRIGGER_EVENT_BEFORE, TRIGGER_EVENT_UPDATE, TriggerEnabled(), TriggerDesc::triggers, and TriggerData::type.

Referenced by fireBSTriggers().

2622 {
2623  TriggerDesc *trigdesc;
2624  int i;
2625  TriggerData LocTriggerData = {0};
2626  Bitmapset *updatedCols;
2627 
2628  trigdesc = relinfo->ri_TrigDesc;
2629 
2630  if (trigdesc == NULL)
2631  return;
2632  if (!trigdesc->trig_update_before_statement)
2633  return;
2634 
2635  /* no-op if we already fired BS triggers in this context */
2637  CMD_UPDATE))
2638  return;
2639 
2640  /* statement-level triggers operate on the parent table */
2641  Assert(relinfo->ri_RootResultRelInfo == NULL);
2642 
2643  updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
2644 
2645  LocTriggerData.type = T_TriggerData;
2646  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2648  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2649  LocTriggerData.tg_updatedcols = updatedCols;
2650  for (i = 0; i < trigdesc->numtriggers; i++)
2651  {
2652  Trigger *trigger = &trigdesc->triggers[i];
2653  HeapTuple newtuple;
2654 
2655  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2656  TRIGGER_TYPE_STATEMENT,
2657  TRIGGER_TYPE_BEFORE,
2658  TRIGGER_TYPE_UPDATE))
2659  continue;
2660  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2661  updatedCols, NULL, NULL))
2662  continue;
2663 
2664  LocTriggerData.tg_trigger = trigger;
2665  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2666  i,
2667  relinfo->ri_TrigFunctions,
2668  relinfo->ri_TrigInstrument,
2669  GetPerTupleMemoryContext(estate));
2670 
2671  if (newtuple)
2672  ereport(ERROR,
2673  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2674  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2675  }
2676 }
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
const Bitmapset * tg_updatedcols
Definition: trigger.h:42
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1347
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
int errcode(int sqlerrcode)
Definition: elog.c:698
bool trig_update_before_statement
Definition: reltrigger.h:64
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5765
#define ERROR
Definition: elog.h:46
int16 tgtype
Definition: reltrigger.h:29
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:511
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:99
Trigger * triggers
Definition: reltrigger.h:49
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:93
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
int errmsg(const char *fmt,...)
Definition: elog.c:909
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
#define RelationGetRelid(relation)
Definition: rel.h:457
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRDeleteTriggers()

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

Definition at line 2574 of file trigger.c.

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

Referenced by ExecDelete().

2576 {
2577  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2578  TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
2579  TriggerData LocTriggerData = {0};
2580  int i;
2581 
2582  LocTriggerData.type = T_TriggerData;
2583  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2586  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2587 
2588  ExecForceStoreHeapTuple(trigtuple, slot, false);
2589 
2590  for (i = 0; i < trigdesc->numtriggers; i++)
2591  {
2592  HeapTuple rettuple;
2593  Trigger *trigger = &trigdesc->triggers[i];
2594 
2595  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2596  TRIGGER_TYPE_ROW,
2597  TRIGGER_TYPE_INSTEAD,
2598  TRIGGER_TYPE_DELETE))
2599  continue;
2600  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2601  NULL, slot, NULL))
2602  continue;
2603 
2604  LocTriggerData.tg_trigslot = slot;
2605  LocTriggerData.tg_trigtuple = trigtuple;
2606  LocTriggerData.tg_trigger = trigger;
2607  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2608  i,
2609  relinfo->ri_TrigFunctions,
2610  relinfo->ri_TrigInstrument,
2611  GetPerTupleMemoryContext(estate));
2612  if (rettuple == NULL)
2613  return false; /* Delete was suppressed */
2614  if (rettuple != trigtuple)
2615  heap_freetuple(rettuple);
2616  }
2617  return true;
2618 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:92
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:101
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:49
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRInsertTriggers()

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

Definition at line 2328 of file trigger.c.

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

Referenced by CopyFrom(), and ExecInsert().

2330 {
2331  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2332  HeapTuple newtuple = NULL;
2333  bool should_free;
2334  TriggerData LocTriggerData = {0};
2335  int i;
2336 
2337  LocTriggerData.type = T_TriggerData;
2338  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2341  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2342  for (i = 0; i < trigdesc->numtriggers; i++)
2343  {
2344  Trigger *trigger = &trigdesc->triggers[i];
2345  HeapTuple oldtuple;
2346 
2347  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2348  TRIGGER_TYPE_ROW,
2349  TRIGGER_TYPE_INSTEAD,
2350  TRIGGER_TYPE_INSERT))
2351  continue;
2352  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2353  NULL, NULL, slot))
2354  continue;
2355 
2356  if (!newtuple)
2357  newtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
2358 
2359  LocTriggerData.tg_trigslot = slot;
2360  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2361  LocTriggerData.tg_trigger = trigger;
2362  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2363  i,
2364  relinfo->ri_TrigFunctions,
2365  relinfo->ri_TrigInstrument,
2366  GetPerTupleMemoryContext(estate));
2367  if (newtuple == NULL)
2368  {
2369  if (should_free)
2370  heap_freetuple(oldtuple);
2371  return false; /* "do nothing" */
2372  }
2373  else if (newtuple != oldtuple)
2374  {
2375  ExecForceStoreHeapTuple(newtuple, slot, false);
2376 
2377  if (should_free)
2378  heap_freetuple(oldtuple);
2379 
2380  /* signal tuple should be re-fetched if used */
2381  newtuple = NULL;
2382  }
2383  }
2384 
2385  return true;
2386 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:101
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:49
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1644
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
TriggerEvent tg_event
Definition: trigger.h:33
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:91
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ ExecIRUpdateTriggers()

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

Definition at line 2870 of file trigger.c.

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

Referenced by ExecUpdate().

2872 {
2873  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2874  TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
2875  HeapTuple newtuple = NULL;
2876  bool should_free;
2877  TriggerData LocTriggerData = {0};
2878  int i;
2879 
2880  LocTriggerData.type = T_TriggerData;
2881  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2884  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2885 
2886  ExecForceStoreHeapTuple(trigtuple, oldslot, false);
2887 
2888  for (i = 0; i < trigdesc->numtriggers; i++)
2889  {
2890  Trigger *trigger = &trigdesc->triggers[i];
2891  HeapTuple oldtuple;
2892 
2893  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2894  TRIGGER_TYPE_ROW,
2895  TRIGGER_TYPE_INSTEAD,
2896  TRIGGER_TYPE_UPDATE))
2897  continue;
2898  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2899  NULL, oldslot, newslot))
2900  continue;
2901 
2902  if (!newtuple)
2903  newtuple = ExecFetchSlotHeapTuple(newslot, true, &should_free);
2904 
2905  LocTriggerData.tg_trigslot = oldslot;
2906  LocTriggerData.tg_trigtuple = trigtuple;
2907  LocTriggerData.tg_newslot = newslot;
2908  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2909 
2910  LocTriggerData.tg_trigger = trigger;
2911  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2912  i,
2913  relinfo->ri_TrigFunctions,
2914  relinfo->ri_TrigInstrument,
2915  GetPerTupleMemoryContext(estate));
2916  if (newtuple == NULL)
2917  {
2918  return false; /* "do nothing" */
2919  }
2920  else if (newtuple != oldtuple)
2921  {
2922  ExecForceStoreHeapTuple(newtuple, newslot, false);
2923 
2924  if (should_free)
2925  heap_freetuple(oldtuple);
2926 
2927  /* signal tuple should be re-fetched if used */
2928  newtuple = NULL;
2929  }
2930  }
2931 
2932  return true;
2933 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:97
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
Relation ri_RelationDesc
Definition: execnodes.h:411
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: trigger.c:3113
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:447
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
Definition: execUtils.c:1166
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:101
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:49
TupleTableSlot * tg_newslot
Definition: trigger.h:39
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1644
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:438
int numtriggers
Definition: reltrigger.h:50
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:93
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:537
NodeTag type
Definition: trigger.h:32
int i
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2083
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:441
Relation tg_relation
Definition: trigger.h:34

◆ FindTriggerIncompatibleWithInheritance()

const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2053 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2054 {
2055  if (trigdesc != NULL)
2056  {
2057  int i;
2058 
2059  for (i = 0; i < trigdesc->numtriggers; ++i)
2060  {
2061  Trigger *trigger = &trigdesc->triggers[i];
2062 
2063  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2064  return trigger->tgname;
2065  }
2066  }
2067 
2068  return NULL;
2069 }
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:49
int numtriggers
Definition: reltrigger.h:50
char * tgnewtable
Definition: reltrigger.h:44
int i
char * tgoldtable
Definition: reltrigger.h:43

◆ FreeTriggerDesc()

void FreeTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1921 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::tgisclone, 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().

1922 {
1923  Trigger *trigger;
1924  int i;
1925 
1926  if (trigdesc == NULL)
1927  return;
1928 
1929  trigger = trigdesc->triggers;
1930  for (i = 0; i < trigdesc->numtriggers; i++)
1931  {
1932  pfree(trigger->tgname);
1933  if (trigger->tgnattr > 0)
1934  pfree(trigger->tgattr);
1935  if (trigger->tgnargs > 0)
1936  {
1937  while (--(trigger->tgnargs) >= 0)
1938  pfree(trigger->tgargs[trigger->tgnargs]);
1939  pfree(trigger->tgargs);
1940  }
1941  if (trigger->tgqual)
1942  pfree(trigger->tgqual);
1943  if (trigger->tgoldtable)
1944  pfree(trigger->tgoldtable);
1945  if (trigger->tgnewtable)
1946  pfree(trigger->tgnewtable);
1947  trigger++;
1948  }
1949  pfree(trigdesc->triggers);
1950  pfree(trigdesc);
1951 }
void pfree(void *pointer)
Definition: mcxt.c:1169
char * tgqual
Definition: reltrigger.h:42
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:49
int numtriggers
Definition: reltrigger.h:50
char ** tgargs
Definition: reltrigger.h:41
int16 * tgattr
Definition: reltrigger.h:40
char * tgnewtable
Definition: reltrigger.h:44
int16 tgnattr
Definition: reltrigger.h:39
int i
int16 tgnargs
Definition: reltrigger.h:38
char * tgoldtable
Definition: reltrigger.h:43

◆ get_trigger_oid()

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

Definition at line 1305 of file trigger.c.

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

Referenced by get_object_address_relobject().

1306 {
1307  Relation tgrel;
1308  ScanKeyData skey[2];
1309  SysScanDesc tgscan;
1310  HeapTuple tup;
1311  Oid oid;
1312 
1313  /*
1314  * Find the trigger, verify permissions, set up object address
1315  */
1316  tgrel = table_open(TriggerRelationId, AccessShareLock);
1317 
1318  ScanKeyInit(&skey[0],
1319  Anum_pg_trigger_tgrelid,
1320  BTEqualStrategyNumber, F_OIDEQ,
1321  ObjectIdGetDatum(relid));
1322  ScanKeyInit(&skey[1],
1323  Anum_pg_trigger_tgname,
1324  BTEqualStrategyNumber, F_NAMEEQ,
1325  CStringGetDatum(trigname));
1326 
1327  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1328  NULL, 2, skey);
1329 
1330  tup = systable_getnext(tgscan);
1331 
1332  if (!HeapTupleIsValid(tup))
1333  {
1334  if (!missing_ok)
1335  ereport(ERROR,
1336  (errcode(ERRCODE_UNDEFINED_OBJECT),
1337  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1338  trigname, get_rel_name(relid))));
1339  oid = InvalidOid;
1340  }
1341  else
1342  {
1343  oid = ((Form_pg_trigger) GETSTRUCT(tup))->oid;
1344  }
1345 
1346  systable_endscan(tgscan);
1347  table_close(tgrel, AccessShareLock);
1348  return oid;
1349 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define TriggerRelidNameIndexId
Definition: pg_trigger.h:87
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
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:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define CStringGetDatum(X)
Definition: postgres.h:622
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
int errmsg(const char *fmt,...)
Definition: elog.c:909
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ MakeTransitionCaptureState()

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

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

4399 {
4401  bool need_old,
4402  need_new;
4403  AfterTriggersTableData *table;
4404  MemoryContext oldcxt;
4405  ResourceOwner saveResourceOwner;
4406 
4407  if (trigdesc == NULL)
4408  return NULL;
4409 
4410  /* Detect which table(s) we need. */
4411  switch (cmdType)
4412  {
4413  case CMD_INSERT:
4414  need_old = false;
4415  need_new = trigdesc->trig_insert_new_table;
4416  break;
4417  case CMD_UPDATE:
4418  need_old = trigdesc->trig_update_old_table;
4419  need_new = trigdesc->trig_update_new_table;
4420  break;
4421  case CMD_DELETE:
4422  need_old = trigdesc->trig_delete_old_table;
4423  need_new = false;
4424  break;
4425  default:
4426  elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
4427  need_old = need_new = false; /* keep compiler quiet */
4428  break;
4429  }
4430  if (!need_old && !need_new)
4431  return NULL;
4432 
4433  /* Check state, like AfterTriggerSaveEvent. */
4434  if (afterTriggers.query_depth < 0)
4435  elog(ERROR, "MakeTransitionCaptureState() called outside of query");
4436 
4437  /* Be sure we have enough space to record events at this query depth. */
4440 
4441  /*
4442  * Find or create an AfterTriggersTableData struct to hold the
4443  * tuplestore(s). If there's a matching struct but it's marked closed,
4444  * ignore it; we need a newer one.
4445  *
4446  * Note: the AfterTriggersTableData list, as well as the tuplestores, are
4447  * allocated in the current (sub)transaction's CurTransactionContext, and
4448  * the tuplestores are managed by the (sub)transaction's resource owner.
4449  * This is sufficient lifespan because we do not allow triggers using
4450  * transition tables to be deferrable; they will be fired during
4451  * AfterTriggerEndQuery, after which it's okay to delete the data.
4452  */
4453  table = GetAfterTriggersTableData(relid, cmdType);
4454 
4455  /* Now create required tuplestore(s), if we don't have them already. */
4457  saveResourceOwner = CurrentResourceOwner;
4459 
4460  if (need_old && table->old_tuplestore == NULL)
4461  table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4462  if (need_new && table->new_tuplestore == NULL)
4463  table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4464 
4465  CurrentResourceOwner = saveResourceOwner;
4466  MemoryContextSwitchTo(oldcxt);
4467 
4468  /* Now build the TransitionCaptureState struct, in caller's context */
4470  state->tcs_delete_old_table = trigdesc->trig_delete_old_table;
4471  state->tcs_update_old_table = trigdesc->trig_update_old_table;
4472  state->tcs_update_new_table = trigdesc->trig_update_new_table;
4473  state->tcs_insert_new_table = trigdesc->trig_insert_new_table;
4474  state->tcs_private = table;
4475 
4476  return state;
4477 }
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:147
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext CurTransactionContext
Definition: mcxt.c:54
Tuplestorestate * old_tuplestore
Definition: trigger.c:3526
bool trig_update_new_table
Definition: reltrigger.h:77
bool trig_insert_new_table
Definition: reltrigger.h:75
struct AfterTriggersTableData * tcs_private
Definition: trigger.h:80
#define ERROR
Definition: elog.h:46
static AfterTriggersTableData * GetAfterTriggersTableData(Oid relid, CmdType cmdType)
Definition: trigger.c:4314
bool trig_update_old_table
Definition: reltrigger.h:76
Tuplestorestate * new_tuplestore
Definition: trigger.c:3527
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
void * palloc0(Size size)
Definition: mcxt.c:1093
int work_mem
Definition: globals.c:124
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4940
Definition: regguts.h:317
#define elog(elevel,...)
Definition: elog.h:232
bool trig_delete_old_table
Definition: reltrigger.h:78
static AfterTriggersData afterTriggers
Definition: trigger.c:3531

◆ RelationBuildTriggers()

void RelationBuildTriggers ( Relation  relation)

Definition at line 1637 of file trigger.c.

References AccessShareLock, BTEqualStrategyNumber, CacheMemoryContext, CopyTriggerDesc(), DatumGetByteaPP, DatumGetCString, DirectFunctionCall1, elog, ERROR, fastgetattr, FreeTriggerDesc(), GETSTRUCT, HeapTupleIsValid, i, MemoryContextSwitchTo(), NameGetDatum, nameout(), TriggerDesc::numtriggers, ObjectIdGetDatum, OidIsValid, palloc(), palloc0(), pfree(), pstrdup(), RelationData::rd_att, RelationGetRelationName, RelationGetRelid, repalloc(), ScanKeyInit(), SetTriggerFlags(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, Trigger::tgargs, Trigger::tgattr, Trigger::tgconstraint, Trigger::tgconstrindid, Trigger::tgconstrrelid, Trigger::tgdeferrable, Trigger::tgenabled, Trigger::tgfoid, Trigger::tginitdeferred, Trigger::tgisclone, Trigger::tgisinternal, Trigger::tgname, Trigger::tgnargs, Trigger::tgnattr, Trigger::tgnewtable, Trigger::tgoid, Trigger::tgoldtable, Trigger::tgqual, Trigger::tgtype, RelationData::trigdesc, TriggerRelidNameIndexId, TriggerDesc::triggers, val, and VARDATA_ANY.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

1638 {
1639  TriggerDesc *trigdesc;
1640  int numtrigs;
1641  int maxtrigs;
1642  Trigger *triggers;
1643  Relation tgrel;
1644  ScanKeyData skey;
1645  SysScanDesc tgscan;
1646  HeapTuple htup;
1647  MemoryContext oldContext;
1648  int i;
1649 
1650  /*
1651  * Allocate a working array to hold the triggers (the array is extended if
1652  * necessary)
1653  */
1654  maxtrigs = 16;
1655  triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
1656  numtrigs = 0;
1657 
1658  /*
1659  * Note: since we scan the triggers using TriggerRelidNameIndexId, we will
1660  * be reading the triggers in name order, except possibly during
1661  * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
1662  * ensures that triggers will be fired in name order.
1663  */
1664  ScanKeyInit(&skey,
1665  Anum_pg_trigger_tgrelid,
1666  BTEqualStrategyNumber, F_OIDEQ,
1667  ObjectIdGetDatum(RelationGetRelid(relation)));
1668 
1669  tgrel = table_open(TriggerRelationId, AccessShareLock);
1670  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1671  NULL, 1, &skey);
1672 
1673  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
1674  {
1675  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1676  Trigger *build;
1677  Datum datum;
1678  bool isnull;
1679 
1680  if (numtrigs >= maxtrigs)
1681  {