PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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, bool isInternal)
 
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)
 
void RelationBuildTriggers (Relation relation)
 
TriggerDescCopyTriggerDesc (TriggerDesc *trigdesc)
 
const char * FindTriggerIncompatibleWithInheritance (TriggerDesc *trigdesc)
 
TransitionCaptureStateMakeTransitionCaptureState (TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecBRUpdateTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
 
void ExecARUpdateTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
 
TupleTableSlotExecIRUpdateTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *slot)
 
void ExecBSTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASTruncateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void AfterTriggerBeginXact (void)
 
void AfterTriggerBeginQuery (void)
 
void AfterTriggerEndQuery (EState *estate)
 
void AfterTriggerFireDeferred (void)
 
void AfterTriggerEndXact (bool isCommit)
 
void AfterTriggerBeginSubXact (void)
 
void AfterTriggerEndSubXact (bool isCommit)
 
void AfterTriggerSetState (ConstraintsSetStmt *stmt)
 
bool AfterTriggerPendingOnRel (Oid relid)
 
bool RI_FKey_pk_upd_check_required (Trigger *trigger, Relation pk_rel, HeapTuple old_row, HeapTuple new_row)
 
bool RI_FKey_fk_upd_check_required (Trigger *trigger, Relation fk_rel, HeapTuple old_row, HeapTuple new_row)
 
bool RI_Initial_Check (Trigger *trigger, Relation fk_rel, Relation pk_rel)
 
int RI_FKey_trigger_type (Oid tgfoid)
 

Variables

PGDLLIMPORT int SessionReplicationRole
 

Macro Definition Documentation

#define AFTER_TRIGGER_DEFERRABLE   0x00000020

Definition at line 113 of file trigger.h.

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

#define AFTER_TRIGGER_INITDEFERRED   0x00000040

Definition at line 114 of file trigger.h.

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

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

Definition at line 267 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

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

Definition at line 268 of file trigger.h.

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

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

Definition at line 266 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

#define SESSION_REPLICATION_ROLE_LOCAL   2

Definition at line 148 of file trigger.h.

#define SESSION_REPLICATION_ROLE_ORIGIN   0

Definition at line 146 of file trigger.h.

#define SESSION_REPLICATION_ROLE_REPLICA   1

Definition at line 147 of file trigger.h.

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

#define TRIGGER_DISABLED   'D'

Definition at line 158 of file trigger.h.

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

#define TRIGGER_EVENT_AFTER   0x00000000

Definition at line 107 of file trigger.h.

#define TRIGGER_EVENT_DELETE   0x00000001
#define TRIGGER_EVENT_INSTEAD   0x00000010

Definition at line 108 of file trigger.h.

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

#define TRIGGER_EVENT_OPMASK   0x00000003
#define TRIGGER_EVENT_TIMINGMASK   0x00000018

Definition at line 109 of file trigger.h.

#define TRIGGER_EVENT_TRUNCATE   0x00000003
#define TRIGGER_FIRED_BY_TRUNCATE (   event)    (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_TRUNCATE)
#define TRIGGER_FIRED_FOR_STATEMENT (   event)    (!TRIGGER_FIRED_FOR_ROW(event))
#define TRIGGER_FIRED_INSTEAD (   event)    (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_INSTEAD)
#define TRIGGER_FIRES_ALWAYS   'A'

Definition at line 156 of file trigger.h.

Referenced by ATExecCmd().

#define TRIGGER_FIRES_ON_ORIGIN   'O'
#define TRIGGER_FIRES_ON_REPLICA   'R'

Definition at line 157 of file trigger.h.

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

Typedef Documentation

Definition at line 28 of file trigger.h.

Function Documentation

void AfterTriggerBeginQuery ( void  )

Definition at line 4540 of file trigger.c.

References AfterTriggersData::query_depth.

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

4541 {
4542  /* Increase the query stack depth */
4544 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
void AfterTriggerBeginSubXact ( void  )

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

4809 {
4810  int my_level = GetCurrentTransactionNestLevel();
4811 
4812  /*
4813  * Allocate more space in the trans_stack if needed. (Note: because the
4814  * minimum nest level of a subtransaction is 2, we waste the first couple
4815  * entries of the array; not worth the notational effort to avoid it.)
4816  */
4817  while (my_level >= afterTriggers.maxtransdepth)
4818  {
4819  if (afterTriggers.maxtransdepth == 0)
4820  {
4821  /* Arbitrarily initialize for max of 8 subtransaction levels */
4824  8 * sizeof(AfterTriggersTransData));
4826  }
4827  else
4828  {
4829  /* repalloc will keep the stack in the same context */
4830  int new_alloc = afterTriggers.maxtransdepth * 2;
4831 
4834  new_alloc * sizeof(AfterTriggersTransData));
4835  afterTriggers.maxtransdepth = new_alloc;
4836  }
4837  }
4838 
4839  /*
4840  * Push the current information into the stack. The SET CONSTRAINTS state
4841  * is not saved until/unless changed. Likewise, we don't make a
4842  * per-subtransaction event context until needed.
4843  */
4844  afterTriggers.trans_stack[my_level].state = NULL;
4848 }
AfterTriggersTransData * trans_stack
Definition: trigger.c:3569
MemoryContext TopTransactionContext
Definition: mcxt.c:48
AfterTriggerEventList events
Definition: trigger.c:3584
CommandId firing_counter
Definition: trigger.c:3586
CommandId firing_counter
Definition: trigger.c:3558
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:762
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:962
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
AfterTriggerEventList events
Definition: trigger.c:3560
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
SetConstraintState state
Definition: trigger.c:3583
void AfterTriggerBeginXact ( void  )

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

4509 {
4510  /*
4511  * Initialize after-trigger state structure to empty
4512  */
4513  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4515 
4516  /*
4517  * Verify that there is no leftover state remaining. If these assertions
4518  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4519  * up properly.
4520  */
4521  Assert(afterTriggers.state == NULL);
4522  Assert(afterTriggers.query_stack == NULL);
4524  Assert(afterTriggers.event_cxt == NULL);
4525  Assert(afterTriggers.events.head == NULL);
4526  Assert(afterTriggers.trans_stack == NULL);
4528 }
uint32 CommandId
Definition: c.h:405
AfterTriggersTransData * trans_stack
Definition: trigger.c:3569
AfterTriggersQueryData * query_stack
Definition: trigger.c:3564
SetConstraintState state
Definition: trigger.c:3559
CommandId firing_counter
Definition: trigger.c:3558
#define Assert(condition)
Definition: c.h:664
AfterTriggerEventChunk * head
Definition: trigger.c:3452
MemoryContext event_cxt
Definition: trigger.c:3561
AfterTriggerEventList events
Definition: trigger.c:3560
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
void AfterTriggerEndQuery ( EState estate)

Definition at line 4560 of file trigger.c.

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

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

4561 {
4563 
4564  /* Must be inside a query, too */
4566 
4567  /*
4568  * If we never even got as far as initializing the event stack, there
4569  * certainly won't be any events, so exit quickly.
4570  */
4572  {
4574  return;
4575  }
4576 
4577  /*
4578  * Process all immediate-mode triggers queued by the query, and move the
4579  * deferred ones to the main list of deferred events.
4580  *
4581  * Notice that we decide which ones will be fired, and put the deferred
4582  * ones on the main list, before anything is actually fired. This ensures
4583  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4584  * IMMEDIATE: all events we have decided to defer will be available for it
4585  * to fire.
4586  *
4587  * We loop in case a trigger queues more events at the same query level.
4588  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4589  * will instead fire any triggers in a dedicated query level. Foreign key
4590  * enforcement triggers do add to the current query level, thanks to their
4591  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4592  * C-language triggers might do likewise.
4593  *
4594  * If we find no firable events, we don't have to increment
4595  * firing_counter.
4596  */
4598 
4599  for (;;)
4600  {
4602  {
4603  CommandId firing_id = afterTriggers.firing_counter++;
4604  AfterTriggerEventChunk *oldtail = qs->events.tail;
4605 
4606  if (afterTriggerInvokeEvents(&qs->events, firing_id, estate, false))
4607  break; /* all fired */
4608 
4609  /*
4610  * Firing a trigger could result in query_stack being repalloc'd,
4611  * so we must recalculate qs after each afterTriggerInvokeEvents
4612  * call. Furthermore, it's unsafe to pass delete_ok = true here,
4613  * because that could cause afterTriggerInvokeEvents to try to
4614  * access qs->events after the stack has been repalloc'd.
4615  */
4617 
4618  /*
4619  * We'll need to scan the events list again. To reduce the cost
4620  * of doing so, get rid of completely-fired chunks. We know that
4621  * all events were marked IN_PROGRESS or DONE at the conclusion of
4622  * afterTriggerMarkEvents, so any still-interesting events must
4623  * have been added after that, and so must be in the chunk that
4624  * was then the tail chunk, or in later chunks. So, zap all
4625  * chunks before oldtail. This is approximately the same set of
4626  * events we would have gotten rid of by passing delete_ok = true.
4627  */
4628  Assert(oldtail != NULL);
4629  while (qs->events.head != oldtail)
4631  }
4632  else
4633  break;
4634  }
4635 
4636  /* Release query-level-local storage, including tuplestores if any */
4638 
4640 }
uint32 CommandId
Definition: c.h:405
static void afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs)
Definition: trigger.c:3892
AfterTriggersQueryData * query_stack
Definition: trigger.c:3564
AfterTriggerEventChunk * tail
Definition: trigger.c:3453
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4212
CommandId firing_counter
Definition: trigger.c:3558
#define Assert(condition)
Definition: c.h:664
AfterTriggerEventChunk * head
Definition: trigger.c:3452
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4140
AfterTriggerEventList events
Definition: trigger.c:3560
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4651
AfterTriggerEventList events
Definition: trigger.c:3575
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
void AfterTriggerEndSubXact ( bool  isCommit)

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

4857 {
4858  int my_level = GetCurrentTransactionNestLevel();
4860  AfterTriggerEvent event;
4861  AfterTriggerEventChunk *chunk;
4862  CommandId subxact_firing_id;
4863 
4864  /*
4865  * Pop the prior state if needed.
4866  */
4867  if (isCommit)
4868  {
4869  Assert(my_level < afterTriggers.maxtransdepth);
4870  /* If we saved a prior state, we don't need it anymore */
4871  state = afterTriggers.trans_stack[my_level].state;
4872  if (state != NULL)
4873  pfree(state);
4874  /* this avoids double pfree if error later: */
4875  afterTriggers.trans_stack[my_level].state = NULL;
4878  }
4879  else
4880  {
4881  /*
4882  * Aborting. It is possible subxact start failed before calling
4883  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4884  * trans_stack levels that aren't there.
4885  */
4886  if (my_level >= afterTriggers.maxtransdepth)
4887  return;
4888 
4889  /*
4890  * Release query-level storage for queries being aborted, and restore
4891  * query_depth to its pre-subxact value. This assumes that a
4892  * subtransaction will not add events to query levels started in a
4893  * earlier transaction state.
4894  */
4896  {
4900  }
4903 
4904  /*
4905  * Restore the global deferred-event list to its former length,
4906  * discarding any events queued by the subxact.
4907  */
4909  &afterTriggers.trans_stack[my_level].events);
4910 
4911  /*
4912  * Restore the trigger state. If the saved state is NULL, then this
4913  * subxact didn't save it, so it doesn't need restoring.
4914  */
4915  state = afterTriggers.trans_stack[my_level].state;
4916  if (state != NULL)
4917  {
4919  afterTriggers.state = state;
4920  }
4921  /* this avoids double pfree if error later: */
4922  afterTriggers.trans_stack[my_level].state = NULL;
4923 
4924  /*
4925  * Scan for any remaining deferred events that were marked DONE or IN
4926  * PROGRESS by this subxact or a child, and un-mark them. We can
4927  * recognize such events because they have a firing ID greater than or
4928  * equal to the firing_counter value we saved at subtransaction start.
4929  * (This essentially assumes that the current subxact includes all
4930  * subxacts started after it.)
4931  */
4932  subxact_firing_id = afterTriggers.trans_stack[my_level].firing_counter;
4934  {
4935  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4936 
4937  if (event->ate_flags &
4939  {
4940  if (evtshared->ats_firing_id >= subxact_firing_id)
4941  event->ate_flags &=
4943  }
4944  }
4945  }
4946 }
uint32 CommandId
Definition: c.h:405
AfterTriggersTransData * trans_stack
Definition: trigger.c:3569
TriggerFlags ate_flags
Definition: trigger.c:3403
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3379
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3465
AfterTriggerEventList events
Definition: trigger.c:3584
AfterTriggersQueryData * query_stack
Definition: trigger.c:3564
CommandId firing_counter
Definition: trigger.c:3586
#define GetTriggerSharedData(evt)
Definition: trigger.c:3428
void pfree(void *pointer)
Definition: mcxt.c:949
SetConstraintState state
Definition: trigger.c:3559
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:762
#define Assert(condition)
Definition: c.h:664
Definition: regguts.h:298
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3852
CommandId ats_firing_id
Definition: trigger.c:3395
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3380
AfterTriggerEventList events
Definition: trigger.c:3560
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
Definition: trigger.c:4651
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
SetConstraintState state
Definition: trigger.c:3583
void AfterTriggerEndXact ( bool  isCommit)

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

4761 {
4762  /*
4763  * Forget the pending-events list.
4764  *
4765  * Since all the info is in TopTransactionContext or children thereof, we
4766  * don't really need to do anything to reclaim memory. However, the
4767  * pending-events list could be large, and so it's useful to discard it as
4768  * soon as possible --- especially if we are aborting because we ran out
4769  * of memory for the list!
4770  */
4772  {
4774  afterTriggers.event_cxt = NULL;
4775  afterTriggers.events.head = NULL;
4776  afterTriggers.events.tail = NULL;
4777  afterTriggers.events.tailfree = NULL;
4778  }
4779 
4780  /*
4781  * Forget any subtransaction state as well. Since this can't be very
4782  * large, we let the eventual reset of TopTransactionContext free the
4783  * memory instead of doing it here.
4784  */
4785  afterTriggers.trans_stack = NULL;
4787 
4788 
4789  /*
4790  * Forget the query stack and constraint-related state information. As
4791  * with the subtransaction state information, we don't bother freeing the
4792  * memory here.
4793  */
4794  afterTriggers.query_stack = NULL;
4796  afterTriggers.state = NULL;
4797 
4798  /* No more afterTriggers manipulation until next transaction starts. */
4800 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggersTransData * trans_stack
Definition: trigger.c:3569
AfterTriggersQueryData * query_stack
Definition: trigger.c:3564
AfterTriggerEventChunk * tail
Definition: trigger.c:3453
SetConstraintState state
Definition: trigger.c:3559
AfterTriggerEventChunk * head
Definition: trigger.c:3452
MemoryContext event_cxt
Definition: trigger.c:3561
AfterTriggerEventList events
Definition: trigger.c:3560
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
void AfterTriggerFireDeferred ( void  )

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

4705 {
4706  AfterTriggerEventList *events;
4707  bool snap_pushed = false;
4708 
4709  /* Must not be inside a query */
4711 
4712  /*
4713  * If there are any triggers to fire, make sure we have set a snapshot for
4714  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4715  * can't assume ActiveSnapshot is valid on entry.)
4716  */
4717  events = &afterTriggers.events;
4718  if (events->head != NULL)
4719  {
4721  snap_pushed = true;
4722  }
4723 
4724  /*
4725  * Run all the remaining triggers. Loop until they are all gone, in case
4726  * some trigger queues more for us to do.
4727  */
4728  while (afterTriggerMarkEvents(events, NULL, false))
4729  {
4730  CommandId firing_id = afterTriggers.firing_counter++;
4731 
4732  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4733  break; /* all fired */
4734  }
4735 
4736  /*
4737  * We don't bother freeing the event list, since it will go away anyway
4738  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4739  */
4740 
4741  if (snap_pushed)
4743 }
uint32 CommandId
Definition: c.h:405
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4212
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
CommandId firing_counter
Definition: trigger.c:3558
#define Assert(condition)
Definition: c.h:664
AfterTriggerEventChunk * head
Definition: trigger.c:3452
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4140
AfterTriggerEventList events
Definition: trigger.c:3560
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
bool AfterTriggerPendingOnRel ( Oid  relid)

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

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

Definition at line 5080 of file trigger.c.

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

Referenced by standard_ProcessUtility().

5081 {
5082  int my_level = GetCurrentTransactionNestLevel();
5083 
5084  /* If we haven't already done so, initialize our state. */
5085  if (afterTriggers.state == NULL)
5087 
5088  /*
5089  * If in a subtransaction, and we didn't save the current state already,
5090  * save it so it can be restored if the subtransaction aborts.
5091  */
5092  if (my_level > 1 &&
5093  afterTriggers.trans_stack[my_level].state == NULL)
5094  {
5095  afterTriggers.trans_stack[my_level].state =
5097  }
5098 
5099  /*
5100  * Handle SET CONSTRAINTS ALL ...
5101  */
5102  if (stmt->constraints == NIL)
5103  {
5104  /*
5105  * Forget any previous SET CONSTRAINTS commands in this transaction.
5106  */
5108 
5109  /*
5110  * Set the per-transaction ALL state to known.
5111  */
5112  afterTriggers.state->all_isset = true;
5114  }
5115  else
5116  {
5117  Relation conrel;
5118  Relation tgrel;
5119  List *conoidlist = NIL;
5120  List *tgoidlist = NIL;
5121  ListCell *lc;
5122 
5123  /*
5124  * Handle SET CONSTRAINTS constraint-name [, ...]
5125  *
5126  * First, identify all the named constraints and make a list of their
5127  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
5128  * the same name within a schema, the specifications are not
5129  * necessarily unique. Our strategy is to target all matching
5130  * constraints within the first search-path schema that has any
5131  * matches, but disregard matches in schemas beyond the first match.
5132  * (This is a bit odd but it's the historical behavior.)
5133  */
5135 
5136  foreach(lc, stmt->constraints)
5137  {
5138  RangeVar *constraint = lfirst(lc);
5139  bool found;
5140  List *namespacelist;
5141  ListCell *nslc;
5142 
5143  if (constraint->catalogname)
5144  {
5145  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
5146  ereport(ERROR,
5147  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5148  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
5149  constraint->catalogname, constraint->schemaname,
5150  constraint->relname)));
5151  }
5152 
5153  /*
5154  * If we're given the schema name with the constraint, look only
5155  * in that schema. If given a bare constraint name, use the
5156  * search path to find the first matching constraint.
5157  */
5158  if (constraint->schemaname)
5159  {
5160  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
5161  false);
5162 
5163  namespacelist = list_make1_oid(namespaceId);
5164  }
5165  else
5166  {
5167  namespacelist = fetch_search_path(true);
5168  }
5169 
5170  found = false;
5171  foreach(nslc, namespacelist)
5172  {
5173  Oid namespaceId = lfirst_oid(nslc);
5174  SysScanDesc conscan;
5175  ScanKeyData skey[2];
5176  HeapTuple tup;
5177 
5178  ScanKeyInit(&skey[0],
5180  BTEqualStrategyNumber, F_NAMEEQ,
5181  CStringGetDatum(constraint->relname));
5182  ScanKeyInit(&skey[1],
5184  BTEqualStrategyNumber, F_OIDEQ,
5185  ObjectIdGetDatum(namespaceId));
5186 
5187  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
5188  true, NULL, 2, skey);
5189 
5190  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
5191  {
5193 
5194  if (con->condeferrable)
5195  conoidlist = lappend_oid(conoidlist,
5196  HeapTupleGetOid(tup));
5197  else if (stmt->deferred)
5198  ereport(ERROR,
5199  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5200  errmsg("constraint \"%s\" is not deferrable",
5201  constraint->relname)));
5202  found = true;
5203  }
5204 
5205  systable_endscan(conscan);
5206 
5207  /*
5208  * Once we've found a matching constraint we do not search
5209  * later parts of the search path.
5210  */
5211  if (found)
5212  break;
5213  }
5214 
5215  list_free(namespacelist);
5216 
5217  /*
5218  * Not found ?
5219  */
5220  if (!found)
5221  ereport(ERROR,
5222  (errcode(ERRCODE_UNDEFINED_OBJECT),
5223  errmsg("constraint \"%s\" does not exist",
5224  constraint->relname)));
5225  }
5226 
5227  heap_close(conrel, AccessShareLock);
5228 
5229  /*
5230  * Now, locate the trigger(s) implementing each of these constraints,
5231  * and make a list of their OIDs.
5232  */
5234 
5235  foreach(lc, conoidlist)
5236  {
5237  Oid conoid = lfirst_oid(lc);
5238  bool found;
5239  ScanKeyData skey;
5240  SysScanDesc tgscan;
5241  HeapTuple htup;
5242 
5243  found = false;
5244 
5245  ScanKeyInit(&skey,
5247  BTEqualStrategyNumber, F_OIDEQ,
5248  ObjectIdGetDatum(conoid));
5249 
5250  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
5251  NULL, 1, &skey);
5252 
5253  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
5254  {
5255  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
5256 
5257  /*
5258  * Silently skip triggers that are marked as non-deferrable in
5259  * pg_trigger. This is not an error condition, since a
5260  * deferrable RI constraint may have some non-deferrable
5261  * actions.
5262  */
5263  if (pg_trigger->tgdeferrable)
5264  tgoidlist = lappend_oid(tgoidlist,
5265  HeapTupleGetOid(htup));
5266 
5267  found = true;
5268  }
5269 
5270  systable_endscan(tgscan);
5271 
5272  /* Safety check: a deferrable constraint should have triggers */
5273  if (!found)
5274  elog(ERROR, "no triggers found for constraint with OID %u",
5275  conoid);
5276  }
5277 
5278  heap_close(tgrel, AccessShareLock);
5279 
5280  /*
5281  * Now we can set the trigger states of individual triggers for this
5282  * xact.
5283  */
5284  foreach(lc, tgoidlist)
5285  {
5286  Oid tgoid = lfirst_oid(lc);
5288  bool found = false;
5289  int i;
5290 
5291  for (i = 0; i < state->numstates; i++)
5292  {
5293  if (state->trigstates[i].sct_tgoid == tgoid)
5294  {
5295  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5296  found = true;
5297  break;
5298  }
5299  }
5300  if (!found)
5301  {
5303  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
5304  }
5305  }
5306  }
5307 
5308  /*
5309  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
5310  * checks against that constraint must be made when the SET CONSTRAINTS
5311  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
5312  * apply retroactively. We've updated the constraints state, so scan the
5313  * list of previously deferred events to fire any that have now become
5314  * immediate.
5315  *
5316  * Obviously, if this was SET ... DEFERRED then it can't have converted
5317  * any unfired events to immediate, so we need do nothing in that case.
5318  */
5319  if (!stmt->deferred)
5320  {
5322  bool snapshot_set = false;
5323 
5324  while (afterTriggerMarkEvents(events, NULL, true))
5325  {
5326  CommandId firing_id = afterTriggers.firing_counter++;
5327 
5328  /*
5329  * Make sure a snapshot has been established in case trigger
5330  * functions need one. Note that we avoid setting a snapshot if
5331  * we don't find at least one trigger that has to be fired now.
5332  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
5333  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
5334  * at the start of a transaction it's not possible for any trigger
5335  * events to be queued yet.)
5336  */
5337  if (!snapshot_set)
5338  {
5340  snapshot_set = true;
5341  }
5342 
5343  /*
5344  * We can delete fired events if we are at top transaction level,
5345  * but we'd better not if inside a subtransaction, since the
5346  * subtransaction could later get rolled back.
5347  */
5348  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5349  !IsSubTransaction()))
5350  break; /* all fired */
5351  }
5352 
5353  if (snapshot_set)
5355  }
5356 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:405
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2853
AfterTriggersTransData * trans_stack
Definition: trigger.c:3569
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:87
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
Definition: trigger.c:3333
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
Definition: trigger.c:5050
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4212
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_constraint_conname
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
char * schemaname
Definition: primnodes.h:67
char * relname
Definition: primnodes.h:68
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
SetConstraintState state
Definition: trigger.c:3559
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
#define CStringGetDatum(X)
Definition: postgres.h:584
#define TriggerConstraintIndexId
Definition: indexing.h:247
#define ereport(elevel, rest)
Definition: elog.h:122
static SetConstraintState SetConstraintStateCreate(int numalloc)
Definition: trigger.c:5005
#define list_make1_oid(x1)
Definition: pg_list.h:151
Oid MyDatabaseId
Definition: globals.c:77
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
CommandId firing_counter
Definition: trigger.c:3558
#define ConstraintNameNspIndexId
Definition: indexing.h:124
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:762
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define lfirst(lc)
Definition: pg_list.h:106
Definition: regguts.h:298
#define TriggerRelationId
Definition: pg_trigger.h:34
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
bool IsSubTransaction(void)
Definition: xact.c:4528
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
int i
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4140
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3560
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Definition: pg_list.h:45
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4168
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
char * catalogname
Definition: primnodes.h:66
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
SetConstraintState state
Definition: trigger.c:3583
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:5030
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1912 {
1913  TriggerDesc *newdesc;
1914  Trigger *trigger;
1915  int i;
1916 
1917  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1918  return NULL;
1919 
1920  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1921  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1922 
1923  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1924  memcpy(trigger, trigdesc->triggers,
1925  trigdesc->numtriggers * sizeof(Trigger));
1926  newdesc->triggers = trigger;
1927 
1928  for (i = 0; i < trigdesc->numtriggers; i++)
1929  {
1930  trigger->tgname = pstrdup(trigger->tgname);
1931  if (trigger->tgnattr > 0)
1932  {
1933  int16 *newattr;
1934 
1935  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1936  memcpy(newattr, trigger->tgattr,
1937  trigger->tgnattr * sizeof(int16));
1938  trigger->tgattr = newattr;
1939  }
1940  if (trigger->tgnargs > 0)
1941  {
1942  char **newargs;
1943  int16 j;
1944 
1945  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1946  for (j = 0; j < trigger->tgnargs; j++)
1947  newargs[j] = pstrdup(trigger->tgargs[j]);
1948  trigger->tgargs = newargs;
1949  }
1950  if (trigger->tgqual)
1951  trigger->tgqual = pstrdup(trigger->tgqual);
1952  if (trigger->tgoldtable)
1953  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1954  if (trigger->tgnewtable)
1955  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1956  trigger++;
1957  }
1958 
1959  return newdesc;
1960 }
signed short int16
Definition: c.h:245
char * pstrdup(const char *in)
Definition: mcxt.c:1076
char * tgqual
Definition: reltrigger.h:41
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char ** tgargs
Definition: reltrigger.h:40
int16 * tgattr
Definition: reltrigger.h:39
char * tgnewtable
Definition: reltrigger.h:43
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:848
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42
ObjectAddress CreateTrigger ( CreateTrigStmt stmt,
const char *  queryString,
Oid  relOid,
Oid  refRelOid,
Oid  constraintOid,
Oid  indexOid,
bool  isInternal 
)

Definition at line 141 of file trigger.c.

References AccessShareLock, ACL_EXECUTE, ACL_KIND_CLASS, ACL_KIND_PROC, ACL_TRIGGER, aclcheck_error(), ACLCHECK_OK, addRangeTableEntryForRelation(), addRTEtoQuery(), allowSystemTableMods, Anum_pg_trigger_tgargs, Anum_pg_trigger_tgattr, Anum_pg_trigger_tgconstraint, Anum_pg_trigger_tgconstrindid, Anum_pg_trigger_tgconstrrelid, Anum_pg_trigger_tgdeferrable, Anum_pg_trigger_tgenabled, Anum_pg_trigger_tgfoid, Anum_pg_trigger_tginitdeferred, Anum_pg_trigger_tgisinternal, Anum_pg_trigger_tgname, Anum_pg_trigger_tgnargs, Anum_pg_trigger_tgnewtable, Anum_pg_trigger_tgoldtable, Anum_pg_trigger_tgqual, Anum_pg_trigger_tgrelid, Anum_pg_trigger_tgtype, generate_unaccent_rules::args, CreateTrigStmt::args, Assert, assign_expr_collations(), attnameAttNum(), BoolGetDatum, BTEqualStrategyNumber, buildint2vector(), byteain(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum, ObjectAddress::classId, CreateTrigStmt::columns, CONSTRAINT_TRIGGER, ConstraintRelationId, CreateTrigStmt::constrrel, ConvertTriggerToFK(), copyObject, CreateConstraintEntry(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, CreateTrigStmt::deferrable, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, DirectFunctionCall1, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errhint(), errmsg(), ERROR, CreateTrigStmt::events, EXPR_KIND_TRIGGER_WHEN, free_parsestate(), CreateTrigStmt::funcname, get_func_rettype(), get_rel_name(), GetNewOid(), GETSTRUCT, GetUserId(), has_superclass(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), heap_openrv(), HeapTupleIsValid, HeapTupleSetOid, i, CreateTrigStmt::initdeferred, Int16GetDatum, InvalidAttrNumber, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHookArg, CreateTrigStmt::isconstraint, TriggerTransition::isNew, IsSystemRelation(), TriggerTransition::isTable, lfirst, lfirst_node, list_length(), Var::location, LockRelationOid(), LookupFuncName(), make_parsestate(), makeAlias(), name, TriggerTransition::name, NAMEDATALEN, namein(), NameListToString(), namestrcmp(), Natts_pg_trigger, NIL, nodeToString(), NoLock, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPAQUEOID, ParseState::p_rtable, ParseState::p_sourcetext, palloc(), parser_errposition(), pfree(), pg_class_aclcheck(), pg_proc_aclcheck(), PointerGetDatum, ProcedureRelationId, PRS2_NEW_VARNO, PRS2_OLD_VARNO, pull_var_clause(), RangeVarGetRelid, RelationData::rd_att, RelationData::rd_id, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnExpr(), CreateTrigStmt::relation, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RELOID, RI_FKey_trigger_type(), RI_TRIGGER_NONE, CreateTrigStmt::row, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SetFunctionReturnType(), ShareRowExclusiveLock, snprintf(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, CreateTrigStmt::timing, transformWhereClause(), CreateTrigStmt::transitionRels, TRIGGER_CLEAR_TYPE, TRIGGER_FIRES_ON_ORIGIN, TRIGGER_FOR_BEFORE, TRIGGER_FOR_DELETE, TRIGGER_FOR_INSERT, TRIGGER_FOR_INSTEAD, TRIGGER_FOR_ROW, TRIGGER_FOR_TRUNCATE, TRIGGER_FOR_UPDATE, TRIGGER_SETT_ROW, TRIGGER_TYPE_AFTER, TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSTEAD, TRIGGEROID, TriggerRelationId, TriggerRelidNameIndexId, CreateTrigStmt::trigname, values, Var::varattno, Var::varno, WARNING, and CreateTrigStmt::whenClause.

Referenced by CreateFKCheckTrigger(), createForeignKeyTriggers(), index_constraint_create(), and ProcessUtilitySlow().

144 {
145  int16 tgtype;
146  int ncolumns;
147  int16 *columns;
148  int2vector *tgattr;
149  Node *whenClause;
150  List *whenRtable;
151  char *qual;
153  bool nulls[Natts_pg_trigger];
154  Relation rel;
155  AclResult aclresult;
156  Relation tgrel;
157  SysScanDesc tgscan;
158  ScanKeyData key;
159  Relation pgrel;
160  HeapTuple tuple;
161  Oid fargtypes[1]; /* dummy */
162  Oid funcoid;
163  Oid funcrettype;
164  Oid trigoid;
165  char internaltrigname[NAMEDATALEN];
166  char *trigname;
167  Oid constrrelid = InvalidOid;
168  ObjectAddress myself,
169  referenced;
170  char *oldtablename = NULL;
171  char *newtablename = NULL;
172 
173  if (OidIsValid(relOid))
174  rel = heap_open(relOid, ShareRowExclusiveLock);
175  else
177 
178  /*
179  * Triggers must be on tables or views, and there are additional
180  * relation-type-specific restrictions.
181  */
182  if (rel->rd_rel->relkind == RELKIND_RELATION ||
183  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
184  {
185  /* Tables can't have INSTEAD OF triggers */
186  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
187  stmt->timing != TRIGGER_TYPE_AFTER)
188  ereport(ERROR,
189  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
190  errmsg("\"%s\" is a table",
192  errdetail("Tables cannot have INSTEAD OF triggers.")));
193  /* Disallow ROW triggers on partitioned tables */
194  if (stmt->row && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
195  ereport(ERROR,
196  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
197  errmsg("\"%s\" is a partitioned table",
199  errdetail("Partitioned tables cannot have ROW triggers.")));
200  }
201  else if (rel->rd_rel->relkind == RELKIND_VIEW)
202  {
203  /*
204  * Views can have INSTEAD OF triggers (which we check below are
205  * row-level), or statement-level BEFORE/AFTER triggers.
206  */
207  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
208  ereport(ERROR,
209  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
210  errmsg("\"%s\" is a view",
212  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
213  /* Disallow TRUNCATE triggers on VIEWs */
214  if (TRIGGER_FOR_TRUNCATE(stmt->events))
215  ereport(ERROR,
216  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
217  errmsg("\"%s\" is a view",
219  errdetail("Views cannot have TRUNCATE triggers.")));
220  }
221  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
222  {
223  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
224  stmt->timing != TRIGGER_TYPE_AFTER)
225  ereport(ERROR,
226  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
227  errmsg("\"%s\" is a foreign table",
229  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
230 
231  if (TRIGGER_FOR_TRUNCATE(stmt->events))
232  ereport(ERROR,
233  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
234  errmsg("\"%s\" is a foreign table",
236  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
237 
238  /*
239  * We disallow constraint triggers to protect the assumption that
240  * triggers on FKs can't be deferred. See notes with AfterTriggers
241  * data structures, below.
242  */
243  if (stmt->isconstraint)
244  ereport(ERROR,
245  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
246  errmsg("\"%s\" is a foreign table",
248  errdetail("Foreign tables cannot have constraint triggers.")));
249  }
250  else
251  ereport(ERROR,
252  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
253  errmsg("\"%s\" is not a table or view",
254  RelationGetRelationName(rel))));
255 
257  ereport(ERROR,
258  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
259  errmsg("permission denied: \"%s\" is a system catalog",
260  RelationGetRelationName(rel))));
261 
262  if (stmt->isconstraint)
263  {
264  /*
265  * We must take a lock on the target relation to protect against
266  * concurrent drop. It's not clear that AccessShareLock is strong
267  * enough, but we certainly need at least that much... otherwise, we
268  * might end up creating a pg_constraint entry referencing a
269  * nonexistent table.
270  */
271  if (OidIsValid(refRelOid))
272  {
273  LockRelationOid(refRelOid, AccessShareLock);
274  constrrelid = refRelOid;
275  }
276  else if (stmt->constrrel != NULL)
277  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
278  false);
279  }
280 
281  /* permission checks */
282  if (!isInternal)
283  {
284  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
285  ACL_TRIGGER);
286  if (aclresult != ACLCHECK_OK)
287  aclcheck_error(aclresult, ACL_KIND_CLASS,
289 
290  if (OidIsValid(constrrelid))
291  {
292  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
293  ACL_TRIGGER);
294  if (aclresult != ACLCHECK_OK)
295  aclcheck_error(aclresult, ACL_KIND_CLASS,
296  get_rel_name(constrrelid));
297  }
298  }
299 
300  /* Compute tgtype */
301  TRIGGER_CLEAR_TYPE(tgtype);
302  if (stmt->row)
303  TRIGGER_SETT_ROW(tgtype);
304  tgtype |= stmt->timing;
305  tgtype |= stmt->events;
306 
307  /* Disallow ROW-level TRUNCATE triggers */
308  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
309  ereport(ERROR,
310  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
311  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
312 
313  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
314  if (TRIGGER_FOR_INSTEAD(tgtype))
315  {
316  if (!TRIGGER_FOR_ROW(tgtype))
317  ereport(ERROR,
318  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
319  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
320  if (stmt->whenClause)
321  ereport(ERROR,
322  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
323  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
324  if (stmt->columns != NIL)
325  ereport(ERROR,
326  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
327  errmsg("INSTEAD OF triggers cannot have column lists")));
328  }
329 
330  /*
331  * We don't yet support naming ROW transition variables, but the parser
332  * recognizes the syntax so we can give a nicer message here.
333  *
334  * Per standard, REFERENCING TABLE names are only allowed on AFTER
335  * triggers. Per standard, REFERENCING ROW names are not allowed with FOR
336  * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is
337  * only allowed once. Per standard, OLD may not be specified when
338  * creating a trigger only for INSERT, and NEW may not be specified when
339  * creating a trigger only for DELETE.
340  *
341  * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to
342  * reference both ROW and TABLE transition data.
343  */
344  if (stmt->transitionRels != NIL)
345  {
346  List *varList = stmt->transitionRels;
347  ListCell *lc;
348 
349  foreach(lc, varList)
350  {
352 
353  if (!(tt->isTable))
354  ereport(ERROR,
355  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
356  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
357  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
358 
359  /*
360  * Because of the above test, we omit further ROW-related testing
361  * below. If we later allow naming OLD and NEW ROW variables,
362  * adjustments will be needed below.
363  */
364 
365  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
366  ereport(ERROR,
367  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
368  errmsg("\"%s\" is a foreign table",
370  errdetail("Triggers on foreign tables cannot have transition tables.")));
371 
372  if (rel->rd_rel->relkind == RELKIND_VIEW)
373  ereport(ERROR,
374  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
375  errmsg("\"%s\" is a view",
377  errdetail("Triggers on views cannot have transition tables.")));
378 
379  /*
380  * We currently don't allow row-level triggers with transition
381  * tables on partition or inheritance children. Such triggers
382  * would somehow need to see tuples converted to the format of the
383  * table they're attached to, and it's not clear which subset of
384  * tuples each child should see. See also the prohibitions in
385  * ATExecAttachPartition() and ATExecAddInherit().
386  */
387  if (TRIGGER_FOR_ROW(tgtype) && has_superclass(rel->rd_id))
388  {
389  /* Use appropriate error message. */
390  if (rel->rd_rel->relispartition)
391  ereport(ERROR,
392  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
393  errmsg("ROW triggers with transition tables are not supported on partitions")));
394  else
395  ereport(ERROR,
396  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
397  errmsg("ROW triggers with transition tables are not supported on inheritance children")));
398  }
399 
400  if (stmt->timing != TRIGGER_TYPE_AFTER)
401  ereport(ERROR,
402  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
403  errmsg("transition table name can only be specified for an AFTER trigger")));
404 
405  if (TRIGGER_FOR_TRUNCATE(tgtype))
406  ereport(ERROR,
407  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
408  errmsg("TRUNCATE triggers with transition tables are not supported")));
409 
410  /*
411  * We currently don't allow multi-event triggers ("INSERT OR
412  * UPDATE") with transition tables, because it's not clear how to
413  * handle INSERT ... ON CONFLICT statements which can fire both
414  * INSERT and UPDATE triggers. We show the inserted tuples to
415  * INSERT triggers and the updated tuples to UPDATE triggers, but
416  * it's not yet clear what INSERT OR UPDATE trigger should see.
417  * This restriction could be lifted if we can decide on the right
418  * semantics in a later release.
419  */
420  if (((TRIGGER_FOR_INSERT(tgtype) ? 1 : 0) +
421  (TRIGGER_FOR_UPDATE(tgtype) ? 1 : 0) +
422  (TRIGGER_FOR_DELETE(tgtype) ? 1 : 0)) != 1)
423  ereport(ERROR,
424  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
425  errmsg("transition tables cannot be specified for triggers with more than one event")));
426 
427  /*
428  * We currently don't allow column-specific triggers with
429  * transition tables. Per spec, that seems to require
430  * accumulating separate transition tables for each combination of
431  * columns, which is a lot of work for a rather marginal feature.
432  */
433  if (stmt->columns != NIL)
434  ereport(ERROR,
435  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
436  errmsg("transition tables cannot be specified for triggers with column lists")));
437 
438  /*
439  * We disallow constraint triggers with transition tables, to
440  * protect the assumption that such triggers can't be deferred.
441  * See notes with AfterTriggers data structures, below.
442  *
443  * Currently this is enforced by the grammar, so just Assert here.
444  */
445  Assert(!stmt->isconstraint);
446 
447  if (tt->isNew)
448  {
449  if (!(TRIGGER_FOR_INSERT(tgtype) ||
450  TRIGGER_FOR_UPDATE(tgtype)))
451  ereport(ERROR,
452  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
453  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
454 
455  if (newtablename != NULL)
456  ereport(ERROR,
457  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
458  errmsg("NEW TABLE cannot be specified multiple times")));
459 
460  newtablename = tt->name;
461  }
462  else
463  {
464  if (!(TRIGGER_FOR_DELETE(tgtype) ||
465  TRIGGER_FOR_UPDATE(tgtype)))
466  ereport(ERROR,
467  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
468  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
469 
470  if (oldtablename != NULL)
471  ereport(ERROR,
472  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
473  errmsg("OLD TABLE cannot be specified multiple times")));
474 
475  oldtablename = tt->name;
476  }
477  }
478 
479  if (newtablename != NULL && oldtablename != NULL &&
480  strcmp(newtablename, oldtablename) == 0)
481  ereport(ERROR,
482  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
483  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
484  }
485 
486  /*
487  * Parse the WHEN clause, if any
488  */
489  if (stmt->whenClause)
490  {
491  ParseState *pstate;
492  RangeTblEntry *rte;
493  List *varList;
494  ListCell *lc;
495 
496  /* Set up a pstate to parse with */
497  pstate = make_parsestate(NULL);
498  pstate->p_sourcetext = queryString;
499 
500  /*
501  * Set up RTEs for OLD and NEW references.
502  *
503  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
504  */
505  rte = addRangeTableEntryForRelation(pstate, rel,
506  makeAlias("old", NIL),
507  false, false);
508  addRTEtoQuery(pstate, rte, false, true, true);
509  rte = addRangeTableEntryForRelation(pstate, rel,
510  makeAlias("new", NIL),
511  false, false);
512  addRTEtoQuery(pstate, rte, false, true, true);
513 
514  /* Transform expression. Copy to be sure we don't modify original */
515  whenClause = transformWhereClause(pstate,
516  copyObject(stmt->whenClause),
518  "WHEN");
519  /* we have to fix its collations too */
520  assign_expr_collations(pstate, whenClause);
521 
522  /*
523  * Check for disallowed references to OLD/NEW.
524  *
525  * NB: pull_var_clause is okay here only because we don't allow
526  * subselects in WHEN clauses; it would fail to examine the contents
527  * of subselects.
528  */
529  varList = pull_var_clause(whenClause, 0);
530  foreach(lc, varList)
531  {
532  Var *var = (Var *) lfirst(lc);
533 
534  switch (var->varno)
535  {
536  case PRS2_OLD_VARNO:
537  if (!TRIGGER_FOR_ROW(tgtype))
538  ereport(ERROR,
539  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
540  errmsg("statement trigger's WHEN condition cannot reference column values"),
541  parser_errposition(pstate, var->location)));
542  if (TRIGGER_FOR_INSERT(tgtype))
543  ereport(ERROR,
544  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
545  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
546  parser_errposition(pstate, var->location)));
547  /* system columns are okay here */
548  break;
549  case PRS2_NEW_VARNO:
550  if (!TRIGGER_FOR_ROW(tgtype))
551  ereport(ERROR,
552  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
553  errmsg("statement trigger's WHEN condition cannot reference column values"),
554  parser_errposition(pstate, var->location)));
555  if (TRIGGER_FOR_DELETE(tgtype))
556  ereport(ERROR,
557  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
558  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
559  parser_errposition(pstate, var->location)));
560  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
561  ereport(ERROR,
562  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
563  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
564  parser_errposition(pstate, var->location)));
565  break;
566  default:
567  /* can't happen without add_missing_from, so just elog */
568  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
569  break;
570  }
571  }
572 
573  /* we'll need the rtable for recordDependencyOnExpr */
574  whenRtable = pstate->p_rtable;
575 
576  qual = nodeToString(whenClause);
577 
578  free_parsestate(pstate);
579  }
580  else
581  {
582  whenClause = NULL;
583  whenRtable = NIL;
584  qual = NULL;
585  }
586 
587  /*
588  * Find and validate the trigger function.
589  */
590  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
591  if (!isInternal)
592  {
593  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
594  if (aclresult != ACLCHECK_OK)
595  aclcheck_error(aclresult, ACL_KIND_PROC,
596  NameListToString(stmt->funcname));
597  }
598  funcrettype = get_func_rettype(funcoid);
599  if (funcrettype != TRIGGEROID)
600  {
601  /*
602  * We allow OPAQUE just so we can load old dump files. When we see a
603  * trigger function declared OPAQUE, change it to TRIGGER.
604  */
605  if (funcrettype == OPAQUEOID)
606  {
608  (errmsg("changing return type of function %s from %s to %s",
609  NameListToString(stmt->funcname),
610  "opaque", "trigger")));
612  }
613  else
614  ereport(ERROR,
615  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
616  errmsg("function %s must return type %s",
617  NameListToString(stmt->funcname), "trigger")));
618  }
619 
620  /*
621  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
622  * references one of the built-in RI_FKey trigger functions, assume it is
623  * from a dump of a pre-7.3 foreign key constraint, and take steps to
624  * convert this legacy representation into a regular foreign key
625  * constraint. Ugly, but necessary for loading old dump files.
626  */
627  if (stmt->isconstraint && !isInternal &&
628  list_length(stmt->args) >= 6 &&
629  (list_length(stmt->args) % 2) == 0 &&
631  {
632  /* Keep lock on target rel until end of xact */
633  heap_close(rel, NoLock);
634 
635  ConvertTriggerToFK(stmt, funcoid);
636 
637  return InvalidObjectAddress;
638  }
639 
640  /*
641  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
642  * corresponding pg_constraint entry.
643  */
644  if (stmt->isconstraint && !OidIsValid(constraintOid))
645  {
646  /* Internal callers should have made their own constraints */
647  Assert(!isInternal);
648  constraintOid = CreateConstraintEntry(stmt->trigname,
651  stmt->deferrable,
652  stmt->initdeferred,
653  true,
654  RelationGetRelid(rel),
655  NULL, /* no conkey */
656  0,
657  InvalidOid, /* no domain */
658  InvalidOid, /* no index */
659  InvalidOid, /* no foreign key */
660  NULL,
661  NULL,
662  NULL,
663  NULL,
664  0,
665  ' ',
666  ' ',
667  ' ',
668  NULL, /* no exclusion */
669  NULL, /* no check constraint */
670  NULL,
671  NULL,
672  true, /* islocal */
673  0, /* inhcount */
674  true, /* isnoinherit */
675  isInternal); /* is_internal */
676  }
677 
678  /*
679  * Generate the trigger's OID now, so that we can use it in the name if
680  * needed.
681  */
683 
684  trigoid = GetNewOid(tgrel);
685 
686  /*
687  * If trigger is internally generated, modify the provided trigger name to
688  * ensure uniqueness by appending the trigger OID. (Callers will usually
689  * supply a simple constant trigger name in these cases.)
690  */
691  if (isInternal)
692  {
693  snprintf(internaltrigname, sizeof(internaltrigname),
694  "%s_%u", stmt->trigname, trigoid);
695  trigname = internaltrigname;
696  }
697  else
698  {
699  /* user-defined trigger; use the specified trigger name as-is */
700  trigname = stmt->trigname;
701  }
702 
703  /*
704  * Scan pg_trigger for existing triggers on relation. We do this only to
705  * give a nice error message if there's already a trigger of the same
706  * name. (The unique index on tgrelid/tgname would complain anyway.) We
707  * can skip this for internally generated triggers, since the name
708  * modification above should be sufficient.
709  *
710  * NOTE that this is cool only because we have ShareRowExclusiveLock on
711  * the relation, so the trigger set won't be changing underneath us.
712  */
713  if (!isInternal)
714  {
715  ScanKeyInit(&key,
717  BTEqualStrategyNumber, F_OIDEQ,
719  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
720  NULL, 1, &key);
721  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
722  {
723  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
724 
725  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
726  ereport(ERROR,
728  errmsg("trigger \"%s\" for relation \"%s\" already exists",
729  trigname, RelationGetRelationName(rel))));
730  }
731  systable_endscan(tgscan);
732  }
733 
734  /*
735  * Build the new pg_trigger tuple.
736  */
737  memset(nulls, false, sizeof(nulls));
738 
741  CStringGetDatum(trigname));
742  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
743  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
745  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
746  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
747  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
748  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
751 
752  if (stmt->args)
753  {
754  ListCell *le;
755  char *args;
756  int16 nargs = list_length(stmt->args);
757  int len = 0;
758 
759  foreach(le, stmt->args)
760  {
761  char *ar = strVal(lfirst(le));
762 
763  len += strlen(ar) + 4;
764  for (; *ar; ar++)
765  {
766  if (*ar == '\\')
767  len++;
768  }
769  }
770  args = (char *) palloc(len + 1);
771  args[0] = '\0';
772  foreach(le, stmt->args)
773  {
774  char *s = strVal(lfirst(le));
775  char *d = args + strlen(args);
776 
777  while (*s)
778  {
779  if (*s == '\\')
780  *d++ = '\\';
781  *d++ = *s++;
782  }
783  strcpy(d, "\\000");
784  }
785  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
787  CStringGetDatum(args));
788  }
789  else
790  {
791  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
793  CStringGetDatum(""));
794  }
795 
796  /* build column number array if it's a column-specific trigger */
797  ncolumns = list_length(stmt->columns);
798  if (ncolumns == 0)
799  columns = NULL;
800  else
801  {
802  ListCell *cell;
803  int i = 0;
804 
805  columns = (int16 *) palloc(ncolumns * sizeof(int16));
806  foreach(cell, stmt->columns)
807  {
808  char *name = strVal(lfirst(cell));
809  int16 attnum;
810  int j;
811 
812  /* Lookup column name. System columns are not allowed */
813  attnum = attnameAttNum(rel, name, false);
814  if (attnum == InvalidAttrNumber)
815  ereport(ERROR,
816  (errcode(ERRCODE_UNDEFINED_COLUMN),
817  errmsg("column \"%s\" of relation \"%s\" does not exist",
818  name, RelationGetRelationName(rel))));
819 
820  /* Check for duplicates */
821  for (j = i - 1; j >= 0; j--)
822  {
823  if (columns[j] == attnum)
824  ereport(ERROR,
825  (errcode(ERRCODE_DUPLICATE_COLUMN),
826  errmsg("column \"%s\" specified more than once",
827  name)));
828  }
829 
830  columns[i++] = attnum;
831  }
832  }
833  tgattr = buildint2vector(columns, ncolumns);
834  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
835 
836  /* set tgqual if trigger has WHEN clause */
837  if (qual)
838  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
839  else
840  nulls[Anum_pg_trigger_tgqual - 1] = true;
841 
842  if (oldtablename)
844  CStringGetDatum(oldtablename));
845  else
846  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
847  if (newtablename)
849  CStringGetDatum(newtablename));
850  else
851  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
852 
853  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
854 
855  /* force tuple to have the desired OID */
856  HeapTupleSetOid(tuple, trigoid);
857 
858  /*
859  * Insert tuple into pg_trigger.
860  */
861  CatalogTupleInsert(tgrel, tuple);
862 
863  heap_freetuple(tuple);
865 
869  if (oldtablename)
871  if (newtablename)
873 
874  /*
875  * Update relation's pg_class entry. Crucial side-effect: other backends
876  * (and this one too!) are sent SI message to make them rebuild relcache
877  * entries.
878  */
880  tuple = SearchSysCacheCopy1(RELOID,
882  if (!HeapTupleIsValid(tuple))
883  elog(ERROR, "cache lookup failed for relation %u",
884  RelationGetRelid(rel));
885 
886  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
887 
888  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
889 
890  heap_freetuple(tuple);
892 
893  /*
894  * We used to try to update the rel's relcache entry here, but that's
895  * fairly pointless since it will happen as a byproduct of the upcoming
896  * CommandCounterIncrement...
897  */
898 
899  /*
900  * Record dependencies for trigger. Always place a normal dependency on
901  * the function.
902  */
903  myself.classId = TriggerRelationId;
904  myself.objectId = trigoid;
905  myself.objectSubId = 0;
906 
907  referenced.classId = ProcedureRelationId;
908  referenced.objectId = funcoid;
909  referenced.objectSubId = 0;
910  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
911 
912  if (isInternal && OidIsValid(constraintOid))
913  {
914  /*
915  * Internally-generated trigger for a constraint, so make it an
916  * internal dependency of the constraint. We can skip depending on
917  * the relation(s), as there'll be an indirect dependency via the
918  * constraint.
919  */
920  referenced.classId = ConstraintRelationId;
921  referenced.objectId = constraintOid;
922  referenced.objectSubId = 0;
923  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
924  }
925  else
926  {
927  /*
928  * User CREATE TRIGGER, so place dependencies. We make trigger be
929  * auto-dropped if its relation is dropped or if the FK relation is
930  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
931  */
932  referenced.classId = RelationRelationId;
933  referenced.objectId = RelationGetRelid(rel);
934  referenced.objectSubId = 0;
935  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
936  if (OidIsValid(constrrelid))
937  {
938  referenced.classId = RelationRelationId;
939  referenced.objectId = constrrelid;
940  referenced.objectSubId = 0;
941  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
942  }
943  /* Not possible to have an index dependency in this case */
944  Assert(!OidIsValid(indexOid));
945 
946  /*
947  * If it's a user-specified constraint trigger, make the constraint
948  * internally dependent on the trigger instead of vice versa.
949  */
950  if (OidIsValid(constraintOid))
951  {
952  referenced.classId = ConstraintRelationId;
953  referenced.objectId = constraintOid;
954  referenced.objectSubId = 0;
955  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
956  }
957  }
958 
959  /* If column-specific trigger, add normal dependencies on columns */
960  if (columns != NULL)
961  {
962  int i;
963 
964  referenced.classId = RelationRelationId;
965  referenced.objectId = RelationGetRelid(rel);
966  for (i = 0; i < ncolumns; i++)
967  {
968  referenced.objectSubId = columns[i];
969  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
970  }
971  }
972 
973  /*
974  * If it has a WHEN clause, add dependencies on objects mentioned in the
975  * expression (eg, functions, as well as any columns used).
976  */
977  if (whenClause != NULL)
978  recordDependencyOnExpr(&myself, whenClause, whenRtable,
980 
981  /* Post creation hook for new trigger */
983  isInternal);
984 
985  /* Keep lock on target rel until end of xact */
986  heap_close(rel, NoLock);
987 
988  return myself;
989 }
signed short int16
Definition: c.h:245
#define NIL
Definition: pg_list.h:69
#define Anum_pg_trigger_tgdeferrable
Definition: pg_trigger.h:88
#define TRIGGER_FOR_DELETE(type)
Definition: pg_trigger.h:135
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3701
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
int errhint(const char *fmt,...)
Definition: elog.c:987
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
Oid GetUserId(void)
Definition: miscinit.c:284
#define PointerGetDatum(X)
Definition: postgres.h:562
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:53
#define Anum_pg_trigger_tgconstraint
Definition: pg_trigger.h:87
#define ProcedureRelationId
Definition: pg_proc.h:33
Node * whenClause
Definition: parsenodes.h:2364
#define RelationRelationId
Definition: pg_class.h:29
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:112
#define Anum_pg_trigger_tgqual
Definition: pg_trigger.h:93
#define TRIGGER_CLEAR_TYPE(type)
Definition: pg_trigger.h:118
#define Int16GetDatum(X)
Definition: postgres.h:457
#define Anum_pg_trigger_tgtype
Definition: pg_trigger.h:82
#define AccessShareLock
Definition: lockdefs.h:36
#define Anum_pg_trigger_tgnargs
Definition: pg_trigger.h:90
Definition: nodes.h:509
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
int namestrcmp(Name name, const char *str)
Definition: name.c:247
#define TRIGGER_FOR_UPDATE(type)
Definition: pg_trigger.h:136
AttrNumber varattno
Definition: primnodes.h:168
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
List * pull_var_clause(Node *node, int flags)
Definition: var.c:535
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:163
#define Anum_pg_trigger_tgisinternal
Definition: pg_trigger.h:84
#define OidIsValid(objectId)
Definition: c.h:532
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:155
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1459
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define TriggerRelidNameIndexId
Definition: indexing.h:249
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#define NAMEDATALEN
void assign_expr_collations(ParseState *pstate, Node *expr)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:384
RangeVar * constrrel
Definition: parsenodes.h:2371
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define TRIGGER_FOR_ROW(type)
Definition: pg_trigger.h:130
void pfree(void *pointer)
Definition: mcxt.c:949
#define OPAQUEOID
Definition: pg_type.h:700
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define TRIGGER_TYPE_AFTER
Definition: pg_trigger.h:112
#define TRIGGEROID
Definition: pg_type.h:692
ItemPointerData t_self
Definition: htup.h:65
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:282
Datum byteain(PG_FUNCTION_ARGS)
Definition: varlena.c:255
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define ACL_TRIGGER
Definition: parsenodes.h:78
int location
Definition: primnodes.h:178
#define NoLock
Definition: lockdefs.h:34
#define TRIGGER_SETT_ROW(type)
Definition: pg_trigger.h:120
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define CStringGetDatum(X)
Definition: postgres.h:584
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
Definition: dependency.c:1351
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
const char * p_sourcetext
Definition: parse_node.h:171
#define TRIGGER_FOR_BEFORE(type)
Definition: pg_trigger.h:131
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
Definition: trigger.c:1019
List * transitionRels
Definition: parsenodes.h:2367
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid rd_id
Definition: rel.h:116
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:166
char * NameListToString(List *names)
Definition: namespace.c:3063
#define Anum_pg_trigger_tgnewtable
Definition: pg_trigger.h:95
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Definition: c.h:461
#define Anum_pg_trigger_tgconstrindid
Definition: pg_trigger.h:86
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:372
#define Anum_pg_trigger_tgenabled
Definition: pg_trigger.h:83
Oid GetNewOid(Relation relation)
Definition: catalog.c:289
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
void SetFunctionReturnType(Oid funcOid, Oid newRetType)
#define TRIGGER_FOR_TRUNCATE(type)
Definition: pg_trigger.h:137
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
TupleDesc rd_att
Definition: rel.h:115
#define BoolGetDatum(X)
Definition: postgres.h:408
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1318
bool allowSystemTableMods
Definition: globals.c:112
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
#define Assert(condition)
Definition: c.h:664
#define lfirst(lc)
Definition: pg_list.h:106
#define Anum_pg_trigger_tgargs
Definition: pg_trigger.h:92
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
#define Anum_pg_trigger_tgconstrrelid
Definition: pg_trigger.h:85
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
#define TRIGGER_FOR_INSERT(type)
Definition: pg_trigger.h:134
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
const char * name
Definition: encode.c:521
#define InvalidAttrNumber
Definition: attnum.h:23
#define CharGetDatum(X)
Definition: postgres.h:422
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4422
#define DatumGetPointer(X)
Definition: postgres.h:555
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1929
#define Anum_pg_trigger_tgoldtable
Definition: pg_trigger.h:94
static Datum values[MAXATTR]
Definition: bootstrap.c:164
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:168
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:79
#define RELKIND_VIEW
Definition: pg_class.h:164
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
RangeVar * relation
Definition: parsenodes.h:2355
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:91
char * nodeToString(const void *obj)
Definition: outfuncs.c:4255
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define CONSTRAINT_TRIGGER
#define copyObject(obj)
Definition: nodes.h:622
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:77
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RI_TRIGGER_NONE
Definition: trigger.h:268
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define RelationGetRelid(relation)
Definition: rel.h:416
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define Anum_pg_trigger_tgfoid
Definition: pg_trigger.h:81
#define Anum_pg_trigger_tginitdeferred
Definition: pg_trigger.h:89
#define Anum_pg_trigger_tgattr
Definition: pg_trigger.h:91
#define Natts_pg_trigger
Definition: pg_trigger.h:78
#define TRIGGER_FOR_INSTEAD(type)
Definition: pg_trigger.h:133
#define RelationGetNamespace(relation)
Definition: rel.h:443
List * p_rtable
Definition: parse_node.h:172
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

Definition at line 1581 of file trigger.c.

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

Referenced by ATExecEnableDisableTrigger().

1583 {
1584  Relation tgrel;
1585  int nkeys;
1586  ScanKeyData keys[2];
1587  SysScanDesc tgscan;
1588  HeapTuple tuple;
1589  bool found;
1590  bool changed;
1591 
1592  /* Scan the relevant entries in pg_triggers */
1594 
1595  ScanKeyInit(&keys[0],
1597  BTEqualStrategyNumber, F_OIDEQ,
1599  if (tgname)
1600  {
1601  ScanKeyInit(&keys[1],
1603  BTEqualStrategyNumber, F_NAMEEQ,
1604  CStringGetDatum(tgname));
1605  nkeys = 2;
1606  }
1607  else
1608  nkeys = 1;
1609 
1610  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1611  NULL, nkeys, keys);
1612 
1613  found = changed = false;
1614 
1615  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1616  {
1617  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1618 
1619  if (oldtrig->tgisinternal)
1620  {
1621  /* system trigger ... ok to process? */
1622  if (skip_system)
1623  continue;
1624  if (!superuser())
1625  ereport(ERROR,
1626  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1627  errmsg("permission denied: \"%s\" is a system trigger",
1628  NameStr(oldtrig->tgname))));
1629  }
1630 
1631  found = true;
1632 
1633  if (oldtrig->tgenabled != fires_when)
1634  {
1635  /* need to change this one ... make a copy to scribble on */
1636  HeapTuple newtup = heap_copytuple(tuple);
1637  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1638 
1639  newtrig->tgenabled = fires_when;
1640 
1641  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1642 
1643  heap_freetuple(newtup);
1644 
1645  changed = true;
1646  }
1647 
1649  HeapTupleGetOid(tuple), 0);
1650  }
1651 
1652  systable_endscan(tgscan);
1653 
1654  heap_close(tgrel, RowExclusiveLock);
1655 
1656  if (tgname && !found)
1657  ereport(ERROR,
1658  (errcode(ERRCODE_UNDEFINED_OBJECT),
1659  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1660  tgname, RelationGetRelationName(rel))));
1661 
1662  /*
1663  * If we changed anything, broadcast a SI inval message to force each
1664  * backend (including our own!) to rebuild relation's relcache entry.
1665  * Otherwise they will fail to apply the change promptly.
1666  */
1667  if (changed)
1669 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define TriggerRelidNameIndexId
Definition: indexing.h:249
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:584
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:72
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1233
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:493
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define RelationGetRelid(relation)
Definition: rel.h:416
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TransitionCaptureState transition_capture 
)

Definition at line 2572 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2576 {
2577  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2578 
2579  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2580  (transition_capture && transition_capture->tcs_delete_old_table))
2581  {
2582  HeapTuple trigtuple;
2583 
2584  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2585  if (fdw_trigtuple == NULL)
2586  trigtuple = GetTupleForTrigger(estate,
2587  NULL,
2588  relinfo,
2589  tupleid,
2591  NULL);
2592  else
2593  trigtuple = fdw_trigtuple;
2594 
2596  true, trigtuple, NULL, NIL, NULL,
2597  transition_capture);
2598  if (trigtuple != fdw_trigtuple)
2599  heap_freetuple(trigtuple);
2600  }
2601 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
bool trig_delete_after_row
Definition: reltrigger.h:66
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:664
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3007
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2354 of file trigger.c.

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

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

2357 {
2358  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2359 
2360  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2361  (transition_capture && transition_capture->tcs_insert_new_table))
2363  true, NULL, trigtuple,
2364  recheckIndexes, NULL,
2365  transition_capture);
2366 }
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2841 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), HeapTupleIsValid, 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 ExecSimpleRelationUpdate(), and ExecUpdate().

2847 {
2848  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2849 
2850  if ((trigdesc && trigdesc->trig_update_after_row) ||
2851  (transition_capture &&
2852  (transition_capture->tcs_update_old_table ||
2853  transition_capture->tcs_update_new_table)))
2854  {
2855  HeapTuple trigtuple;
2856 
2857  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2858  if (fdw_trigtuple == NULL)
2859  trigtuple = GetTupleForTrigger(estate,
2860  NULL,
2861  relinfo,
2862  tupleid,
2864  NULL);
2865  else
2866  trigtuple = fdw_trigtuple;
2867 
2869  true, trigtuple, newtuple, recheckIndexes,
2870  GetUpdatedColumns(relinfo, estate),
2871  transition_capture);
2872  if (trigtuple != fdw_trigtuple)
2873  heap_freetuple(trigtuple);
2874  }
2875 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
bool trig_update_after_row
Definition: reltrigger.h:61
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:664
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3007
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2492 of file trigger.c.

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

Referenced by fireASTriggers().

2494 {
2495  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2496 
2497  if (trigdesc && trigdesc->trig_delete_after_statement)
2499  false, NULL, NULL, NIL, NULL, transition_capture);
2500 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2277 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2279 {
2280  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2281 
2282  if (trigdesc && trigdesc->trig_insert_after_statement)
2284  false, NULL, NULL, NIL, NULL, transition_capture);
2285 }
#define NIL
Definition: pg_list.h:69
bool trig_insert_after_statement
Definition: reltrigger.h:59
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2996 of file trigger.c.

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

Referenced by ExecuteTruncate().

2997 {
2998  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2999 
3000  if (trigdesc && trigdesc->trig_truncate_after_statement)
3002  false, NULL, NULL, NIL, NULL, NULL);
3003 }
#define NIL
Definition: pg_list.h:69
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
bool trig_truncate_after_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101
void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2711 of file trigger.c.

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

Referenced by fireASTriggers().

2713 {
2714  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2715 
2716  if (trigdesc && trigdesc->trig_update_after_statement)
2718  false, NULL, NULL, NIL,
2719  GetUpdatedColumns(relinfo, estate),
2720  transition_capture);
2721 }
#define NIL
Definition: pg_list.h:69
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture)
Definition: trigger.c:5439
bool trig_update_after_statement
Definition: reltrigger.h:64
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2503 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2507 {
2508  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2509  bool result = true;
2510  TriggerData LocTriggerData;
2511  HeapTuple trigtuple;
2512  HeapTuple newtuple;
2513  TupleTableSlot *newSlot;
2514  int i;
2515 
2516  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2517  if (fdw_trigtuple == NULL)
2518  {
2519  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2520  LockTupleExclusive, &newSlot);
2521  if (trigtuple == NULL)
2522  return false;
2523  }
2524  else
2525  trigtuple = fdw_trigtuple;
2526 
2527  LocTriggerData.type = T_TriggerData;
2528  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2531  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2532  LocTriggerData.tg_newtuple = NULL;
2533  LocTriggerData.tg_oldtable = NULL;
2534  LocTriggerData.tg_newtable = NULL;
2535  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2536  for (i = 0; i < trigdesc->numtriggers; i++)
2537  {
2538  Trigger *trigger = &trigdesc->triggers[i];
2539 
2540  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2544  continue;
2545  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2546  NULL, trigtuple, NULL))
2547  continue;
2548 
2549  LocTriggerData.tg_trigtuple = trigtuple;
2550  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2551  LocTriggerData.tg_trigger = trigger;
2552  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2553  i,
2554  relinfo->ri_TrigFunctions,
2555  relinfo->ri_TrigInstrument,
2556  GetPerTupleMemoryContext(estate));
2557  if (newtuple == NULL)
2558  {
2559  result = false; /* tell caller to suppress delete */
2560  break;
2561  }
2562  if (newtuple != trigtuple)
2563  heap_freetuple(newtuple);
2564  }
2565  if (trigtuple != fdw_trigtuple)
2566  heap_freetuple(trigtuple);
2567 
2568  return result;
2569 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
return result
Definition: formatting.c:1633
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:664
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3007
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecBRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

Definition at line 2288 of file trigger.c.

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

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

2290 {
2291  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2292  HeapTuple slottuple = ExecMaterializeSlot(slot);
2293  HeapTuple newtuple = slottuple;
2294  HeapTuple oldtuple;
2295  TriggerData LocTriggerData;
2296  int i;
2297 
2298  LocTriggerData.type = T_TriggerData;
2299  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2302  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2303  LocTriggerData.tg_newtuple = NULL;
2304  LocTriggerData.tg_oldtable = NULL;
2305  LocTriggerData.tg_newtable = NULL;
2306  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2307  for (i = 0; i < trigdesc->numtriggers; i++)
2308  {
2309  Trigger *trigger = &trigdesc->triggers[i];
2310 
2311  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2315  continue;
2316  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2317  NULL, NULL, newtuple))
2318  continue;
2319 
2320  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2321  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2322  LocTriggerData.tg_trigger = trigger;
2323  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2324  i,
2325  relinfo->ri_TrigFunctions,
2326  relinfo->ri_TrigInstrument,
2327  GetPerTupleMemoryContext(estate));
2328  if (oldtuple != newtuple && oldtuple != slottuple)
2329  heap_freetuple(oldtuple);
2330  if (newtuple == NULL)
2331  return NULL; /* "do nothing" */
2332  }
2333 
2334  if (newtuple != slottuple)
2335  {
2336  /*
2337  * Return the modified tuple using the es_trig_tuple_slot. We assume
2338  * the tuple was allocated in per-tuple memory context, and therefore
2339  * will go away by itself. The tuple table slot should not try to
2340  * clear it.
2341  */
2342  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2343  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2344 
2345  if (newslot->tts_tupleDescriptor != tupdesc)
2346  ExecSetSlotDescriptor(newslot, tupdesc);
2347  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2348  slot = newslot;
2349  }
2350  return slot;
2351 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
#define RelationGetDescr(relation)
Definition: rel.h:428
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:460
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecBRUpdateTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
TupleTableSlot slot 
)

Definition at line 2724 of file trigger.c.

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

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2729 {
2730  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2731  HeapTuple slottuple = ExecMaterializeSlot(slot);
2732  HeapTuple newtuple = slottuple;
2733  TriggerData LocTriggerData;
2734  HeapTuple trigtuple;
2735  HeapTuple oldtuple;
2736  TupleTableSlot *newSlot;
2737  int i;
2738  Bitmapset *updatedCols;
2739  LockTupleMode lockmode;
2740 
2741  /* Determine lock mode to use */
2742  lockmode = ExecUpdateLockMode(estate, relinfo);
2743 
2744  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2745  if (fdw_trigtuple == NULL)
2746  {
2747  /* get a copy of the on-disk tuple we are planning to update */
2748  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2749  lockmode, &newSlot);
2750  if (trigtuple == NULL)
2751  return NULL; /* cancel the update action */
2752  }
2753  else
2754  {
2755  trigtuple = fdw_trigtuple;
2756  newSlot = NULL;
2757  }
2758 
2759  /*
2760  * In READ COMMITTED isolation level it's possible that target tuple was
2761  * changed due to concurrent update. In that case we have a raw subplan
2762  * output tuple in newSlot, and need to run it through the junk filter to
2763  * produce an insertable tuple.
2764  *
2765  * Caution: more than likely, the passed-in slot is the same as the
2766  * junkfilter's output slot, so we are clobbering the original value of
2767  * slottuple by doing the filtering. This is OK since neither we nor our
2768  * caller have any more interest in the prior contents of that slot.
2769  */
2770  if (newSlot != NULL)
2771  {
2772  slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
2773  slottuple = ExecMaterializeSlot(slot);
2774  newtuple = slottuple;
2775  }
2776 
2777 
2778  LocTriggerData.type = T_TriggerData;
2779  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2782  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2783  LocTriggerData.tg_oldtable = NULL;
2784  LocTriggerData.tg_newtable = NULL;
2785  updatedCols = GetUpdatedColumns(relinfo, estate);
2786  for (i = 0; i < trigdesc->numtriggers; i++)
2787  {
2788  Trigger *trigger = &trigdesc->triggers[i];
2789 
2790  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2794  continue;
2795  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2796  updatedCols, trigtuple, newtuple))
2797  continue;
2798 
2799  LocTriggerData.tg_trigtuple = trigtuple;
2800  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2801  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2802  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2803  LocTriggerData.tg_trigger = trigger;
2804  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2805  i,
2806  relinfo->ri_TrigFunctions,
2807  relinfo->ri_TrigInstrument,
2808  GetPerTupleMemoryContext(estate));
2809  if (oldtuple != newtuple && oldtuple != slottuple)
2810  heap_freetuple(oldtuple);
2811  if (newtuple == NULL)
2812  {
2813  if (trigtuple != fdw_trigtuple)
2814  heap_freetuple(trigtuple);
2815  return NULL; /* "do nothing" */
2816  }
2817  }
2818  if (trigtuple != fdw_trigtuple)
2819  heap_freetuple(trigtuple);
2820 
2821  if (newtuple != slottuple)
2822  {
2823  /*
2824  * Return the modified tuple using the es_trig_tuple_slot. We assume
2825  * the tuple was allocated in per-tuple memory context, and therefore
2826  * will go away by itself. The tuple table slot should not try to
2827  * clear it.
2828  */
2829  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2830  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2831 
2832  if (newslot->tts_tupleDescriptor != tupdesc)
2833  ExecSetSlotDescriptor(newslot, tupdesc);
2834  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2835  slot = newslot;
2836  }
2837  return slot;
2838 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
JunkFilter * ri_junkFilter
Definition: execnodes.h:396
Relation ri_RelationDesc
Definition: execnodes.h:354
#define RelationGetDescr(relation)
Definition: rel.h:428
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
LockTupleMode
Definition: heapam.h:38
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:460
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:262
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:102
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:664
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2358
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3007
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2435 of file trigger.c.

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

Referenced by fireBSTriggers().

2436 {
2437  TriggerDesc *trigdesc;
2438  int i;
2439  TriggerData LocTriggerData;
2440 
2441  trigdesc = relinfo->ri_TrigDesc;
2442 
2443  if (trigdesc == NULL)
2444  return;
2445  if (!trigdesc->trig_delete_before_statement)
2446  return;
2447 
2448  /* no-op if we already fired BS triggers in this context */
2450  CMD_DELETE))
2451  return;
2452 
2453  LocTriggerData.type = T_TriggerData;
2454  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2456  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2457  LocTriggerData.tg_trigtuple = NULL;
2458  LocTriggerData.tg_newtuple = NULL;
2459  LocTriggerData.tg_oldtable = NULL;
2460  LocTriggerData.tg_newtable = NULL;
2461  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2462  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2463  for (i = 0; i < trigdesc->numtriggers; i++)
2464  {
2465  Trigger *trigger = &trigdesc->triggers[i];
2466  HeapTuple newtuple;
2467 
2468  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2472  continue;
2473  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2474  NULL, NULL, NULL))
2475  continue;
2476 
2477  LocTriggerData.tg_trigger = trigger;
2478  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2479  i,
2480  relinfo->ri_TrigFunctions,
2481  relinfo->ri_TrigInstrument,
2482  GetPerTupleMemoryContext(estate));
2483 
2484  if (newtuple)
2485  ereport(ERROR,
2486  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2487  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2488  }
2489 }
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5731
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
bool trig_delete_before_statement
Definition: reltrigger.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
int errmsg(const char *fmt,...)
Definition: elog.c:797
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
#define RelationGetRelid(relation)
Definition: rel.h:416
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2220 of file trigger.c.

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

Referenced by CopyFrom(), and fireBSTriggers().

2221 {
2222  TriggerDesc *trigdesc;
2223  int i;
2224  TriggerData LocTriggerData;
2225 
2226  trigdesc = relinfo->ri_TrigDesc;
2227 
2228  if (trigdesc == NULL)
2229  return;
2230  if (!trigdesc->trig_insert_before_statement)
2231  return;
2232 
2233  /* no-op if we already fired BS triggers in this context */
2235  CMD_INSERT))
2236  return;
2237 
2238  LocTriggerData.type = T_TriggerData;
2239  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2241  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2242  LocTriggerData.tg_trigtuple = NULL;
2243  LocTriggerData.tg_newtuple = NULL;
2244  LocTriggerData.tg_oldtable = NULL;
2245  LocTriggerData.tg_newtable = NULL;
2246  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2247  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2248  for (i = 0; i < trigdesc->numtriggers; i++)
2249  {
2250  Trigger *trigger = &trigdesc->triggers[i];
2251  HeapTuple newtuple;
2252 
2253  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2257  continue;
2258  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2259  NULL, NULL, NULL))
2260  continue;
2261 
2262  LocTriggerData.tg_trigger = trigger;
2263  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2264  i,
2265  relinfo->ri_TrigFunctions,
2266  relinfo->ri_TrigInstrument,
2267  GetPerTupleMemoryContext(estate));
2268 
2269  if (newtuple)
2270  ereport(ERROR,
2271  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2272  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2273  }
2274 }
Relation ri_RelationDesc
Definition: execnodes.h:354
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5731
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
bool trig_insert_before_statement
Definition: reltrigger.h:58
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
int errmsg(const char *fmt,...)
Definition: elog.c:797
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
#define RelationGetRelid(relation)
Definition: rel.h:416
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2944 of file trigger.c.

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

Referenced by ExecuteTruncate().

2945 {
2946  TriggerDesc *trigdesc;
2947  int i;
2948  TriggerData LocTriggerData;
2949 
2950  trigdesc = relinfo->ri_TrigDesc;
2951 
2952  if (trigdesc == NULL)
2953  return;
2954  if (!trigdesc->trig_truncate_before_statement)
2955  return;
2956 
2957  LocTriggerData.type = T_TriggerData;
2958  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
2960  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2961  LocTriggerData.tg_trigtuple = NULL;
2962  LocTriggerData.tg_newtuple = NULL;
2963  LocTriggerData.tg_oldtable = NULL;
2964  LocTriggerData.tg_newtable = NULL;
2965  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2966  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2967  for (i = 0; i < trigdesc->numtriggers; i++)
2968  {
2969  Trigger *trigger = &trigdesc->triggers[i];
2970  HeapTuple newtuple;
2971 
2972  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2976  continue;
2977  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2978  NULL, NULL, NULL))
2979  continue;
2980 
2981  LocTriggerData.tg_trigger = trigger;
2982  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2983  i,
2984  relinfo->ri_TrigFunctions,
2985  relinfo->ri_TrigInstrument,
2986  GetPerTupleMemoryContext(estate));
2987 
2988  if (newtuple)
2989  ereport(ERROR,
2990  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2991  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2992  }
2993 }
Relation ri_RelationDesc
Definition: execnodes.h:354
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
bool trig_truncate_before_statement
Definition: reltrigger.h:71
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
#define TRIGGER_TYPE_TRUNCATE
Definition: pg_trigger.h:103
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:101
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
int errmsg(const char *fmt,...)
Definition: elog.c:797
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2651 of file trigger.c.

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

Referenced by fireBSTriggers().

2652 {
2653  TriggerDesc *trigdesc;
2654  int i;
2655  TriggerData LocTriggerData;
2656  Bitmapset *updatedCols;
2657 
2658  trigdesc = relinfo->ri_TrigDesc;
2659 
2660  if (trigdesc == NULL)
2661  return;
2662  if (!trigdesc->trig_update_before_statement)
2663  return;
2664 
2665  /* no-op if we already fired BS triggers in this context */
2667  CMD_UPDATE))
2668  return;
2669 
2670  updatedCols = GetUpdatedColumns(relinfo, estate);
2671 
2672  LocTriggerData.type = T_TriggerData;
2673  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2675  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2676  LocTriggerData.tg_trigtuple = NULL;
2677  LocTriggerData.tg_newtuple = NULL;
2678  LocTriggerData.tg_oldtable = NULL;
2679  LocTriggerData.tg_newtable = NULL;
2680  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2681  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2682  for (i = 0; i < trigdesc->numtriggers; i++)
2683  {
2684  Trigger *trigger = &trigdesc->triggers[i];
2685  HeapTuple newtuple;
2686 
2687  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2691  continue;
2692  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2693  updatedCols, NULL, NULL))
2694  continue;
2695 
2696  LocTriggerData.tg_trigger = trigger;
2697  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2698  i,
2699  relinfo->ri_TrigFunctions,
2700  relinfo->ri_TrigInstrument,
2701  GetPerTupleMemoryContext(estate));
2702 
2703  if (newtuple)
2704  ereport(ERROR,
2705  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2706  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2707  }
2708 }
Relation ri_RelationDesc
Definition: execnodes.h:354
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
bool trig_update_before_statement
Definition: reltrigger.h:63
HeapTuple tg_trigtuple
Definition: trigger.h:35
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
Definition: trigger.c:5731
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:106
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:102
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
int errmsg(const char *fmt,...)
Definition: elog.c:797
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
#define RelationGetRelid(relation)
Definition: rel.h:416
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
bool ExecIRDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple 
)

Definition at line 2604 of file trigger.c.

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

Referenced by ExecDelete().

2606 {
2607  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2608  TriggerData LocTriggerData;
2609  HeapTuple rettuple;
2610  int i;
2611 
2612  LocTriggerData.type = T_TriggerData;
2613  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2616  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2617  LocTriggerData.tg_newtuple = NULL;
2618  LocTriggerData.tg_oldtable = NULL;
2619  LocTriggerData.tg_newtable = NULL;
2620  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2621  for (i = 0; i < trigdesc->numtriggers; i++)
2622  {
2623  Trigger *trigger = &trigdesc->triggers[i];
2624 
2625  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2629  continue;
2630  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2631  NULL, trigtuple, NULL))
2632  continue;
2633 
2634  LocTriggerData.tg_trigtuple = trigtuple;
2635  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2636  LocTriggerData.tg_trigger = trigger;
2637  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2638  i,
2639  relinfo->ri_TrigFunctions,
2640  relinfo->ri_TrigInstrument,
2641  GetPerTupleMemoryContext(estate));
2642  if (rettuple == NULL)
2643  return false; /* Delete was suppressed */
2644  if (rettuple != trigtuple)
2645  heap_freetuple(rettuple);
2646  }
2647  return true;
2648 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:99
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecIRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

Definition at line 2369 of file trigger.c.

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

Referenced by CopyFrom(), and ExecInsert().

2371 {
2372  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2373  HeapTuple slottuple = ExecMaterializeSlot(slot);
2374  HeapTuple newtuple = slottuple;
2375  HeapTuple oldtuple;
2376  TriggerData LocTriggerData;
2377  int i;
2378 
2379  LocTriggerData.type = T_TriggerData;
2380  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2383  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2384  LocTriggerData.tg_newtuple = NULL;
2385  LocTriggerData.tg_oldtable = NULL;
2386  LocTriggerData.tg_newtable = NULL;
2387  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2388  for (i = 0; i < trigdesc->numtriggers; i++)
2389  {
2390  Trigger *trigger = &trigdesc->triggers[i];
2391 
2392  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2396  continue;
2397  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2398  NULL, NULL, newtuple))
2399  continue;
2400 
2401  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2402  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2403  LocTriggerData.tg_trigger = trigger;
2404  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2405  i,
2406  relinfo->ri_TrigFunctions,
2407  relinfo->ri_TrigInstrument,
2408  GetPerTupleMemoryContext(estate));
2409  if (oldtuple != newtuple && oldtuple != slottuple)
2410  heap_freetuple(oldtuple);
2411  if (newtuple == NULL)
2412  return NULL; /* "do nothing" */
2413  }
2414 
2415  if (newtuple != slottuple)
2416  {
2417  /*
2418  * Return the modified tuple using the es_trig_tuple_slot. We assume
2419  * the tuple was allocated in per-tuple memory context, and therefore
2420  * will go away by itself. The tuple table slot should not try to
2421  * clear it.
2422  */
2423  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2424  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2425 
2426  if (newslot->tts_tupleDescriptor != tupdesc)
2427  ExecSetSlotDescriptor(newslot, tupdesc);
2428  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2429  slot = newslot;
2430  }
2431  return slot;
2432 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
#define RelationGetDescr(relation)
Definition: rel.h:428
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:460
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_TYPE_INSERT
Definition: pg_trigger.h:100
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:98
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecIRUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
TupleTableSlot slot 
)

Definition at line 2878 of file trigger.c.

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

Referenced by ExecUpdate().

2880 {
2881  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2882  HeapTuple slottuple = ExecMaterializeSlot(slot);
2883  HeapTuple newtuple = slottuple;
2884  TriggerData LocTriggerData;
2885  HeapTuple oldtuple;
2886  int i;
2887 
2888  LocTriggerData.type = T_TriggerData;
2889  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2892  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2893  LocTriggerData.tg_oldtable = NULL;
2894  LocTriggerData.tg_newtable = NULL;
2895  for (i = 0; i < trigdesc->numtriggers; i++)
2896  {
2897  Trigger *trigger = &trigdesc->triggers[i];
2898 
2899  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2903  continue;
2904  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2905  NULL, trigtuple, newtuple))
2906  continue;
2907 
2908  LocTriggerData.tg_trigtuple = trigtuple;
2909  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2910  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2911  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2912  LocTriggerData.tg_trigger = trigger;
2913  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2914  i,
2915  relinfo->ri_TrigFunctions,
2916  relinfo->ri_TrigInstrument,
2917  GetPerTupleMemoryContext(estate));
2918  if (oldtuple != newtuple && oldtuple != slottuple)
2919  heap_freetuple(oldtuple);
2920  if (newtuple == NULL)
2921  return NULL; /* "do nothing" */
2922  }
2923 
2924  if (newtuple != slottuple)
2925  {
2926  /*
2927  * Return the modified tuple using the es_trig_tuple_slot. We assume
2928  * the tuple was allocated in per-tuple memory context, and therefore
2929  * will go away by itself. The tuple table slot should not try to
2930  * clear it.
2931  */
2932  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2933  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2934 
2935  if (newslot->tts_tupleDescriptor != tupdesc)
2936  ExecSetSlotDescriptor(newslot, tupdesc);
2937  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2938  slot = newslot;
2939  }
2940  return slot;
2941 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:104
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
#define RelationGetDescr(relation)
Definition: rel.h:428
Buffer tg_newtuplebuf
Definition: trigger.h:39
#define TRIGGER_TYPE_MATCHES(type, level, timing, event)
Definition: pg_trigger.h:146
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:375
#define InvalidBuffer
Definition: buf.h:25
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:108
int16 tgtype
Definition: reltrigger.h:29
Trigger * triggers
Definition: reltrigger.h:48
Buffer tg_trigtuplebuf
Definition: trigger.h:38
#define TRIGGER_TYPE_ROW
Definition: pg_trigger.h:98
TupleTableSlot * es_trig_tuple_slot
Definition: execnodes.h:460
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
int numtriggers
Definition: reltrigger.h:49
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
Trigger * tg_trigger
Definition: trigger.h:37
HeapTuple tg_newtuple
Definition: trigger.h:36
#define TRIGGER_TYPE_UPDATE
Definition: pg_trigger.h:102
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, HeapTuple oldtup, HeapTuple newtup)
Definition: trigger.c:3151
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:481
NodeTag type
Definition: trigger.h:32
int i
Tuplestorestate * tg_newtable
Definition: trigger.h:41
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
Definition: trigger.c:2126
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2096 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2097 {
2098  if (trigdesc != NULL)
2099  {
2100  int i;
2101 
2102  for (i = 0; i < trigdesc->numtriggers; ++i)
2103  {
2104  Trigger *trigger = &trigdesc->triggers[i];
2105 
2106  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2107  return trigger->tgname;
2108  }
2109  }
2110 
2111  return NULL;
2112 }
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char * tgnewtable
Definition: reltrigger.h:43
int i
char * tgoldtable
Definition: reltrigger.h:42
void FreeTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1966 of file trigger.c.

References i, TriggerDesc::numtriggers, pfree(), Trigger::tgargs, Trigger::tgattr, Trigger::tgname, Trigger::tgnargs, Trigger::tgnattr, Trigger::tgnewtable, Trigger::tgoldtable, Trigger::tgqual, and TriggerDesc::triggers.

Referenced by RelationBuildTriggers(), and RelationDestroyRelation().

1967 {
1968  Trigger *trigger;
1969  int i;
1970 
1971  if (trigdesc == NULL)
1972  return;
1973 
1974  trigger = trigdesc->triggers;
1975  for (i = 0; i < trigdesc->numtriggers; i++)
1976  {
1977  pfree(trigger->tgname);
1978  if (trigger->tgnattr > 0)
1979  pfree(trigger->tgattr);
1980  if (trigger->tgnargs > 0)
1981  {
1982  while (--(trigger->tgnargs) >= 0)
1983  pfree(trigger->tgargs[trigger->tgnargs]);
1984  pfree(trigger->tgargs);
1985  }
1986  if (trigger->tgqual)
1987  pfree(trigger->tgqual);
1988  if (trigger->tgoldtable)
1989  pfree(trigger->tgoldtable);
1990  if (trigger->tgnewtable)
1991  pfree(trigger->tgnewtable);
1992  trigger++;
1993  }
1994  pfree(trigdesc->triggers);
1995  pfree(trigdesc);
1996 }
void pfree(void *pointer)
Definition: mcxt.c:949
char * tgqual
Definition: reltrigger.h:41
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char ** tgargs
Definition: reltrigger.h:40
int16 * tgattr
Definition: reltrigger.h:39
char * tgnewtable
Definition: reltrigger.h:43
int16 tgnattr
Definition: reltrigger.h:38
int i
int16 tgnargs
Definition: reltrigger.h:37
char * tgoldtable
Definition: reltrigger.h:42
Oid get_trigger_oid ( Oid  relid,
const char *  name,
bool  missing_ok 
)

Definition at line 1353 of file trigger.c.

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

Referenced by get_object_address_relobject().

1354 {
1355  Relation tgrel;
1356  ScanKeyData skey[2];
1357  SysScanDesc tgscan;
1358  HeapTuple tup;
1359  Oid oid;
1360 
1361  /*
1362  * Find the trigger, verify permissions, set up object address
1363  */
1365 
1366  ScanKeyInit(&skey[0],
1368  BTEqualStrategyNumber, F_OIDEQ,
1369  ObjectIdGetDatum(relid));
1370  ScanKeyInit(&skey[1],
1372  BTEqualStrategyNumber, F_NAMEEQ,
1373  CStringGetDatum(trigname));
1374 
1375  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1376  NULL, 2, skey);
1377 
1378  tup = systable_getnext(tgscan);
1379 
1380  if (!HeapTupleIsValid(tup))
1381  {
1382  if (!missing_ok)
1383  ereport(ERROR,
1384  (errcode(ERRCODE_UNDEFINED_OBJECT),
1385  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1386  trigname, get_rel_name(relid))));
1387  oid = InvalidOid;
1388  }
1389  else
1390  {
1391  oid = HeapTupleGetOid(tup);
1392  }
1393 
1394  systable_endscan(tgscan);
1395  heap_close(tgrel, AccessShareLock);
1396  return oid;
1397 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define TriggerRelidNameIndexId
Definition: indexing.h:249
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_trigger_tgrelid
Definition: pg_trigger.h:79
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_trigger_tgname
Definition: pg_trigger.h:80
#define TriggerRelationId
Definition: pg_trigger.h:34
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define BTEqualStrategyNumber
Definition: stratnum.h:31
TransitionCaptureState* MakeTransitionCaptureState ( TriggerDesc trigdesc,
Oid  relid,
CmdType  cmdType 
)

Definition at line 4411 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(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, 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().

4412 {
4414  bool need_old,
4415  need_new;
4416  AfterTriggersTableData *table;
4417  MemoryContext oldcxt;
4418  ResourceOwner saveResourceOwner;
4419 
4420  if (trigdesc == NULL)
4421  return NULL;
4422 
4423  /* Detect which table(s) we need. */
4424  switch (cmdType)
4425  {
4426  case CMD_INSERT:
4427  need_old = false;
4428  need_new = trigdesc->trig_insert_new_table;
4429  break;
4430  case CMD_UPDATE:
4431  need_old = trigdesc->trig_update_old_table;
4432  need_new = trigdesc->trig_update_new_table;
4433  break;
4434  case CMD_DELETE:
4435  need_old = trigdesc->trig_delete_old_table;
4436  need_new = false;
4437  break;
4438  default:
4439  elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
4440  need_old = need_new = false; /* keep compiler quiet */
4441  break;
4442  }
4443  if (!need_old && !need_new)
4444  return NULL;
4445 
4446  /* Check state, like AfterTriggerSaveEvent. */
4447  if (afterTriggers.query_depth < 0)
4448  elog(ERROR, "MakeTransitionCaptureState() called outside of query");
4449 
4450  /* Be sure we have enough space to record events at this query depth. */
4453 
4454  /*
4455  * Find or create an AfterTriggersTableData struct to hold the
4456  * tuplestore(s). If there's a matching struct but it's marked closed,
4457  * ignore it; we need a newer one.
4458  *
4459  * Note: the AfterTriggersTableData list, as well as the tuplestores, are
4460  * allocated in the current (sub)transaction's CurTransactionContext, and
4461  * the tuplestores are managed by the (sub)transaction's resource owner.
4462  * This is sufficient lifespan because we do not allow triggers using
4463  * transition tables to be deferrable; they will be fired during
4464  * AfterTriggerEndQuery, after which it's okay to delete the data.
4465  */
4466  table = GetAfterTriggersTableData(relid, cmdType);
4467 
4468  /* Now create required tuplestore(s), if we don't have them already. */
4470  saveResourceOwner = CurrentResourceOwner;
4471  PG_TRY();
4472  {
4474  if (need_old && table->old_tuplestore == NULL)
4475  table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4476  if (need_new && table->new_tuplestore == NULL)
4477  table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
4478  }
4479  PG_CATCH();
4480  {
4481  CurrentResourceOwner = saveResourceOwner;
4482  PG_RE_THROW();
4483  }
4484  PG_END_TRY();
4485  CurrentResourceOwner = saveResourceOwner;
4486  MemoryContextSwitchTo(oldcxt);
4487 
4488  /* Now build the TransitionCaptureState struct, in caller's context */
4490  state->tcs_delete_old_table = trigdesc->trig_delete_old_table;
4491  state->tcs_update_old_table = trigdesc->trig_update_old_table;
4492  state->tcs_update_new_table = trigdesc->trig_update_new_table;
4493  state->tcs_insert_new_table = trigdesc->trig_insert_new_table;
4494  state->tcs_private = table;
4495 
4496  return state;
4497 }
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:139
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext CurTransactionContext
Definition: mcxt.c:49
Tuplestorestate * old_tuplestore
Definition: trigger.c:3598
bool trig_update_new_table
Definition: reltrigger.h:76
bool trig_insert_new_table
Definition: reltrigger.h:74
struct AfterTriggersTableData * tcs_private
Definition: trigger.h:87
#define ERROR
Definition: elog.h:43
static AfterTriggersTableData * GetAfterTriggersTableData(Oid relid, CmdType cmdType)
Definition: trigger.c:4353
bool trig_update_old_table
Definition: reltrigger.h:75
Tuplestorestate * new_tuplestore
Definition: trigger.c:3599
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
void * palloc0(Size size)
Definition: mcxt.c:877
int work_mem
Definition: globals.c:113
static void AfterTriggerEnlargeQueryState(void)
Definition: trigger.c:4958
#define PG_CATCH()
Definition: elog.h:293
Definition: regguts.h:298
#define PG_RE_THROW()
Definition: elog.h:314
bool trig_delete_old_table
Definition: reltrigger.h:77
#define elog
Definition: elog.h:219
#define PG_TRY()
Definition: elog.h:284
static AfterTriggersData afterTriggers
Definition: trigger.c:3602
#define PG_END_TRY()
Definition: elog.h:300
void RelationBuildTriggers ( Relation  relation)

Definition at line 1683 of file trigger.c.

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

1684 {
1685  TriggerDesc *trigdesc;
1686  int numtrigs;
1687  int maxtrigs;
1688  Trigger *triggers;
1689  Relation tgrel;
1690  ScanKeyData skey;
1691  SysScanDesc tgscan;
1692  HeapTuple htup;
1693  MemoryContext oldContext;
1694  int