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)
 
void DestroyTransitionCaptureState (TransitionCaptureState *tcs)
 
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 112 of file trigger.h.

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

#define AFTER_TRIGGER_INITDEFERRED   0x00000040

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

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

#define SESSION_REPLICATION_ROLE_LOCAL   2

Definition at line 147 of file trigger.h.

#define SESSION_REPLICATION_ROLE_ORIGIN   0

Definition at line 145 of file trigger.h.

#define SESSION_REPLICATION_ROLE_REPLICA   1

Definition at line 146 of file trigger.h.

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

#define TRIGGER_DISABLED   'D'

Definition at line 157 of file trigger.h.

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

#define TRIGGER_EVENT_AFTER   0x00000000

Definition at line 106 of file trigger.h.

#define TRIGGER_EVENT_DELETE   0x00000001
#define TRIGGER_EVENT_INSTEAD   0x00000010

Definition at line 107 of file trigger.h.

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

#define TRIGGER_EVENT_OPMASK   0x00000003

Definition at line 101 of file trigger.h.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define TRIGGER_EVENT_TIMINGMASK   0x00000018

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

Referenced by ATExecCmd().

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

Definition at line 156 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 4343 of file trigger.c.

References AfterTriggersData::query_depth.

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

4344 {
4345  /* Increase the query stack depth */
4347 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerBeginSubXact ( void  )

Definition at line 4551 of file trigger.c.

References DEFTRIG_INITALLOC, AfterTriggersData::depth_stack, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::firing_counter, AfterTriggersData::firing_stack, GetCurrentTransactionNestLevel(), AfterTriggersData::maxtransdepth, MemoryContextSwitchTo(), NULL, palloc(), AfterTriggersData::query_depth, repalloc(), AfterTriggersData::state_stack, and TopTransactionContext.

Referenced by StartSubTransaction().

4552 {
4553  int my_level = GetCurrentTransactionNestLevel();
4554 
4555  /*
4556  * Allocate more space in the stacks if needed. (Note: because the
4557  * minimum nest level of a subtransaction is 2, we waste the first couple
4558  * entries of each array; not worth the notational effort to avoid it.)
4559  */
4560  while (my_level >= afterTriggers.maxtransdepth)
4561  {
4562  if (afterTriggers.maxtransdepth == 0)
4563  {
4564  MemoryContext old_cxt;
4565 
4567 
4568 #define DEFTRIG_INITALLOC 8
4573  afterTriggers.depth_stack = (int *)
4574  palloc(DEFTRIG_INITALLOC * sizeof(int));
4576  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4578 
4579  MemoryContextSwitchTo(old_cxt);
4580  }
4581  else
4582  {
4583  /* repalloc will keep the stacks in the same context */
4584  int new_alloc = afterTriggers.maxtransdepth * 2;
4585 
4588  new_alloc * sizeof(SetConstraintState));
4591  new_alloc * sizeof(AfterTriggerEventList));
4592  afterTriggers.depth_stack = (int *)
4594  new_alloc * sizeof(int));
4597  new_alloc * sizeof(CommandId));
4598  afterTriggers.maxtransdepth = new_alloc;
4599  }
4600  }
4601 
4602  /*
4603  * Push the current information into the stack. The SET CONSTRAINTS state
4604  * is not saved until/unless changed. Likewise, we don't make a
4605  * per-subtransaction event context until needed.
4606  */
4607  afterTriggers.state_stack[my_level] = NULL;
4611 }
uint32 CommandId
Definition: c.h:411
MemoryContext TopTransactionContext
Definition: mcxt.c:48
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define DEFTRIG_INITALLOC
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
CommandId firing_counter
Definition: trigger.c:3567
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
#define NULL
Definition: c.h:229
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
void * palloc(Size size)
Definition: mcxt.c:849
AfterTriggerEventList events
Definition: trigger.c:3569
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerBeginXact ( void  )

Definition at line 4307 of file trigger.c.

References Assert, AfterTriggersData::depth_stack, AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::firing_stack, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, and AfterTriggersData::state_stack.

Referenced by StartTransaction().

4308 {
4309  /*
4310  * Initialize after-trigger state structure to empty
4311  */
4312  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4314 
4315  /*
4316  * Verify that there is no leftover state remaining. If these assertions
4317  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4318  * up properly.
4319  */
4331 }
uint32 CommandId
Definition: c.h:411
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
CommandId firing_counter
Definition: trigger.c:3567
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3492
MemoryContext event_cxt
Definition: trigger.c:3575
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndQuery ( EState estate)

Definition at line 4363 of file trigger.c.

References afterTriggerFreeEventList(), afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::maxquerydepth, NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, and tuplestore_end().

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

4364 {
4365  AfterTriggerEventList *events;
4366  Tuplestorestate *fdw_tuplestore;
4367 
4368  /* Must be inside a query, too */
4370 
4371  /*
4372  * If we never even got as far as initializing the event stack, there
4373  * certainly won't be any events, so exit quickly.
4374  */
4376  {
4378  return;
4379  }
4380 
4381  /*
4382  * Process all immediate-mode triggers queued by the query, and move the
4383  * deferred ones to the main list of deferred events.
4384  *
4385  * Notice that we decide which ones will be fired, and put the deferred
4386  * ones on the main list, before anything is actually fired. This ensures
4387  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4388  * IMMEDIATE: all events we have decided to defer will be available for it
4389  * to fire.
4390  *
4391  * We loop in case a trigger queues more events at the same query level.
4392  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4393  * will instead fire any triggers in a dedicated query level. Foreign key
4394  * enforcement triggers do add to the current query level, thanks to their
4395  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4396  * C-language triggers might do likewise. Be careful here: firing a
4397  * trigger could result in query_stack being repalloc'd, so we can't save
4398  * its address across afterTriggerInvokeEvents calls.
4399  *
4400  * If we find no firable events, we don't have to increment
4401  * firing_counter.
4402  */
4403  for (;;)
4404  {
4406  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4407  {
4408  CommandId firing_id = afterTriggers.firing_counter++;
4409 
4410  /* OK to delete the immediate events after processing them */
4411  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4412  break; /* all fired */
4413  }
4414  else
4415  break;
4416  }
4417 
4418  /* Release query-local storage for events, including tuplestore if any */
4420  if (fdw_tuplestore)
4421  {
4422  tuplestore_end(fdw_tuplestore);
4424  }
4426 
4428 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3812
CommandId firing_counter
Definition: trigger.c:3567
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4098
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndSubXact ( bool  isCommit)

Definition at line 4619 of file trigger.c.

References AFTER_TRIGGER_DONE, AFTER_TRIGGER_IN_PROGRESS, afterTriggerFreeEventList(), afterTriggerRestoreEventList(), Assert, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_firing_id, AfterTriggersData::depth_stack, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_stack, for_each_event_chunk, GetCurrentTransactionNestLevel(), GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, NULL, pfree(), AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, and tuplestore_end().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

4620 {
4621  int my_level = GetCurrentTransactionNestLevel();
4623  AfterTriggerEvent event;
4624  AfterTriggerEventChunk *chunk;
4625  CommandId subxact_firing_id;
4626 
4627  /*
4628  * Pop the prior state if needed.
4629  */
4630  if (isCommit)
4631  {
4632  Assert(my_level < afterTriggers.maxtransdepth);
4633  /* If we saved a prior state, we don't need it anymore */
4634  state = afterTriggers.state_stack[my_level];
4635  if (state != NULL)
4636  pfree(state);
4637  /* this avoids double pfree if error later: */
4638  afterTriggers.state_stack[my_level] = NULL;
4640  afterTriggers.depth_stack[my_level]);
4641  }
4642  else
4643  {
4644  /*
4645  * Aborting. It is possible subxact start failed before calling
4646  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4647  * stack levels that aren't there.
4648  */
4649  if (my_level >= afterTriggers.maxtransdepth)
4650  return;
4651 
4652  /*
4653  * Release any event lists from queries being aborted, and restore
4654  * query_depth to its pre-subxact value. This assumes that a
4655  * subtransaction will not add events to query levels started in a
4656  * earlier transaction state.
4657  */
4659  {
4661  {
4662  Tuplestorestate *ts;
4663 
4665  if (ts)
4666  {
4667  tuplestore_end(ts);
4669  }
4670 
4672  }
4673 
4675  }
4677  afterTriggers.depth_stack[my_level]);
4678 
4679  /*
4680  * Restore the global deferred-event list to its former length,
4681  * discarding any events queued by the subxact.
4682  */
4684  &afterTriggers.events_stack[my_level]);
4685 
4686  /*
4687  * Restore the trigger state. If the saved state is NULL, then this
4688  * subxact didn't save it, so it doesn't need restoring.
4689  */
4690  state = afterTriggers.state_stack[my_level];
4691  if (state != NULL)
4692  {
4694  afterTriggers.state = state;
4695  }
4696  /* this avoids double pfree if error later: */
4697  afterTriggers.state_stack[my_level] = NULL;
4698 
4699  /*
4700  * Scan for any remaining deferred events that were marked DONE or IN
4701  * PROGRESS by this subxact or a child, and un-mark them. We can
4702  * recognize such events because they have a firing ID greater than or
4703  * equal to the firing_counter value we saved at subtransaction start.
4704  * (This essentially assumes that the current subxact includes all
4705  * subxacts started after it.)
4706  */
4707  subxact_firing_id = afterTriggers.firing_stack[my_level];
4709  {
4710  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4711 
4712  if (event->ate_flags &
4714  {
4715  if (evtshared->ats_firing_id >= subxact_firing_id)
4716  event->ate_flags &=
4718  }
4719  }
4720  }
4721 }
uint32 CommandId
Definition: c.h:411
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3505
CommandId * firing_stack
Definition: trigger.c:3582
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3812
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Definition: regguts.h:298
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
Definition: trigger.c:3835
CommandId ats_firing_id
Definition: trigger.c:3435
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3420
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerEndXact ( bool  isCommit)

Definition at line 4499 of file trigger.c.

References AfterTriggersData::depth_stack, AfterTriggersData::event_cxt, AfterTriggersData::events, AfterTriggersData::events_stack, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_stack, AfterTriggerEventList::head, AfterTriggersData::maxquerydepth, AfterTriggersData::maxtransdepth, MemoryContextDelete(), NULL, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

4500 {
4501  /*
4502  * Forget the pending-events list.
4503  *
4504  * Since all the info is in TopTransactionContext or children thereof, we
4505  * don't really need to do anything to reclaim memory. However, the
4506  * pending-events list could be large, and so it's useful to discard it as
4507  * soon as possible --- especially if we are aborting because we ran out
4508  * of memory for the list!
4509  */
4511  {
4517  }
4518 
4519  /*
4520  * Forget any subtransaction state as well. Since this can't be very
4521  * large, we let the eventual reset of TopTransactionContext free the
4522  * memory instead of doing it here.
4523  */
4529 
4530 
4531  /*
4532  * Forget the query stack and constraint-related state information. As
4533  * with the subtransaction state information, we don't bother freeing the
4534  * memory here.
4535  */
4540 
4541  /* No more afterTriggers manipulation until next transaction starts. */
4543 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3493
CommandId * firing_stack
Definition: trigger.c:3582
SetConstraintState * state_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
AfterTriggerEventList * events_stack
Definition: trigger.c:3580
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3492
MemoryContext event_cxt
Definition: trigger.c:3575
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3572
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerFireDeferred ( void  )

Definition at line 4443 of file trigger.c.

References afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::firing_counter, GetTransactionSnapshot(), AfterTriggerEventList::head, NULL, PopActiveSnapshot(), PushActiveSnapshot(), and AfterTriggersData::query_depth.

Referenced by CommitTransaction(), and PrepareTransaction().

4444 {
4445  AfterTriggerEventList *events;
4446  bool snap_pushed = false;
4447 
4448  /* Must not be inside a query */
4450 
4451  /*
4452  * If there are any triggers to fire, make sure we have set a snapshot for
4453  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4454  * can't assume ActiveSnapshot is valid on entry.)
4455  */
4456  events = &afterTriggers.events;
4457  if (events->head != NULL)
4458  {
4460  snap_pushed = true;
4461  }
4462 
4463  /*
4464  * Run all the remaining triggers. Loop until they are all gone, in case
4465  * some trigger queues more for us to do.
4466  */
4467  while (afterTriggerMarkEvents(events, NULL, false))
4468  {
4469  CommandId firing_id = afterTriggers.firing_counter++;
4470 
4471  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4472  break; /* all fired */
4473  }
4474 
4475  /*
4476  * We don't bother freeing the event list, since it will go away anyway
4477  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4478  */
4479 
4480  if (snap_pushed)
4482 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
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:3567
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3492
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:4098
AfterTriggerEventList events
Definition: trigger.c:3569
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
bool AfterTriggerPendingOnRel ( Oid  relid)

Definition at line 5157 of file trigger.c.

References AFTER_TRIGGER_DONE, AfterTriggerEventData::ate_flags, AfterTriggerSharedData::ats_relid, AfterTriggersData::events, for_each_event_chunk, GetTriggerSharedData, AfterTriggersData::maxquerydepth, AfterTriggersData::query_depth, and AfterTriggersData::query_stack.

Referenced by CheckTableNotInUse().

5158 {
5159  AfterTriggerEvent event;
5160  AfterTriggerEventChunk *chunk;
5161  int depth;
5162 
5163  /* Scan queued events */
5165  {
5166  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5167 
5168  /*
5169  * We can ignore completed events. (Even if a DONE flag is rolled
5170  * back by subxact abort, it's OK because the effects of the TRUNCATE
5171  * or whatever must get rolled back too.)
5172  */
5173  if (event->ate_flags & AFTER_TRIGGER_DONE)
5174  continue;
5175 
5176  if (evtshared->ats_relid == relid)
5177  return true;
5178  }
5179 
5180  /*
5181  * Also scan events queued by incomplete queries. This could only matter
5182  * if TRUNCATE/etc is executed by a function or trigger within an updating
5183  * query on the same relation, which is pretty perverse, but let's check.
5184  */
5185  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5186  {
5187  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
5188  {
5189  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5190 
5191  if (event->ate_flags & AFTER_TRIGGER_DONE)
5192  continue;
5193 
5194  if (evtshared->ats_relid == relid)
5195  return true;
5196  }
5197  }
5198 
5199  return false;
5200 }
TriggerFlags ate_flags
Definition: trigger.c:3443
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3419
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3505
#define GetTriggerSharedData(evt)
Definition: trigger.c:3468
AfterTriggerEventList events
Definition: trigger.c:3569
AfterTriggerEventList * query_stack
Definition: trigger.c:3571
static AfterTriggersData afterTriggers
Definition: trigger.c:3586
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

Definition at line 4863 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, NULL, SetConstraintStateData::numstates, ObjectIdGetDatum, PopActiveSnapshot(), PushActiveSnapshot(), RangeVar::relname, ScanKeyInit(), RangeVar::schemaname, SetConstraintTriggerData::sct_tgisdeferred, SetConstraintTriggerData::sct_tgoid, SetConstraintStateAddItem(), SetConstraintStateCopy(), SetConstraintStateCreate(), AfterTriggersData::state, AfterTriggersData::state_stack, systable_beginscan(), systable_endscan(), systable_getnext(), TriggerConstraintIndexId, TriggerRelationId, and SetConstraintStateData::trigstates.

Referenced by standard_ProcessUtility().

4864 {
4865  int my_level = GetCurrentTransactionNestLevel();
4866 
4867  /* If we haven't already done so, initialize our state. */
4868  if (afterTriggers.state == NULL)
4870 
4871  /*
4872  * If in a subtransaction, and we didn't save the current state already,
4873  * save it so it can be restored if the subtransaction aborts.
4874  */
4875  if (my_level > 1 &&
4876  afterTriggers.state_stack[my_level] == NULL)
4877  {
4878  afterTriggers.state_stack[my_level] =
4880  }
4881 
4882  /*
4883  * Handle SET CONSTRAINTS ALL ...
4884  */
4885  if (stmt->constraints == NIL)
4886  {
4887  /*
4888  * Forget any previous SET CONSTRAINTS commands in this transaction.
4889  */
4891 
4892  /*
4893  * Set the per-transaction ALL state to known.
4894  */
4895  afterTriggers.state->all_isset = true;
4897  }
4898  else
4899  {
4900  Relation conrel;
4901  Relation tgrel;
4902  List *conoidlist = NIL;
4903  List *tgoidlist = NIL;
4904  ListCell *lc;
4905 
4906  /*
4907  * Handle SET CONSTRAINTS constraint-name [, ...]
4908  *
4909  * First, identify all the named constraints and make a list of their
4910  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4911  * the same name within a schema, the specifications are not
4912  * necessarily unique. Our strategy is to target all matching
4913  * constraints within the first search-path schema that has any
4914  * matches, but disregard matches in schemas beyond the first match.
4915  * (This is a bit odd but it's the historical behavior.)
4916  */
4918 
4919  foreach(lc, stmt->constraints)
4920  {
4921  RangeVar *constraint = lfirst(lc);
4922  bool found;
4923  List *namespacelist;
4924  ListCell *nslc;
4925 
4926  if (constraint->catalogname)
4927  {
4928  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4929  ereport(ERROR,
4930  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4931  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4932  constraint->catalogname, constraint->schemaname,
4933  constraint->relname)));
4934  }
4935 
4936  /*
4937  * If we're given the schema name with the constraint, look only
4938  * in that schema. If given a bare constraint name, use the
4939  * search path to find the first matching constraint.
4940  */
4941  if (constraint->schemaname)
4942  {
4943  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4944  false);
4945 
4946  namespacelist = list_make1_oid(namespaceId);
4947  }
4948  else
4949  {
4950  namespacelist = fetch_search_path(true);
4951  }
4952 
4953  found = false;
4954  foreach(nslc, namespacelist)
4955  {
4956  Oid namespaceId = lfirst_oid(nslc);
4957  SysScanDesc conscan;
4958  ScanKeyData skey[2];
4959  HeapTuple tup;
4960 
4961  ScanKeyInit(&skey[0],
4963  BTEqualStrategyNumber, F_NAMEEQ,
4964  CStringGetDatum(constraint->relname));
4965  ScanKeyInit(&skey[1],
4967  BTEqualStrategyNumber, F_OIDEQ,
4968  ObjectIdGetDatum(namespaceId));
4969 
4970  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4971  true, NULL, 2, skey);
4972 
4973  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4974  {
4976 
4977  if (con->condeferrable)
4978  conoidlist = lappend_oid(conoidlist,
4979  HeapTupleGetOid(tup));
4980  else if (stmt->deferred)
4981  ereport(ERROR,
4982  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4983  errmsg("constraint \"%s\" is not deferrable",
4984  constraint->relname)));
4985  found = true;
4986  }
4987 
4988  systable_endscan(conscan);
4989 
4990  /*
4991  * Once we've found a matching constraint we do not search
4992  * later parts of the search path.
4993  */
4994  if (found)
4995  break;
4996  }
4997 
4998  list_free(namespacelist);
4999 
5000  /*
5001  * Not found ?
5002  */
5003  if (!found)
5004  ereport(ERROR,
5005  (errcode(ERRCODE_UNDEFINED_OBJECT),
5006  errmsg("constraint \"%s\" does not exist",
5007  constraint->relname)));
5008  }
5009 
5010  heap_close(conrel, AccessShareLock);
5011 
5012  /*
5013  * Now, locate the trigger(s) implementing each of these constraints,
5014  * and make a list of their OIDs.
5015  */
5017 
5018  foreach(lc, conoidlist)
5019  {
5020  Oid conoid = lfirst_oid(lc);
5021  bool found;
5022  ScanKeyData skey;
5023  SysScanDesc tgscan;
5024  HeapTuple htup;
5025 
5026  found = false;
5027 
5028  ScanKeyInit(&skey,
5030  BTEqualStrategyNumber, F_OIDEQ,
5031  ObjectIdGetDatum(conoid));
5032 
5033  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
5034  NULL, 1, &skey);
5035 
5036  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
5037  {
5038  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
5039 
5040  /*
5041  * Silently skip triggers that are marked as non-deferrable in
5042  * pg_trigger. This is not an error condition, since a
5043  * deferrable RI constraint may have some non-deferrable
5044  * actions.
5045  */
5046  if (pg_trigger->tgdeferrable)
5047  tgoidlist = lappend_oid(tgoidlist,
5048  HeapTupleGetOid(htup));
5049 
5050  found = true;
5051  }
5052 
5053  systable_endscan(tgscan);
5054 
5055  /* Safety check: a deferrable constraint should have triggers */
5056  if (!found)
5057  elog(ERROR, "no triggers found for constraint with OID %u",
5058  conoid);
5059  }
5060 
5061  heap_close(tgrel, AccessShareLock);
5062 
5063  /*
5064  * Now we can set the trigger states of individual triggers for this
5065  * xact.
5066  */
5067  foreach(lc, tgoidlist)
5068  {
5069  Oid tgoid = lfirst_oid(lc);
5071  bool found = false;
5072  int i;
5073 
5074  for (i = 0; i < state->numstates; i++)
5075  {
5076  if (state->trigstates[i].sct_tgoid == tgoid)
5077  {
5078  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5079  found = true;
5080  break;
5081  }
5082  }
5083  if (!found)
5084  {
5086  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
5087  }
5088  }
5089  }
5090 
5091  /*
5092  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
5093  * checks against that constraint must be made when the SET CONSTRAINTS
5094  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
5095  * apply retroactively. We've updated the constraints state, so scan the
5096  * list of previously deferred events to fire any that have now become
5097  * immediate.
5098  *
5099  * Obviously, if this was SET ... DEFERRED then it can't have converted
5100  * any unfired events to immediate, so we need do nothing in that case.
5101  */
5102  if (!stmt->deferred)
5103  {
5105  bool snapshot_set = false;
5106 
5107  while (afterTriggerMarkEvents(events, NULL, true))
5108  {
5109  CommandId firing_id = afterTriggers.firing_counter++;
5110 
5111  /*
5112  * Make sure a snapshot has been established in case trigger
5113  * functions need one. Note that we avoid setting a snapshot if
5114  * we don't find at least one trigger that has to be fired now.
5115  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
5116  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
5117  * at the start of a transaction it's not possible for any trigger
5118  * events to be queued yet.)
5119  */
5120  if (!snapshot_set)
5121  {
5123  snapshot_set = true;
5124  }
5125 
5126  /*
5127  * We can delete fired events if we are at top transaction level,
5128  * but we'd better not if inside a subtransaction, since the
5129  * subtransaction could later get rolled back.
5130  */
5131  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5132  !IsSubTransaction()))
5133  break; /* all fired */
5134  }
5135 
5136  if (snapshot_set)
5138  }
5139 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:411
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2853
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:3380
#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:4833
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:4170
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_stack
Definition: trigger.c:3579
SetConstraintState state
Definition: trigger.c:3568
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:4788
#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:1284
CommandId firing_counter
Definition: trigger.c:3567
#define ConstraintNameNspIndexId
Definition: indexing.h:124
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:761
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#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:4377
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:4098
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3569
#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:3586
char * catalogname
Definition: primnodes.h:66
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
static SetConstraintState SetConstraintStateCopy(SetConstraintState state)
Definition: trigger.c:4813
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1885 of file trigger.c.

References i, NULL, 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().

1886 {
1887  TriggerDesc *newdesc;
1888  Trigger *trigger;
1889  int i;
1890 
1891  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1892  return NULL;
1893 
1894  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1895  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1896 
1897  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1898  memcpy(trigger, trigdesc->triggers,
1899  trigdesc->numtriggers * sizeof(Trigger));
1900  newdesc->triggers = trigger;
1901 
1902  for (i = 0; i < trigdesc->numtriggers; i++)
1903  {
1904  trigger->tgname = pstrdup(trigger->tgname);
1905  if (trigger->tgnattr > 0)
1906  {
1907  int16 *newattr;
1908 
1909  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1910  memcpy(newattr, trigger->tgattr,
1911  trigger->tgnattr * sizeof(int16));
1912  trigger->tgattr = newattr;
1913  }
1914  if (trigger->tgnargs > 0)
1915  {
1916  char **newargs;
1917  int16 j;
1918 
1919  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1920  for (j = 0; j < trigger->tgnargs; j++)
1921  newargs[j] = pstrdup(trigger->tgargs[j]);
1922  trigger->tgargs = newargs;
1923  }
1924  if (trigger->tgqual)
1925  trigger->tgqual = pstrdup(trigger->tgqual);
1926  if (trigger->tgoldtable)
1927  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1928  if (trigger->tgnewtable)
1929  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1930  trigger++;
1931  }
1932 
1933  return newdesc;
1934 }
signed short int16
Definition: c.h:255
char * pstrdup(const char *in)
Definition: mcxt.c:1077
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
#define NULL
Definition: c.h:229
int16 tgnattr
Definition: reltrigger.h:38
void * palloc(Size size)
Definition: mcxt.c:849
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 140 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, NULL, 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().

143 {
144  int16 tgtype;
145  int ncolumns;
146  int16 *columns;
147  int2vector *tgattr;
148  Node *whenClause;
149  List *whenRtable;
150  char *qual;
152  bool nulls[Natts_pg_trigger];
153  Relation rel;
154  AclResult aclresult;
155  Relation tgrel;
156  SysScanDesc tgscan;
157  ScanKeyData key;
158  Relation pgrel;
159  HeapTuple tuple;
160  Oid fargtypes[1]; /* dummy */
161  Oid funcoid;
162  Oid funcrettype;
163  Oid trigoid;
164  char internaltrigname[NAMEDATALEN];
165  char *trigname;
166  Oid constrrelid = InvalidOid;
167  ObjectAddress myself,
168  referenced;
169  char *oldtablename = NULL;
170  char *newtablename = NULL;
171 
172  if (OidIsValid(relOid))
173  rel = heap_open(relOid, ShareRowExclusiveLock);
174  else
176 
177  /*
178  * Triggers must be on tables or views, and there are additional
179  * relation-type-specific restrictions.
180  */
181  if (rel->rd_rel->relkind == RELKIND_RELATION ||
182  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
183  {
184  /* Tables can't have INSTEAD OF triggers */
185  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
186  stmt->timing != TRIGGER_TYPE_AFTER)
187  ereport(ERROR,
188  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
189  errmsg("\"%s\" is a table",
191  errdetail("Tables cannot have INSTEAD OF triggers.")));
192  /* Disallow ROW triggers on partitioned tables */
193  if (stmt->row && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
194  ereport(ERROR,
195  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
196  errmsg("\"%s\" is a partitioned table",
198  errdetail("Partitioned tables cannot have ROW triggers.")));
199  }
200  else if (rel->rd_rel->relkind == RELKIND_VIEW)
201  {
202  /*
203  * Views can have INSTEAD OF triggers (which we check below are
204  * row-level), or statement-level BEFORE/AFTER triggers.
205  */
206  if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
207  ereport(ERROR,
208  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
209  errmsg("\"%s\" is a view",
211  errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
212  /* Disallow TRUNCATE triggers on VIEWs */
213  if (TRIGGER_FOR_TRUNCATE(stmt->events))
214  ereport(ERROR,
215  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
216  errmsg("\"%s\" is a view",
218  errdetail("Views cannot have TRUNCATE triggers.")));
219  }
220  else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
221  {
222  if (stmt->timing != TRIGGER_TYPE_BEFORE &&
223  stmt->timing != TRIGGER_TYPE_AFTER)
224  ereport(ERROR,
225  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
226  errmsg("\"%s\" is a foreign table",
228  errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
229 
230  if (TRIGGER_FOR_TRUNCATE(stmt->events))
231  ereport(ERROR,
232  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
233  errmsg("\"%s\" is a foreign table",
235  errdetail("Foreign tables cannot have TRUNCATE triggers.")));
236 
237  if (stmt->isconstraint)
238  ereport(ERROR,
239  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
240  errmsg("\"%s\" is a foreign table",
242  errdetail("Foreign tables cannot have constraint triggers.")));
243  }
244  else
245  ereport(ERROR,
246  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
247  errmsg("\"%s\" is not a table or view",
248  RelationGetRelationName(rel))));
249 
251  ereport(ERROR,
252  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
253  errmsg("permission denied: \"%s\" is a system catalog",
254  RelationGetRelationName(rel))));
255 
256  if (stmt->isconstraint)
257  {
258  /*
259  * We must take a lock on the target relation to protect against
260  * concurrent drop. It's not clear that AccessShareLock is strong
261  * enough, but we certainly need at least that much... otherwise, we
262  * might end up creating a pg_constraint entry referencing a
263  * nonexistent table.
264  */
265  if (OidIsValid(refRelOid))
266  {
267  LockRelationOid(refRelOid, AccessShareLock);
268  constrrelid = refRelOid;
269  }
270  else if (stmt->constrrel != NULL)
271  constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock,
272  false);
273  }
274 
275  /* permission checks */
276  if (!isInternal)
277  {
278  aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
279  ACL_TRIGGER);
280  if (aclresult != ACLCHECK_OK)
281  aclcheck_error(aclresult, ACL_KIND_CLASS,
283 
284  if (OidIsValid(constrrelid))
285  {
286  aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
287  ACL_TRIGGER);
288  if (aclresult != ACLCHECK_OK)
289  aclcheck_error(aclresult, ACL_KIND_CLASS,
290  get_rel_name(constrrelid));
291  }
292  }
293 
294  /* Compute tgtype */
295  TRIGGER_CLEAR_TYPE(tgtype);
296  if (stmt->row)
297  TRIGGER_SETT_ROW(tgtype);
298  tgtype |= stmt->timing;
299  tgtype |= stmt->events;
300 
301  /* Disallow ROW-level TRUNCATE triggers */
302  if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
303  ereport(ERROR,
304  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305  errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
306 
307  /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
308  if (TRIGGER_FOR_INSTEAD(tgtype))
309  {
310  if (!TRIGGER_FOR_ROW(tgtype))
311  ereport(ERROR,
312  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
313  errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
314  if (stmt->whenClause)
315  ereport(ERROR,
316  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
317  errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
318  if (stmt->columns != NIL)
319  ereport(ERROR,
320  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321  errmsg("INSTEAD OF triggers cannot have column lists")));
322  }
323 
324  /*
325  * We don't yet support naming ROW transition variables, but the parser
326  * recognizes the syntax so we can give a nicer message here.
327  *
328  * Per standard, REFERENCING TABLE names are only allowed on AFTER
329  * triggers. Per standard, REFERENCING ROW names are not allowed with FOR
330  * EACH STATEMENT. Per standard, each OLD/NEW, ROW/TABLE permutation is
331  * only allowed once. Per standard, OLD may not be specified when
332  * creating a trigger only for INSERT, and NEW may not be specified when
333  * creating a trigger only for DELETE.
334  *
335  * Notice that the standard allows an AFTER ... FOR EACH ROW trigger to
336  * reference both ROW and TABLE transition data.
337  */
338  if (stmt->transitionRels != NIL)
339  {
340  List *varList = stmt->transitionRels;
341  ListCell *lc;
342 
343  foreach(lc, varList)
344  {
346 
347  if (!(tt->isTable))
348  ereport(ERROR,
349  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
350  errmsg("ROW variable naming in the REFERENCING clause is not supported"),
351  errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
352 
353  /*
354  * Because of the above test, we omit further ROW-related testing
355  * below. If we later allow naming OLD and NEW ROW variables,
356  * adjustments will be needed below.
357  */
358 
359  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
360  ereport(ERROR,
361  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
362  errmsg("\"%s\" is a foreign table",
364  errdetail("Triggers on foreign tables cannot have transition tables.")));
365 
366  if (rel->rd_rel->relkind == RELKIND_VIEW)
367  ereport(ERROR,
368  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
369  errmsg("\"%s\" is a view",
371  errdetail("Triggers on views cannot have transition tables.")));
372 
373  /*
374  * We currently don't allow row-level triggers with transition
375  * tables on partition or inheritance children. Such triggers
376  * would somehow need to see tuples converted to the format of the
377  * table they're attached to, and it's not clear which subset of
378  * tuples each child should see. See also the prohibitions in
379  * ATExecAttachPartition() and ATExecAddInherit().
380  */
381  if (TRIGGER_FOR_ROW(tgtype) && has_superclass(rel->rd_id))
382  {
383  /* Use appropriate error message. */
384  if (rel->rd_rel->relispartition)
385  ereport(ERROR,
386  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
387  errmsg("ROW triggers with transition tables are not supported on partitions")));
388  else
389  ereport(ERROR,
390  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
391  errmsg("ROW triggers with transition tables are not supported on inheritance children")));
392  }
393 
394  if (stmt->timing != TRIGGER_TYPE_AFTER)
395  ereport(ERROR,
396  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
397  errmsg("transition table name can only be specified for an AFTER trigger")));
398 
399  if (TRIGGER_FOR_TRUNCATE(tgtype))
400  ereport(ERROR,
401  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
402  errmsg("TRUNCATE triggers with transition tables are not supported")));
403 
404  /*
405  * We currently don't allow multi-event triggers ("INSERT OR
406  * UPDATE") with transition tables, because it's not clear how to
407  * handle INSERT ... ON CONFLICT statements which can fire both
408  * INSERT and UPDATE triggers. We show the inserted tuples to
409  * INSERT triggers and the updated tuples to UPDATE triggers, but
410  * it's not yet clear what INSERT OR UPDATE trigger should see.
411  * This restriction could be lifted if we can decide on the right
412  * semantics in a later release.
413  */
414  if (((TRIGGER_FOR_INSERT(tgtype) ? 1 : 0) +
415  (TRIGGER_FOR_UPDATE(tgtype) ? 1 : 0) +
416  (TRIGGER_FOR_DELETE(tgtype) ? 1 : 0)) != 1)
417  ereport(ERROR,
418  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
419  errmsg("Transition tables cannot be specified for triggers with more than one event")));
420 
421  if (tt->isNew)
422  {
423  if (!(TRIGGER_FOR_INSERT(tgtype) ||
424  TRIGGER_FOR_UPDATE(tgtype)))
425  ereport(ERROR,
426  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
427  errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
428 
429  if (newtablename != NULL)
430  ereport(ERROR,
431  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
432  errmsg("NEW TABLE cannot be specified multiple times")));
433 
434  newtablename = tt->name;
435  }
436  else
437  {
438  if (!(TRIGGER_FOR_DELETE(tgtype) ||
439  TRIGGER_FOR_UPDATE(tgtype)))
440  ereport(ERROR,
441  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
442  errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
443 
444  if (oldtablename != NULL)
445  ereport(ERROR,
446  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
447  errmsg("OLD TABLE cannot be specified multiple times")));
448 
449  oldtablename = tt->name;
450  }
451  }
452 
453  if (newtablename != NULL && oldtablename != NULL &&
454  strcmp(newtablename, oldtablename) == 0)
455  ereport(ERROR,
456  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
457  errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
458  }
459 
460  /*
461  * Parse the WHEN clause, if any
462  */
463  if (stmt->whenClause)
464  {
465  ParseState *pstate;
466  RangeTblEntry *rte;
467  List *varList;
468  ListCell *lc;
469 
470  /* Set up a pstate to parse with */
471  pstate = make_parsestate(NULL);
472  pstate->p_sourcetext = queryString;
473 
474  /*
475  * Set up RTEs for OLD and NEW references.
476  *
477  * 'OLD' must always have varno equal to 1 and 'NEW' equal to 2.
478  */
479  rte = addRangeTableEntryForRelation(pstate, rel,
480  makeAlias("old", NIL),
481  false, false);
482  addRTEtoQuery(pstate, rte, false, true, true);
483  rte = addRangeTableEntryForRelation(pstate, rel,
484  makeAlias("new", NIL),
485  false, false);
486  addRTEtoQuery(pstate, rte, false, true, true);
487 
488  /* Transform expression. Copy to be sure we don't modify original */
489  whenClause = transformWhereClause(pstate,
490  copyObject(stmt->whenClause),
492  "WHEN");
493  /* we have to fix its collations too */
494  assign_expr_collations(pstate, whenClause);
495 
496  /*
497  * Check for disallowed references to OLD/NEW.
498  *
499  * NB: pull_var_clause is okay here only because we don't allow
500  * subselects in WHEN clauses; it would fail to examine the contents
501  * of subselects.
502  */
503  varList = pull_var_clause(whenClause, 0);
504  foreach(lc, varList)
505  {
506  Var *var = (Var *) lfirst(lc);
507 
508  switch (var->varno)
509  {
510  case PRS2_OLD_VARNO:
511  if (!TRIGGER_FOR_ROW(tgtype))
512  ereport(ERROR,
513  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
514  errmsg("statement trigger's WHEN condition cannot reference column values"),
515  parser_errposition(pstate, var->location)));
516  if (TRIGGER_FOR_INSERT(tgtype))
517  ereport(ERROR,
518  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
519  errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
520  parser_errposition(pstate, var->location)));
521  /* system columns are okay here */
522  break;
523  case PRS2_NEW_VARNO:
524  if (!TRIGGER_FOR_ROW(tgtype))
525  ereport(ERROR,
526  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
527  errmsg("statement trigger's WHEN condition cannot reference column values"),
528  parser_errposition(pstate, var->location)));
529  if (TRIGGER_FOR_DELETE(tgtype))
530  ereport(ERROR,
531  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
532  errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
533  parser_errposition(pstate, var->location)));
534  if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
535  ereport(ERROR,
536  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
537  errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
538  parser_errposition(pstate, var->location)));
539  break;
540  default:
541  /* can't happen without add_missing_from, so just elog */
542  elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
543  break;
544  }
545  }
546 
547  /* we'll need the rtable for recordDependencyOnExpr */
548  whenRtable = pstate->p_rtable;
549 
550  qual = nodeToString(whenClause);
551 
552  free_parsestate(pstate);
553  }
554  else
555  {
556  whenClause = NULL;
557  whenRtable = NIL;
558  qual = NULL;
559  }
560 
561  /*
562  * Find and validate the trigger function.
563  */
564  funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
565  if (!isInternal)
566  {
567  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
568  if (aclresult != ACLCHECK_OK)
569  aclcheck_error(aclresult, ACL_KIND_PROC,
570  NameListToString(stmt->funcname));
571  }
572  funcrettype = get_func_rettype(funcoid);
573  if (funcrettype != TRIGGEROID)
574  {
575  /*
576  * We allow OPAQUE just so we can load old dump files. When we see a
577  * trigger function declared OPAQUE, change it to TRIGGER.
578  */
579  if (funcrettype == OPAQUEOID)
580  {
582  (errmsg("changing return type of function %s from %s to %s",
583  NameListToString(stmt->funcname),
584  "opaque", "trigger")));
586  }
587  else
588  ereport(ERROR,
589  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
590  errmsg("function %s must return type %s",
591  NameListToString(stmt->funcname), "trigger")));
592  }
593 
594  /*
595  * If the command is a user-entered CREATE CONSTRAINT TRIGGER command that
596  * references one of the built-in RI_FKey trigger functions, assume it is
597  * from a dump of a pre-7.3 foreign key constraint, and take steps to
598  * convert this legacy representation into a regular foreign key
599  * constraint. Ugly, but necessary for loading old dump files.
600  */
601  if (stmt->isconstraint && !isInternal &&
602  list_length(stmt->args) >= 6 &&
603  (list_length(stmt->args) % 2) == 0 &&
605  {
606  /* Keep lock on target rel until end of xact */
607  heap_close(rel, NoLock);
608 
609  ConvertTriggerToFK(stmt, funcoid);
610 
611  return InvalidObjectAddress;
612  }
613 
614  /*
615  * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a
616  * corresponding pg_constraint entry.
617  */
618  if (stmt->isconstraint && !OidIsValid(constraintOid))
619  {
620  /* Internal callers should have made their own constraints */
621  Assert(!isInternal);
622  constraintOid = CreateConstraintEntry(stmt->trigname,
625  stmt->deferrable,
626  stmt->initdeferred,
627  true,
628  RelationGetRelid(rel),
629  NULL, /* no conkey */
630  0,
631  InvalidOid, /* no domain */
632  InvalidOid, /* no index */
633  InvalidOid, /* no foreign key */
634  NULL,
635  NULL,
636  NULL,
637  NULL,
638  0,
639  ' ',
640  ' ',
641  ' ',
642  NULL, /* no exclusion */
643  NULL, /* no check constraint */
644  NULL,
645  NULL,
646  true, /* islocal */
647  0, /* inhcount */
648  true, /* isnoinherit */
649  isInternal); /* is_internal */
650  }
651 
652  /*
653  * Generate the trigger's OID now, so that we can use it in the name if
654  * needed.
655  */
657 
658  trigoid = GetNewOid(tgrel);
659 
660  /*
661  * If trigger is internally generated, modify the provided trigger name to
662  * ensure uniqueness by appending the trigger OID. (Callers will usually
663  * supply a simple constant trigger name in these cases.)
664  */
665  if (isInternal)
666  {
667  snprintf(internaltrigname, sizeof(internaltrigname),
668  "%s_%u", stmt->trigname, trigoid);
669  trigname = internaltrigname;
670  }
671  else
672  {
673  /* user-defined trigger; use the specified trigger name as-is */
674  trigname = stmt->trigname;
675  }
676 
677  /*
678  * Scan pg_trigger for existing triggers on relation. We do this only to
679  * give a nice error message if there's already a trigger of the same
680  * name. (The unique index on tgrelid/tgname would complain anyway.) We
681  * can skip this for internally generated triggers, since the name
682  * modification above should be sufficient.
683  *
684  * NOTE that this is cool only because we have ShareRowExclusiveLock on
685  * the relation, so the trigger set won't be changing underneath us.
686  */
687  if (!isInternal)
688  {
689  ScanKeyInit(&key,
691  BTEqualStrategyNumber, F_OIDEQ,
693  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
694  NULL, 1, &key);
695  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
696  {
697  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
698 
699  if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
700  ereport(ERROR,
702  errmsg("trigger \"%s\" for relation \"%s\" already exists",
703  trigname, RelationGetRelationName(rel))));
704  }
705  systable_endscan(tgscan);
706  }
707 
708  /*
709  * Build the new pg_trigger tuple.
710  */
711  memset(nulls, false, sizeof(nulls));
712 
715  CStringGetDatum(trigname));
716  values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
717  values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
719  values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
720  values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
721  values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
722  values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
725 
726  if (stmt->args)
727  {
728  ListCell *le;
729  char *args;
730  int16 nargs = list_length(stmt->args);
731  int len = 0;
732 
733  foreach(le, stmt->args)
734  {
735  char *ar = strVal(lfirst(le));
736 
737  len += strlen(ar) + 4;
738  for (; *ar; ar++)
739  {
740  if (*ar == '\\')
741  len++;
742  }
743  }
744  args = (char *) palloc(len + 1);
745  args[0] = '\0';
746  foreach(le, stmt->args)
747  {
748  char *s = strVal(lfirst(le));
749  char *d = args + strlen(args);
750 
751  while (*s)
752  {
753  if (*s == '\\')
754  *d++ = '\\';
755  *d++ = *s++;
756  }
757  strcpy(d, "\\000");
758  }
759  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
761  CStringGetDatum(args));
762  }
763  else
764  {
765  values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
767  CStringGetDatum(""));
768  }
769 
770  /* build column number array if it's a column-specific trigger */
771  ncolumns = list_length(stmt->columns);
772  if (ncolumns == 0)
773  columns = NULL;
774  else
775  {
776  ListCell *cell;
777  int i = 0;
778 
779  columns = (int16 *) palloc(ncolumns * sizeof(int16));
780  foreach(cell, stmt->columns)
781  {
782  char *name = strVal(lfirst(cell));
783  int16 attnum;
784  int j;
785 
786  /* Lookup column name. System columns are not allowed */
787  attnum = attnameAttNum(rel, name, false);
788  if (attnum == InvalidAttrNumber)
789  ereport(ERROR,
790  (errcode(ERRCODE_UNDEFINED_COLUMN),
791  errmsg("column \"%s\" of relation \"%s\" does not exist",
792  name, RelationGetRelationName(rel))));
793 
794  /* Check for duplicates */
795  for (j = i - 1; j >= 0; j--)
796  {
797  if (columns[j] == attnum)
798  ereport(ERROR,
799  (errcode(ERRCODE_DUPLICATE_COLUMN),
800  errmsg("column \"%s\" specified more than once",
801  name)));
802  }
803 
804  columns[i++] = attnum;
805  }
806  }
807  tgattr = buildint2vector(columns, ncolumns);
808  values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
809 
810  /* set tgqual if trigger has WHEN clause */
811  if (qual)
812  values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
813  else
814  nulls[Anum_pg_trigger_tgqual - 1] = true;
815 
816  if (oldtablename)
818  CStringGetDatum(oldtablename));
819  else
820  nulls[Anum_pg_trigger_tgoldtable - 1] = true;
821  if (newtablename)
823  CStringGetDatum(newtablename));
824  else
825  nulls[Anum_pg_trigger_tgnewtable - 1] = true;
826 
827  tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
828 
829  /* force tuple to have the desired OID */
830  HeapTupleSetOid(tuple, trigoid);
831 
832  /*
833  * Insert tuple into pg_trigger.
834  */
835  CatalogTupleInsert(tgrel, tuple);
836 
837  heap_freetuple(tuple);
839 
843  if (oldtablename)
845  if (newtablename)
847 
848  /*
849  * Update relation's pg_class entry. Crucial side-effect: other backends
850  * (and this one too!) are sent SI message to make them rebuild relcache
851  * entries.
852  */
854  tuple = SearchSysCacheCopy1(RELOID,
856  if (!HeapTupleIsValid(tuple))
857  elog(ERROR, "cache lookup failed for relation %u",
858  RelationGetRelid(rel));
859 
860  ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
861 
862  CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
863 
864  heap_freetuple(tuple);
866 
867  /*
868  * We used to try to update the rel's relcache entry here, but that's
869  * fairly pointless since it will happen as a byproduct of the upcoming
870  * CommandCounterIncrement...
871  */
872 
873  /*
874  * Record dependencies for trigger. Always place a normal dependency on
875  * the function.
876  */
877  myself.classId = TriggerRelationId;
878  myself.objectId = trigoid;
879  myself.objectSubId = 0;
880 
881  referenced.classId = ProcedureRelationId;
882  referenced.objectId = funcoid;
883  referenced.objectSubId = 0;
884  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
885 
886  if (isInternal && OidIsValid(constraintOid))
887  {
888  /*
889  * Internally-generated trigger for a constraint, so make it an
890  * internal dependency of the constraint. We can skip depending on
891  * the relation(s), as there'll be an indirect dependency via the
892  * constraint.
893  */
894  referenced.classId = ConstraintRelationId;
895  referenced.objectId = constraintOid;
896  referenced.objectSubId = 0;
897  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
898  }
899  else
900  {
901  /*
902  * User CREATE TRIGGER, so place dependencies. We make trigger be
903  * auto-dropped if its relation is dropped or if the FK relation is
904  * dropped. (Auto drop is compatible with our pre-7.3 behavior.)
905  */
906  referenced.classId = RelationRelationId;
907  referenced.objectId = RelationGetRelid(rel);
908  referenced.objectSubId = 0;
909  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
910  if (OidIsValid(constrrelid))
911  {
912  referenced.classId = RelationRelationId;
913  referenced.objectId = constrrelid;
914  referenced.objectSubId = 0;
915  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
916  }
917  /* Not possible to have an index dependency in this case */
918  Assert(!OidIsValid(indexOid));
919 
920  /*
921  * If it's a user-specified constraint trigger, make the constraint
922  * internally dependent on the trigger instead of vice versa.
923  */
924  if (OidIsValid(constraintOid))
925  {
926  referenced.classId = ConstraintRelationId;
927  referenced.objectId = constraintOid;
928  referenced.objectSubId = 0;
929  recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
930  }
931  }
932 
933  /* If column-specific trigger, add normal dependencies on columns */
934  if (columns != NULL)
935  {
936  int i;
937 
938  referenced.classId = RelationRelationId;
939  referenced.objectId = RelationGetRelid(rel);
940  for (i = 0; i < ncolumns; i++)
941  {
942  referenced.objectSubId = columns[i];
943  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
944  }
945  }
946 
947  /*
948  * If it has a WHEN clause, add dependencies on objects mentioned in the
949  * expression (eg, functions, as well as any columns used).
950  */
951  if (whenClause != NULL)
952  recordDependencyOnExpr(&myself, whenClause, whenRtable,
954 
955  /* Post creation hook for new trigger */
957  isInternal);
958 
959  /* Keep lock on target rel until end of xact */
960  heap_close(rel, NoLock);
961 
962  return myself;
963 }
signed short int16
Definition: c.h:255
#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:2356
#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:692
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
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:538
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:154
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:2363
#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:950
#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:993
List * transitionRels
Definition: parsenodes.h:2359
#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:467
#define Anum_pg_trigger_tgconstrindid
Definition: pg_trigger.h:86
AclResult
Definition: acl.h:170
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:1284
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:1312
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 NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#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:163
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:849
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:2347
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:4252
#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:266
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
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 DestroyTransitionCaptureState ( TransitionCaptureState tcs)

Definition at line 2167 of file trigger.c.

References NULL, pfree(), TransitionCaptureState::tcs_insert_tuplestore, TransitionCaptureState::tcs_old_tuplestore, TransitionCaptureState::tcs_update_tuplestore, and tuplestore_end().

Referenced by ExecEndModifyTable().

2168 {
2169  if (tcs->tcs_insert_tuplestore != NULL)
2171  if (tcs->tcs_update_tuplestore != NULL)
2173  if (tcs->tcs_old_tuplestore != NULL)
2175  pfree(tcs);
2176 }
Tuplestorestate * tcs_update_tuplestore
Definition: trigger.h:86
Tuplestorestate * tcs_old_tuplestore
Definition: trigger.h:84
void pfree(void *pointer)
Definition: mcxt.c:950
#define NULL
Definition: c.h:229
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Tuplestorestate * tcs_insert_tuplestore
Definition: trigger.h:85
void EnableDisableTrigger ( Relation  rel,
const char *  tgname,
char  fires_when,
bool  skip_system 
)

Definition at line 1555 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, NULL, ObjectIdGetDatum, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, ScanKeyInit(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TriggerRelationId, and TriggerRelidNameIndexId.

Referenced by ATExecEnableDisableTrigger().

1557 {
1558  Relation tgrel;
1559  int nkeys;
1560  ScanKeyData keys[2];
1561  SysScanDesc tgscan;
1562  HeapTuple tuple;
1563  bool found;
1564  bool changed;
1565 
1566  /* Scan the relevant entries in pg_triggers */
1568 
1569  ScanKeyInit(&keys[0],
1571  BTEqualStrategyNumber, F_OIDEQ,
1573  if (tgname)
1574  {
1575  ScanKeyInit(&keys[1],
1577  BTEqualStrategyNumber, F_NAMEEQ,
1578  CStringGetDatum(tgname));
1579  nkeys = 2;
1580  }
1581  else
1582  nkeys = 1;
1583 
1584  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1585  NULL, nkeys, keys);
1586 
1587  found = changed = false;
1588 
1589  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1590  {
1591  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1592 
1593  if (oldtrig->tgisinternal)
1594  {
1595  /* system trigger ... ok to process? */
1596  if (skip_system)
1597  continue;
1598  if (!superuser())
1599  ereport(ERROR,
1600  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1601  errmsg("permission denied: \"%s\" is a system trigger",
1602  NameStr(oldtrig->tgname))));
1603  }
1604 
1605  found = true;
1606 
1607  if (oldtrig->tgenabled != fires_when)
1608  {
1609  /* need to change this one ... make a copy to scribble on */
1610  HeapTuple newtup = heap_copytuple(tuple);
1611  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1612 
1613  newtrig->tgenabled = fires_when;
1614 
1615  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1616 
1617  heap_freetuple(newtup);
1618 
1619  changed = true;
1620  }
1621 
1623  HeapTupleGetOid(tuple), 0);
1624  }
1625 
1626  systable_endscan(tgscan);
1627 
1628  heap_close(tgrel, RowExclusiveLock);
1629 
1630  if (tgname && !found)
1631  ereport(ERROR,
1632  (errcode(ERRCODE_UNDEFINED_OBJECT),
1633  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1634  tgname, RelationGetRelationName(rel))));
1635 
1636  /*
1637  * If we changed anything, broadcast a SI inval message to force each
1638  * backend (including our own!) to rebuild relation's relcache entry.
1639  * Otherwise they will fail to apply the change promptly.
1640  */
1641  if (changed)
1643 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
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:1372
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:1284
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#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:499
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 2626 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2630 {
2631  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2632 
2633  if ((trigdesc && trigdesc->trig_delete_after_row) ||
2634  (transition_capture && transition_capture->tcs_delete_old_table))
2635  {
2636  HeapTuple trigtuple;
2637 
2638  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2639  if (fdw_trigtuple == NULL)
2640  trigtuple = GetTupleForTrigger(estate,
2641  NULL,
2642  relinfo,
2643  tupleid,
2645  NULL);
2646  else
2647  trigtuple = fdw_trigtuple;
2648 
2650  true, trigtuple, NULL, NIL, NULL,
2651  transition_capture);
2652  if (trigtuple != fdw_trigtuple)
2653  heap_freetuple(trigtuple);
2654  }
2655 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
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:5222
bool trig_delete_after_row
Definition: reltrigger.h:66
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3056
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2413 of file trigger.c.

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

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

2416 {
2417  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2418 
2419  if ((trigdesc && trigdesc->trig_insert_after_row) ||
2420  (transition_capture && transition_capture->tcs_insert_new_table))
2422  true, NULL, trigtuple,
2423  recheckIndexes, NULL,
2424  transition_capture);
2425 }
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:5222
bool trig_insert_after_row
Definition: reltrigger.h:56
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes,
TransitionCaptureState transition_capture 
)

Definition at line 2890 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), HeapTupleIsValid, ItemPointerIsValid, LockTupleExclusive, NULL, 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().

2896 {
2897  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2898 
2899  if ((trigdesc && trigdesc->trig_update_after_row) ||
2900  (transition_capture &&
2901  (transition_capture->tcs_update_old_table ||
2902  transition_capture->tcs_update_new_table)))
2903  {
2904  HeapTuple trigtuple;
2905 
2906  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2907  if (fdw_trigtuple == NULL)
2908  trigtuple = GetTupleForTrigger(estate,
2909  NULL,
2910  relinfo,
2911  tupleid,
2913  NULL);
2914  else
2915  trigtuple = fdw_trigtuple;
2916 
2918  true, trigtuple, newtuple, recheckIndexes,
2919  GetUpdatedColumns(relinfo, estate),
2920  transition_capture);
2921  if (trigtuple != fdw_trigtuple)
2922  heap_freetuple(trigtuple);
2923  }
2924 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
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:5222
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 NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:3056
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2546 of file trigger.c.

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

Referenced by fireASTriggers().

2548 {
2549  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2550 
2551  if (trigdesc && trigdesc->trig_delete_after_statement)
2553  false, NULL, NULL, NIL, NULL, transition_capture);
2554 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
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:5222
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2336 of file trigger.c.

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

Referenced by CopyFrom(), and fireASTriggers().

2338 {
2339  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2340 
2341  if (trigdesc && trigdesc->trig_insert_after_statement)
2343  false, NULL, NULL, NIL, NULL, transition_capture);
2344 }
#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:5222
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 3045 of file trigger.c.

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

Referenced by ExecuteTruncate().

3046 {
3047  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
3048 
3049  if (trigdesc && trigdesc->trig_truncate_after_statement)
3051  false, NULL, NULL, NIL, NULL, NULL);
3052 }
#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:5222
bool trig_truncate_after_statement
Definition: reltrigger.h:72
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:100
void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
TransitionCaptureState transition_capture 
)

Definition at line 2760 of file trigger.c.

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

Referenced by fireASTriggers().

2762 {
2763  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2764 
2765  if (trigdesc && trigdesc->trig_update_after_statement)
2767  false, NULL, NULL, NIL,
2768  GetUpdatedColumns(relinfo, estate),
2769  transition_capture);
2770 }
#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:5222
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 NULL
Definition: c.h:229
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2557 of file trigger.c.

References Assert, ExecCallTriggerFunc(), GetPerTupleMemoryContext, GetTupleForTrigger(), heap_freetuple(), HeapTupleIsValid, i, InvalidBuffer, ItemPointerIsValid, LockTupleExclusive, NULL, 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().

2561 {
2562  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2563  bool result = true;
2564  TriggerData LocTriggerData;
2565  HeapTuple trigtuple;
2566  HeapTuple newtuple;
2567  TupleTableSlot *newSlot;
2568  int i;
2569 
2570  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2571  if (fdw_trigtuple == NULL)
2572  {
2573  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2574  LockTupleExclusive, &newSlot);
2575  if (trigtuple == NULL)
2576  return false;
2577  }
2578  else
2579  trigtuple = fdw_trigtuple;
2580 
2581  LocTriggerData.type = T_TriggerData;
2582  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2585  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2586  LocTriggerData.tg_newtuple = NULL;
2587  LocTriggerData.tg_oldtable = NULL;
2588  LocTriggerData.tg_newtable = NULL;
2589  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2590  for (i = 0; i < trigdesc->numtriggers; i++)
2591  {
2592  Trigger *trigger = &trigdesc->triggers[i];
2593 
2594  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2598  continue;
2599  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2600  NULL, trigtuple, NULL))
2601  continue;
2602 
2603  LocTriggerData.tg_trigtuple = trigtuple;
2604  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2605  LocTriggerData.tg_trigger = trigger;
2606  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2607  i,
2608  relinfo->ri_TrigFunctions,
2609  relinfo->ri_TrigInstrument,
2610  GetPerTupleMemoryContext(estate));
2611  if (newtuple == NULL)
2612  {
2613  result = false; /* tell caller to suppress delete */
2614  break;
2615  }
2616  if (newtuple != trigtuple)
2617  heap_freetuple(newtuple);
2618  }
2619  if (trigtuple != fdw_trigtuple)
2620  heap_freetuple(trigtuple);
2621 
2622  return result;
2623 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
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:1372
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:105
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:3200
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
#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:3056
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:2190
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 2347 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, NULL, 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().

2349 {
2350  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2351  HeapTuple slottuple = ExecMaterializeSlot(slot);
2352  HeapTuple newtuple = slottuple;
2353  HeapTuple oldtuple;
2354  TriggerData LocTriggerData;
2355  int i;
2356 
2357  LocTriggerData.type = T_TriggerData;
2358  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2361  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2362  LocTriggerData.tg_newtuple = NULL;
2363  LocTriggerData.tg_oldtable = NULL;
2364  LocTriggerData.tg_newtable = NULL;
2365  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2366  for (i = 0; i < trigdesc->numtriggers; i++)
2367  {
2368  Trigger *trigger = &trigdesc->triggers[i];
2369 
2370  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2374  continue;
2375  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2376  NULL, NULL, newtuple))
2377  continue;
2378 
2379  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2380  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2381  LocTriggerData.tg_trigger = trigger;
2382  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2383  i,
2384  relinfo->ri_TrigFunctions,
2385  relinfo->ri_TrigInstrument,
2386  GetPerTupleMemoryContext(estate));
2387  if (oldtuple != newtuple && oldtuple != slottuple)
2388  heap_freetuple(oldtuple);
2389  if (newtuple == NULL)
2390  return NULL; /* "do nothing" */
2391  }
2392 
2393  if (newtuple != slottuple)
2394  {
2395  /*
2396  * Return the modified tuple using the es_trig_tuple_slot. We assume
2397  * the tuple was allocated in per-tuple memory context, and therefore
2398  * will go away by itself. The tuple table slot should not try to
2399  * clear it.
2400  */
2401  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2402  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2403 
2404  if (newslot->tts_tupleDescriptor != tupdesc)
2405  ExecSetSlotDescriptor(newslot, tupdesc);
2406  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2407  slot = newslot;
2408  }
2409  return slot;
2410 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
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:1372
HeapTuple tg_trigtuple
Definition: trigger.h:35
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:105
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:457
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:3200
#define NULL
Definition: c.h:229
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:462
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
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:2190
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 2773 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, NULL, 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().

2778 {
2779  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2780  HeapTuple slottuple = ExecMaterializeSlot(slot);
2781  HeapTuple newtuple = slottuple;
2782  TriggerData LocTriggerData;
2783  HeapTuple trigtuple;
2784  HeapTuple oldtuple;
2785  TupleTableSlot *newSlot;
2786  int i;
2787  Bitmapset *updatedCols;
2788  LockTupleMode lockmode;
2789 
2790  /* Determine lock mode to use */
2791  lockmode = ExecUpdateLockMode(estate, relinfo);
2792 
2793  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2794  if (fdw_trigtuple == NULL)
2795  {
2796  /* get a copy of the on-disk tuple we are planning to update */
2797  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2798  lockmode, &newSlot);
2799  if (trigtuple == NULL)
2800  return NULL; /* cancel the update action */
2801  }
2802  else
2803  {
2804  trigtuple = fdw_trigtuple;
2805  newSlot = NULL;
2806  }
2807 
2808  /*
2809  * In READ COMMITTED isolation level it's possible that target tuple was
2810  * changed due to concurrent update. In that case we have a raw subplan
2811  * output tuple in newSlot, and need to run it through the junk filter to
2812  * produce an insertable tuple.
2813  *
2814  * Caution: more than likely, the passed-in slot is the same as the
2815  * junkfilter's output slot, so we are clobbering the original value of
2816  * slottuple by doing the filtering. This is OK since neither we nor our
2817  * caller have any more interest in the prior contents of that slot.
2818  */
2819  if (newSlot != NULL)
2820  {
2821  slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
2822  slottuple = ExecMaterializeSlot(slot);
2823  newtuple = slottuple;
2824  }
2825 
2826 
2827  LocTriggerData.type = T_TriggerData;
2828  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2831  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2832  LocTriggerData.tg_oldtable = NULL;
2833  LocTriggerData.tg_newtable = NULL;
2834  updatedCols = GetUpdatedColumns(relinfo, estate);
2835  for (i = 0; i < trigdesc->numtriggers; i++)
2836  {
2837  Trigger *trigger = &trigdesc->triggers[i];
2838 
2839  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2843  continue;
2844  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2845  updatedCols, trigtuple, newtuple))
2846  continue;
2847 
2848  LocTriggerData.tg_trigtuple = trigtuple;
2849  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2850  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2851  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2852  LocTriggerData.tg_trigger = trigger;
2853  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2854  i,
2855  relinfo->ri_TrigFunctions,
2856  relinfo->ri_TrigInstrument,
2857  GetPerTupleMemoryContext(estate));
2858  if (oldtuple != newtuple && oldtuple != slottuple)
2859  heap_freetuple(oldtuple);
2860  if (newtuple == NULL)
2861  {
2862  if (trigtuple != fdw_trigtuple)
2863  heap_freetuple(trigtuple);
2864  return NULL; /* "do nothing" */
2865  }
2866  }
2867  if (trigtuple != fdw_trigtuple)
2868  heap_freetuple(trigtuple);
2869 
2870  if (newtuple != slottuple)
2871  {
2872  /*
2873  * Return the modified tuple using the es_trig_tuple_slot. We assume
2874  * the tuple was allocated in per-tuple memory context, and therefore
2875  * will go away by itself. The tuple table slot should not try to
2876  * clear it.
2877  */
2878  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2879  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2880 
2881  if (newslot->tts_tupleDescriptor != tupdesc)
2882  ExecSetSlotDescriptor(newslot, tupdesc);
2883  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2884  slot = newslot;
2885  }
2886  return slot;
2887 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:60
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
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:1372
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:105
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:457
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:3200
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
Definition: execMain.c:2324
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
#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:3056
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:2190
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2494 of file trigger.c.

References ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, InvalidBuffer, NULL, 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_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().

2495 {
2496  TriggerDesc *trigdesc;
2497  int i;
2498  TriggerData LocTriggerData;
2499 
2500  trigdesc = relinfo->ri_TrigDesc;
2501 
2502  if (trigdesc == NULL)
2503  return;
2504  if (!trigdesc->trig_delete_before_statement)
2505  return;
2506 
2507  LocTriggerData.type = T_TriggerData;
2508  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2510  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2511  LocTriggerData.tg_trigtuple = NULL;
2512  LocTriggerData.tg_newtuple = NULL;
2513  LocTriggerData.tg_oldtable = NULL;
2514  LocTriggerData.tg_newtable = NULL;
2515  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2516  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2517  for (i = 0; i < trigdesc->numtriggers; i++)
2518  {
2519  Trigger *trigger = &trigdesc->triggers[i];
2520  HeapTuple newtuple;
2521 
2522  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2526  continue;
2527  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2528  NULL, NULL, NULL))
2529  continue;
2530 
2531  LocTriggerData.tg_trigger = trigger;
2532  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2533  i,
2534  relinfo->ri_TrigFunctions,
2535  relinfo->ri_TrigInstrument,
2536  GetPerTupleMemoryContext(estate));
2537 
2538  if (newtuple)
2539  ereport(ERROR,
2540  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2541  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2542  }
2543 }
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
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:105
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:3200
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
#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:2190
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2284 of file trigger.c.

References ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, InvalidBuffer, NULL, 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_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().

2285 {
2286  TriggerDesc *trigdesc;
2287  int i;
2288  TriggerData LocTriggerData;
2289 
2290  trigdesc = relinfo->ri_TrigDesc;
2291 
2292  if (trigdesc == NULL)
2293  return;
2294  if (!trigdesc->trig_insert_before_statement)
2295  return;
2296 
2297  LocTriggerData.type = T_TriggerData;
2298  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2300  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2301  LocTriggerData.tg_trigtuple = NULL;
2302  LocTriggerData.tg_newtuple = NULL;
2303  LocTriggerData.tg_oldtable = NULL;
2304  LocTriggerData.tg_newtable = NULL;
2305  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2306  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2307  for (i = 0; i < trigdesc->numtriggers; i++)
2308  {
2309  Trigger *trigger = &trigdesc->triggers[i];
2310  HeapTuple newtuple;
2311 
2312  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2316  continue;
2317  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2318  NULL, NULL, NULL))
2319  continue;
2320 
2321  LocTriggerData.tg_trigger = trigger;
2322  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2323  i,
2324  relinfo->ri_TrigFunctions,
2325  relinfo->ri_TrigInstrument,
2326  GetPerTupleMemoryContext(estate));
2327 
2328  if (newtuple)
2329  ereport(ERROR,
2330  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2331  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2332  }
2333 }
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:105
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:3200
#define NULL
Definition: c.h:229
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:462
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
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:2190
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2993 of file trigger.c.

References ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, i, InvalidBuffer, NULL, 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().

2994 {
2995  TriggerDesc *trigdesc;
2996  int i;
2997  TriggerData LocTriggerData;
2998 
2999  trigdesc = relinfo->ri_TrigDesc;
3000 
3001  if (trigdesc == NULL)
3002  return;
3003  if (!trigdesc->trig_truncate_before_statement)
3004  return;
3005 
3006  LocTriggerData.type = T_TriggerData;
3007  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
3009  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
3010  LocTriggerData.tg_trigtuple = NULL;
3011  LocTriggerData.tg_newtuple = NULL;
3012  LocTriggerData.tg_oldtable = NULL;
3013  LocTriggerData.tg_newtable = NULL;
3014  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
3015  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
3016  for (i = 0; i < trigdesc->numtriggers; i++)
3017  {
3018  Trigger *trigger = &trigdesc->triggers[i];
3019  HeapTuple newtuple;
3020 
3021  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3025  continue;
3026  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
3027  NULL, NULL, NULL))
3028  continue;
3029 
3030  LocTriggerData.tg_trigger = trigger;
3031  newtuple = ExecCallTriggerFunc(&LocTriggerData,
3032  i,
3033  relinfo->ri_TrigFunctions,
3034  relinfo->ri_TrigInstrument,
3035  GetPerTupleMemoryContext(estate));
3036 
3037  if (newtuple)
3038  ereport(ERROR,
3039  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3040  errmsg("BEFORE STATEMENT trigger cannot return a value")));
3041  }
3042 }
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:105
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:3200
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:100
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
#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:2190
#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 2705 of file trigger.c.

References ereport, errcode(), errmsg(), ERROR, ExecCallTriggerFunc(), GetPerTupleMemoryContext, GetUpdatedColumns, i, InvalidBuffer, NULL, 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_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().

2706 {
2707  TriggerDesc *trigdesc;
2708  int i;
2709  TriggerData LocTriggerData;
2710  Bitmapset *updatedCols;
2711 
2712  trigdesc = relinfo->ri_TrigDesc;
2713 
2714  if (trigdesc == NULL)
2715  return;
2716  if (!trigdesc->trig_update_before_statement)
2717  return;
2718 
2719  updatedCols = GetUpdatedColumns(relinfo, estate);
2720 
2721  LocTriggerData.type = T_TriggerData;
2722  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2724  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2725  LocTriggerData.tg_trigtuple = NULL;
2726  LocTriggerData.tg_newtuple = NULL;
2727  LocTriggerData.tg_oldtable = NULL;
2728  LocTriggerData.tg_newtable = NULL;
2729  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2730  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2731  for (i = 0; i < trigdesc->numtriggers; i++)
2732  {
2733  Trigger *trigger = &trigdesc->triggers[i];
2734  HeapTuple newtuple;
2735 
2736  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2740  continue;
2741  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2742  updatedCols, NULL, NULL))
2743  continue;
2744 
2745  LocTriggerData.tg_trigger = trigger;
2746  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2747  i,
2748  relinfo->ri_TrigFunctions,
2749  relinfo->ri_TrigInstrument,
2750  GetPerTupleMemoryContext(estate));
2751 
2752  if (newtuple)
2753  ereport(ERROR,
2754  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2755  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2756  }
2757 }
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
#define ERROR
Definition: elog.h:43
int16 tgtype
Definition: reltrigger.h:29
#define TRIGGER_EVENT_BEFORE
Definition: trigger.h:105
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:3200
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:76
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
#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:2190
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
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 2658 of file trigger.c.

References ExecCallTriggerFunc(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, NULL, 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().

2660 {
2661  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2662  TriggerData LocTriggerData;
2663  HeapTuple rettuple;
2664  int i;
2665 
2666  LocTriggerData.type = T_TriggerData;
2667  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2670  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2671  LocTriggerData.tg_newtuple = NULL;
2672  LocTriggerData.tg_oldtable = NULL;
2673  LocTriggerData.tg_newtable = NULL;
2674  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2675  for (i = 0; i < trigdesc->numtriggers; i++)
2676  {
2677  Trigger *trigger = &trigdesc->triggers[i];
2678 
2679  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2683  continue;
2684  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2685  NULL, trigtuple, NULL))
2686  continue;
2687 
2688  LocTriggerData.tg_trigtuple = trigtuple;
2689  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2690  LocTriggerData.tg_trigger = trigger;
2691  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2692  i,
2693  relinfo->ri_TrigFunctions,
2694  relinfo->ri_TrigInstrument,
2695  GetPerTupleMemoryContext(estate));
2696  if (rettuple == NULL)
2697  return false; /* Delete was suppressed */
2698  if (rettuple != trigtuple)
2699  heap_freetuple(rettuple);
2700  }
2701  return true;
2702 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
Relation ri_RelationDesc
Definition: execnodes.h:354
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:98
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:1372
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:107
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:3200
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
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:2190
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 2428 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, NULL, 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().

2430 {
2431  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2432  HeapTuple slottuple = ExecMaterializeSlot(slot);
2433  HeapTuple newtuple = slottuple;
2434  HeapTuple oldtuple;
2435  TriggerData LocTriggerData;
2436  int i;
2437 
2438  LocTriggerData.type = T_TriggerData;
2439  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2442  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2443  LocTriggerData.tg_newtuple = NULL;
2444  LocTriggerData.tg_oldtable = NULL;
2445  LocTriggerData.tg_newtable = NULL;
2446  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2447  for (i = 0; i < trigdesc->numtriggers; i++)
2448  {
2449  Trigger *trigger = &trigdesc->triggers[i];
2450 
2451  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2455  continue;
2456  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2457  NULL, NULL, newtuple))
2458  continue;
2459 
2460  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2461  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2462  LocTriggerData.tg_trigger = trigger;
2463  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2464  i,
2465  relinfo->ri_TrigFunctions,
2466  relinfo->ri_TrigInstrument,
2467  GetPerTupleMemoryContext(estate));
2468  if (oldtuple != newtuple && oldtuple != slottuple)
2469  heap_freetuple(oldtuple);
2470  if (newtuple == NULL)
2471  return NULL; /* "do nothing" */
2472  }
2473 
2474  if (newtuple != slottuple)
2475  {
2476  /*
2477  * Return the modified tuple using the es_trig_tuple_slot. We assume
2478  * the tuple was allocated in per-tuple memory context, and therefore
2479  * will go away by itself. The tuple table slot should not try to
2480  * clear it.
2481  */
2482  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2483  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2484 
2485  if (newslot->tts_tupleDescriptor != tupdesc)
2486  ExecSetSlotDescriptor(newslot, tupdesc);
2487  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2488  slot = newslot;
2489  }
2490  return slot;
2491 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
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:1372
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:107
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:457
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:3200
#define NULL
Definition: c.h:229
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:462
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:97
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:2190
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 2927 of file trigger.c.

References EState::es_trig_tuple_slot, ExecCallTriggerFunc(), ExecMaterializeSlot(), ExecSetSlotDescriptor(), ExecStoreTuple(), GetPerTupleMemoryContext, heap_freetuple(), i, InvalidBuffer, NULL, 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().

2929 {
2930  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2931  HeapTuple slottuple = ExecMaterializeSlot(slot);
2932  HeapTuple newtuple = slottuple;
2933  TriggerData LocTriggerData;
2934  HeapTuple oldtuple;
2935  int i;
2936 
2937  LocTriggerData.type = T_TriggerData;
2938  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2941  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2942  LocTriggerData.tg_oldtable = NULL;
2943  LocTriggerData.tg_newtable = NULL;
2944  for (i = 0; i < trigdesc->numtriggers; i++)
2945  {
2946  Trigger *trigger = &trigdesc->triggers[i];
2947 
2948  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2952  continue;
2953  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2954  NULL, trigtuple, newtuple))
2955  continue;
2956 
2957  LocTriggerData.tg_trigtuple = trigtuple;
2958  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2959  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2960  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2961  LocTriggerData.tg_trigger = trigger;
2962  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2963  i,
2964  relinfo->ri_TrigFunctions,
2965  relinfo->ri_TrigInstrument,
2966  GetPerTupleMemoryContext(estate));
2967  if (oldtuple != newtuple && oldtuple != slottuple)
2968  heap_freetuple(oldtuple);
2969  if (newtuple == NULL)
2970  return NULL; /* "do nothing" */
2971  }
2972 
2973  if (newtuple != slottuple)
2974  {
2975  /*
2976  * Return the modified tuple using the es_trig_tuple_slot. We assume
2977  * the tuple was allocated in per-tuple memory context, and therefore
2978  * will go away by itself. The tuple table slot should not try to
2979  * clear it.
2980  */
2981  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2982  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2983 
2984  if (newslot->tts_tupleDescriptor != tupdesc)
2985  ExecSetSlotDescriptor(newslot, tupdesc);
2986  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2987  slot = newslot;
2988  }
2989  return slot;
2990 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:103
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:1372
HeapTuple tg_trigtuple
Definition: trigger.h:35
#define TRIGGER_TYPE_INSTEAD
Definition: pg_trigger.h:104
#define TRIGGER_EVENT_INSTEAD
Definition: trigger.h:107
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:457
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:3200
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:99
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:462
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:2190
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:369
Relation tg_relation
Definition: trigger.h:34
const char* FindTriggerIncompatibleWithInheritance ( TriggerDesc trigdesc)

Definition at line 2070 of file trigger.c.

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

Referenced by ATExecAddInherit(), and ATExecAttachPartition().

2071 {
2072  if (trigdesc != NULL)
2073  {
2074  int i;
2075 
2076  for (i = 0; i < trigdesc->numtriggers; ++i)
2077  {
2078  Trigger *trigger = &trigdesc->triggers[i];
2079 
2080  if (trigger->tgoldtable != NULL || trigger->tgnewtable != NULL)
2081  return trigger->tgname;
2082  }
2083  }
2084 
2085  return NULL;
2086 }
char * tgname
Definition: reltrigger.h:27
Trigger * triggers
Definition: reltrigger.h:48
int numtriggers
Definition: reltrigger.h:49
char * tgnewtable
Definition: reltrigger.h:43
#define NULL
Definition: c.h:229
int i
char * tgoldtable
Definition: reltrigger.h:42
void FreeTriggerDesc ( TriggerDesc trigdesc)

Definition at line 1940 of file trigger.c.

References i, NULL, 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().

1941 {
1942  Trigger *trigger;
1943  int i;
1944 
1945  if (trigdesc == NULL)
1946  return;
1947 
1948  trigger = trigdesc->triggers;
1949  for (i = 0; i < trigdesc->numtriggers; i++)
1950  {
1951  pfree(trigger->tgname);
1952  if (trigger->tgnattr > 0)
1953  pfree(trigger->tgattr);
1954  if (trigger->tgnargs > 0)
1955  {
1956  while (--(trigger->tgnargs) >= 0)
1957  pfree(trigger->tgargs[trigger->tgnargs]);
1958  pfree(trigger->tgargs);
1959  }
1960  if (trigger->tgqual)
1961  pfree(trigger->tgqual);
1962  if (trigger->tgoldtable)
1963  pfree(trigger->tgoldtable);
1964  if (trigger->tgnewtable)
1965  pfree(trigger->tgnewtable);
1966  trigger++;
1967  }
1968  pfree(trigdesc->triggers);
1969  pfree(trigdesc);
1970 }
void pfree(void *pointer)
Definition: mcxt.c:950
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
#define NULL
Definition: c.h:229
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 1327 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, NULL, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), TriggerRelationId, and TriggerRelidNameIndexId.

Referenced by get_object_address_relobject().

1328 {
1329  Relation tgrel;
1330  ScanKeyData skey[2];
1331  SysScanDesc tgscan;
1332  HeapTuple tup;
1333  Oid oid;
1334 
1335  /*
1336  * Find the trigger, verify permissions, set up object address
1337  */
1339 
1340  ScanKeyInit(&skey[0],
1342  BTEqualStrategyNumber, F_OIDEQ,
1343  ObjectIdGetDatum(relid));
1344  ScanKeyInit(&skey[1],
1346  BTEqualStrategyNumber, F_NAMEEQ,
1347  CStringGetDatum(trigname));
1348 
1349  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1350  NULL, 2, skey);
1351 
1352  tup = systable_getnext(tgscan);
1353 
1354  if (!HeapTupleIsValid(tup))
1355  {
1356  if (!missing_ok)
1357  ereport(ERROR,
1358  (errcode(ERRCODE_UNDEFINED_OBJECT),
1359  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1360  trigname, get_rel_name(relid))));
1361  oid = InvalidOid;
1362  }
1363  else
1364  {
1365  oid = HeapTupleGetOid(tup);
1366  }
1367 
1368  systable_endscan(tgscan);
1369  heap_close(tgrel, AccessShareLock);
1370  return oid;
1371 }
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:1284
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#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)

Definition at line 2104 of file trigger.c.

References CurrentResourceOwner, CurTransactionContext, CurTransactionResourceOwner, MemoryContextSwitchTo(), NULL, palloc0(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, TransitionCaptureState::tcs_delete_old_table, TransitionCaptureState::tcs_insert_new_table, TransitionCaptureState::tcs_insert_tuplestore, TransitionCaptureState::tcs_old_tuplestore, TransitionCaptureState::tcs_update_new_table, TransitionCaptureState::tcs_update_old_table, TransitionCaptureState::tcs_update_tuplestore, 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 BeginCopy(), and ExecSetupTransitionCaptureState().

2105 {
2107 
2108  if (trigdesc != NULL &&
2109  (trigdesc->trig_delete_old_table || trigdesc->trig_update_old_table ||
2110  trigdesc->trig_update_new_table || trigdesc->trig_insert_new_table))
2111  {
2112  MemoryContext oldcxt;
2113  ResourceOwner saveResourceOwner;
2114 
2115  /*
2116  * Normally DestroyTransitionCaptureState should be called after
2117  * executing all AFTER triggers for the current statement.
2118  *
2119  * To handle error cleanup, TransitionCaptureState and the tuplestores
2120  * it contains will live in the current [sub]transaction's memory
2121  * context. Likewise for the current resource owner, because we also
2122  * want to clean up temporary files spilled to disk by the tuplestore
2123  * in that scenario. This scope is sufficient, because AFTER triggers
2124  * with transition tables cannot be deferred (only constraint triggers
2125  * can be deferred, and constraint triggers cannot have transition
2126  * tables). The AFTER trigger queue may contain pointers to this
2127  * TransitionCaptureState, but any such entries will be processed or
2128  * discarded before the end of the current [sub]transaction.
2129  *
2130  * If a future release allows deferred triggers with transition
2131  * tables, we'll need to reconsider the scope of the
2132  * TransitionCaptureState object.
2133  */
2135  saveResourceOwner = CurrentResourceOwner;
2136 
2137  state = (TransitionCaptureState *)
2139  state->tcs_delete_old_table = trigdesc->trig_delete_old_table;
2140  state->tcs_update_old_table = trigdesc->trig_update_old_table;
2141  state->tcs_update_new_table = trigdesc->trig_update_new_table;
2142  state->tcs_insert_new_table = trigdesc->trig_insert_new_table;
2143  PG_TRY();
2144  {
2146  if (trigdesc->trig_delete_old_table || trigdesc->trig_update_old_table)
2147  state->tcs_old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
2148  if (trigdesc->trig_insert_new_table)
2149  state->tcs_insert_tuplestore = tuplestore_begin_heap(false, false, work_mem);
2150  if (trigdesc->trig_update_new_table)
2151  state->tcs_update_tuplestore = tuplestore_begin_heap(false, false, work_mem);
2152  }
2153  PG_CATCH();
2154  {
2155  CurrentResourceOwner = saveResourceOwner;
2156  PG_RE_THROW();
2157  }
2158  PG_END_TRY();
2159  CurrentResourceOwner = saveRe