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
 

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
 

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)
 
void FreeTriggerDesc (TriggerDesc *trigdesc)
 
void ExecBSInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASInsertTriggers (EState *estate, ResultRelInfo *relinfo)
 
TupleTableSlotExecBRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecARInsertTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
 
TupleTableSlotExecIRInsertTriggers (EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
 
void ExecBSDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASDeleteTriggers (EState *estate, ResultRelInfo *relinfo)
 
bool ExecBRDeleteTriggers (EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
void ExecARDeleteTriggers (EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
 
bool ExecIRDeleteTriggers (EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
 
void ExecBSUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
void ExecASUpdateTriggers (EState *estate, ResultRelInfo *relinfo)
 
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)
 
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 67 of file trigger.h.

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

#define AFTER_TRIGGER_INITDEFERRED   0x00000040

Definition at line 68 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 210 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 211 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 209 of file trigger.h.

Referenced by AfterTriggerSaveEvent(), and RI_FKey_trigger_type().

#define SESSION_REPLICATION_ROLE_LOCAL   2

Definition at line 102 of file trigger.h.

#define SESSION_REPLICATION_ROLE_ORIGIN   0

Definition at line 100 of file trigger.h.

#define SESSION_REPLICATION_ROLE_REPLICA   1

Definition at line 101 of file trigger.h.

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

#define TRIGGER_DISABLED   'D'

Definition at line 112 of file trigger.h.

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

#define TRIGGER_EVENT_AFTER   0x00000000

Definition at line 61 of file trigger.h.

#define TRIGGER_EVENT_DELETE   0x00000001
#define TRIGGER_EVENT_INSTEAD   0x00000010

Definition at line 62 of file trigger.h.

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

#define TRIGGER_EVENT_OPMASK   0x00000003

Definition at line 56 of file trigger.h.

Referenced by AfterTriggerExecute(), and AfterTriggerSaveEvent().

#define TRIGGER_EVENT_TIMINGMASK   0x00000018

Definition at line 63 of file trigger.h.

#define TRIGGER_EVENT_TRUNCATE   0x00000003

Definition at line 55 of file trigger.h.

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

#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 110 of file trigger.h.

Referenced by ATExecCmd().

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

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

References AfterTriggersData::query_depth.

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

4169 {
4170  /* Increase the query stack depth */
4172 }
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
void AfterTriggerBeginSubXact ( void  )

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

4393 {
4394  int my_level = GetCurrentTransactionNestLevel();
4395 
4396  /*
4397  * Allocate more space in the stacks if needed. (Note: because the
4398  * minimum nest level of a subtransaction is 2, we waste the first couple
4399  * entries of each array; not worth the notational effort to avoid it.)
4400  */
4401  while (my_level >= afterTriggers.maxtransdepth)
4402  {
4403  if (afterTriggers.maxtransdepth == 0)
4404  {
4405  MemoryContext old_cxt;
4406 
4408 
4409 #define DEFTRIG_INITALLOC 8
4414  afterTriggers.depth_stack = (int *)
4415  palloc(DEFTRIG_INITALLOC * sizeof(int));
4417  palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
4419 
4420  MemoryContextSwitchTo(old_cxt);
4421  }
4422  else
4423  {
4424  /* repalloc will keep the stacks in the same context */
4425  int new_alloc = afterTriggers.maxtransdepth * 2;
4426 
4429  new_alloc * sizeof(SetConstraintState));
4432  new_alloc * sizeof(AfterTriggerEventList));
4433  afterTriggers.depth_stack = (int *)
4435  new_alloc * sizeof(int));
4438  new_alloc * sizeof(CommandId));
4439  afterTriggers.maxtransdepth = new_alloc;
4440  }
4441  }
4442 
4443  /*
4444  * Push the current information into the stack. The SET CONSTRAINTS state
4445  * is not saved until/unless changed. Likewise, we don't make a
4446  * per-subtransaction event context until needed.
4447  */
4448  afterTriggers.state_stack[my_level] = NULL;
4452 }
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:3427
SetConstraintState * state_stack
Definition: trigger.c:3424
CommandId firing_counter
Definition: trigger.c:3410
AfterTriggerEventList * events_stack
Definition: trigger.c:3425
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:3412
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
void AfterTriggerBeginXact ( void  )

Definition at line 4130 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, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, and AfterTriggersData::state_stack.

Referenced by StartTransaction().

4131 {
4132  /*
4133  * Initialize after-trigger state structure to empty
4134  */
4135  afterTriggers.firing_counter = (CommandId) 1; /* mustn't be 0 */
4137 
4138  /*
4139  * Verify that there is no leftover state remaining. If these assertions
4140  * trip, it means that AfterTriggerEndXact wasn't called or didn't clean
4141  * up properly.
4142  */
4156 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3417
CommandId * firing_stack
Definition: trigger.c:3427
SetConstraintState * state_stack
Definition: trigger.c:3424
SetConstraintState state
Definition: trigger.c:3411
CommandId firing_counter
Definition: trigger.c:3410
AfterTriggerEventList * events_stack
Definition: trigger.c:3425
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3332
MemoryContext event_cxt
Definition: trigger.c:3420
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3415
AfterTriggerEventList events
Definition: trigger.c:3412
AfterTriggerEventList * query_stack
Definition: trigger.c:3414
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3418
void AfterTriggerEndQuery ( EState estate)

Definition at line 4188 of file trigger.c.

References afterTriggerFreeEventList(), afterTriggerInvokeEvents(), afterTriggerMarkEvents(), Assert, AfterTriggersData::events, AfterTriggersData::fdw_tuplestores, AfterTriggersData::firing_counter, AfterTriggersData::maxquerydepth, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, 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().

4189 {
4190  AfterTriggerEventList *events;
4191  Tuplestorestate *fdw_tuplestore;
4192  Tuplestorestate *old_tuplestore;
4193  Tuplestorestate *new_tuplestore;
4194 
4195  /* Must be inside a query, too */
4197 
4198  /*
4199  * If we never even got as far as initializing the event stack, there
4200  * certainly won't be any events, so exit quickly.
4201  */
4203  {
4205  return;
4206  }
4207 
4208  /*
4209  * Process all immediate-mode triggers queued by the query, and move the
4210  * deferred ones to the main list of deferred events.
4211  *
4212  * Notice that we decide which ones will be fired, and put the deferred
4213  * ones on the main list, before anything is actually fired. This ensures
4214  * reasonably sane behavior if a trigger function does SET CONSTRAINTS ...
4215  * IMMEDIATE: all events we have decided to defer will be available for it
4216  * to fire.
4217  *
4218  * We loop in case a trigger queues more events at the same query level.
4219  * Ordinary trigger functions, including all PL/pgSQL trigger functions,
4220  * will instead fire any triggers in a dedicated query level. Foreign key
4221  * enforcement triggers do add to the current query level, thanks to their
4222  * passing fire_triggers = false to SPI_execute_snapshot(). Other
4223  * C-language triggers might do likewise. Be careful here: firing a
4224  * trigger could result in query_stack being repalloc'd, so we can't save
4225  * its address across afterTriggerInvokeEvents calls.
4226  *
4227  * If we find no firable events, we don't have to increment
4228  * firing_counter.
4229  */
4230  for (;;)
4231  {
4233  if (afterTriggerMarkEvents(events, &afterTriggers.events, true))
4234  {
4235  CommandId firing_id = afterTriggers.firing_counter++;
4236 
4237  /* OK to delete the immediate events after processing them */
4238  if (afterTriggerInvokeEvents(events, firing_id, estate, true))
4239  break; /* all fired */
4240  }
4241  else
4242  break;
4243  }
4244 
4245  /* Release query-local storage for events, including tuplestore if any */
4247  if (fdw_tuplestore)
4248  {
4249  tuplestore_end(fdw_tuplestore);
4251  }
4253  if (old_tuplestore)
4254  {
4255  tuplestore_end(old_tuplestore);
4257  }
4259  if (new_tuplestore)
4260  {
4261  tuplestore_end(new_tuplestore);
4263  }
4265 
4267 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3417
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3994
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3657
CommandId firing_counter
Definition: trigger.c:3410
#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:3922
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3415
AfterTriggerEventList events
Definition: trigger.c:3412
AfterTriggerEventList * query_stack
Definition: trigger.c:3414
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3418
void AfterTriggerEndSubXact ( bool  isCommit)

Definition at line 4460 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, AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, pfree(), AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, and tuplestore_end().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

4461 {
4462  int my_level = GetCurrentTransactionNestLevel();
4464  AfterTriggerEvent event;
4465  AfterTriggerEventChunk *chunk;
4466  CommandId subxact_firing_id;
4467 
4468  /*
4469  * Pop the prior state if needed.
4470  */
4471  if (isCommit)
4472  {
4473  Assert(my_level < afterTriggers.maxtransdepth);
4474  /* If we saved a prior state, we don't need it anymore */
4475  state = afterTriggers.state_stack[my_level];
4476  if (state != NULL)
4477  pfree(state);
4478  /* this avoids double pfree if error later: */
4479  afterTriggers.state_stack[my_level] = NULL;
4481  afterTriggers.depth_stack[my_level]);
4482  }
4483  else
4484  {
4485  /*
4486  * Aborting. It is possible subxact start failed before calling
4487  * AfterTriggerBeginSubXact, in which case we mustn't risk touching
4488  * stack levels that aren't there.
4489  */
4490  if (my_level >= afterTriggers.maxtransdepth)
4491  return;
4492 
4493  /*
4494  * Release any event lists from queries being aborted, and restore
4495  * query_depth to its pre-subxact value. This assumes that a
4496  * subtransaction will not add events to query levels started in a
4497  * earlier transaction state.
4498  */
4500  {
4502  {
4503  Tuplestorestate *ts;
4504 
4506  if (ts)
4507  {
4508  tuplestore_end(ts);
4510  }
4512  if (ts)
4513  {
4514  tuplestore_end(ts);
4516  }
4518  if (ts)
4519  {
4520  tuplestore_end(ts);
4522  }
4523 
4525  }
4526 
4528  }
4530  afterTriggers.depth_stack[my_level]);
4531 
4532  /*
4533  * Restore the global deferred-event list to its former length,
4534  * discarding any events queued by the subxact.
4535  */
4537  &afterTriggers.events_stack[my_level]);
4538 
4539  /*
4540  * Restore the trigger state. If the saved state is NULL, then this
4541  * subxact didn't save it, so it doesn't need restoring.
4542  */
4543  state = afterTriggers.state_stack[my_level];
4544  if (state != NULL)
4545  {
4547  afterTriggers.state = state;
4548  }
4549  /* this avoids double pfree if error later: */
4550  afterTriggers.state_stack[my_level] = NULL;
4551 
4552  /*
4553  * Scan for any remaining deferred events that were marked DONE or IN
4554  * PROGRESS by this subxact or a child, and un-mark them. We can
4555  * recognize such events because they have a firing ID greater than or
4556  * equal to the firing_counter value we saved at subtransaction start.
4557  * (This essentially assumes that the current subxact includes all
4558  * subxacts started after it.)
4559  */
4560  subxact_firing_id = afterTriggers.firing_stack[my_level];
4562  {
4563  AfterTriggerShared evtshared = GetTriggerSharedData(event);
4564 
4565  if (event->ate_flags &
4567  {
4568  if (evtshared->ats_firing_id >= subxact_firing_id)
4569  event->ate_flags &=
4571  }
4572  }
4573  }
4574 }
uint32 CommandId
Definition: c.h:411
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3417
TriggerFlags ate_flags
Definition: trigger.c:3283
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3260
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3345
CommandId * firing_stack
Definition: trigger.c:3427
#define GetTriggerSharedData(evt)
Definition: trigger.c:3308
void pfree(void *pointer)
Definition: mcxt.c:950
SetConstraintState * state_stack
Definition: trigger.c:3424
SetConstraintState state
Definition: trigger.c:3411
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
Definition: trigger.c:3657
AfterTriggerEventList * events_stack
Definition: trigger.c:3425
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:3680
CommandId ats_firing_id
Definition: trigger.c:3276
#define AFTER_TRIGGER_IN_PROGRESS
Definition: trigger.c:3261
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3415
AfterTriggerEventList events
Definition: trigger.c:3412
AfterTriggerEventList * query_stack
Definition: trigger.c:3414
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3418
void AfterTriggerEndXact ( bool  isCommit)

Definition at line 4338 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(), AfterTriggersData::new_tuplestores, NULL, AfterTriggersData::old_tuplestores, AfterTriggersData::query_depth, AfterTriggersData::query_stack, AfterTriggersData::state, AfterTriggersData::state_stack, AfterTriggerEventList::tail, and AfterTriggerEventList::tailfree.

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

4339 {
4340  /*
4341  * Forget the pending-events list.
4342  *
4343  * Since all the info is in TopTransactionContext or children thereof, we
4344  * don't really need to do anything to reclaim memory. However, the
4345  * pending-events list could be large, and so it's useful to discard it as
4346  * soon as possible --- especially if we are aborting because we ran out
4347  * of memory for the list!
4348  */
4350  {
4356  }
4357 
4358  /*
4359  * Forget any subtransaction state as well. Since this can't be very
4360  * large, we let the eventual reset of TopTransactionContext free the
4361  * memory instead of doing it here.
4362  */
4368 
4369 
4370  /*
4371  * Forget the query stack and constraint-related state information. As
4372  * with the subtransaction state information, we don't bother freeing the
4373  * memory here.
4374  */
4381 
4382  /* No more afterTriggers manipulation until next transaction starts. */
4384 }
Tuplestorestate ** old_tuplestores
Definition: trigger.c:3417
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
AfterTriggerEventChunk * tail
Definition: trigger.c:3333
CommandId * firing_stack
Definition: trigger.c:3427
SetConstraintState * state_stack
Definition: trigger.c:3424
SetConstraintState state
Definition: trigger.c:3411
AfterTriggerEventList * events_stack
Definition: trigger.c:3425
#define NULL
Definition: c.h:229
AfterTriggerEventChunk * head
Definition: trigger.c:3332
MemoryContext event_cxt
Definition: trigger.c:3420
Tuplestorestate ** fdw_tuplestores
Definition: trigger.c:3415
AfterTriggerEventList events
Definition: trigger.c:3412
AfterTriggerEventList * query_stack
Definition: trigger.c:3414
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
Tuplestorestate ** new_tuplestores
Definition: trigger.c:3418
void AfterTriggerFireDeferred ( void  )

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

4283 {
4284  AfterTriggerEventList *events;
4285  bool snap_pushed = false;
4286 
4287  /* Must not be inside a query */
4289 
4290  /*
4291  * If there are any triggers to fire, make sure we have set a snapshot for
4292  * them to use. (Since PortalRunUtility doesn't set a snap for COMMIT, we
4293  * can't assume ActiveSnapshot is valid on entry.)
4294  */
4295  events = &afterTriggers.events;
4296  if (events->head != NULL)
4297  {
4299  snap_pushed = true;
4300  }
4301 
4302  /*
4303  * Run all the remaining triggers. Loop until they are all gone, in case
4304  * some trigger queues more for us to do.
4305  */
4306  while (afterTriggerMarkEvents(events, NULL, false))
4307  {
4308  CommandId firing_id = afterTriggers.firing_counter++;
4309 
4310  if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
4311  break; /* all fired */
4312  }
4313 
4314  /*
4315  * We don't bother freeing the event list, since it will go away anyway
4316  * (and more efficiently than via pfree) in AfterTriggerEndXact.
4317  */
4318 
4319  if (snap_pushed)
4321 }
uint32 CommandId
Definition: c.h:411
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3994
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
CommandId firing_counter
Definition: trigger.c:3410
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
AfterTriggerEventChunk * head
Definition: trigger.c:3332
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
Definition: trigger.c:3922
AfterTriggerEventList events
Definition: trigger.c:3412
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
bool AfterTriggerPendingOnRel ( Oid  relid)

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

5027 {
5028  AfterTriggerEvent event;
5029  AfterTriggerEventChunk *chunk;
5030  int depth;
5031 
5032  /* Scan queued events */
5034  {
5035  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5036 
5037  /*
5038  * We can ignore completed events. (Even if a DONE flag is rolled
5039  * back by subxact abort, it's OK because the effects of the TRUNCATE
5040  * or whatever must get rolled back too.)
5041  */
5042  if (event->ate_flags & AFTER_TRIGGER_DONE)
5043  continue;
5044 
5045  if (evtshared->ats_relid == relid)
5046  return true;
5047  }
5048 
5049  /*
5050  * Also scan events queued by incomplete queries. This could only matter
5051  * if TRUNCATE/etc is executed by a function or trigger within an updating
5052  * query on the same relation, which is pretty perverse, but let's check.
5053  */
5054  for (depth = 0; depth <= afterTriggers.query_depth && depth < afterTriggers.maxquerydepth; depth++)
5055  {
5056  for_each_event_chunk(event, chunk, afterTriggers.query_stack[depth])
5057  {
5058  AfterTriggerShared evtshared = GetTriggerSharedData(event);
5059 
5060  if (event->ate_flags & AFTER_TRIGGER_DONE)
5061  continue;
5062 
5063  if (evtshared->ats_relid == relid)
5064  return true;
5065  }
5066  }
5067 
5068  return false;
5069 }
TriggerFlags ate_flags
Definition: trigger.c:3283
#define AFTER_TRIGGER_DONE
Definition: trigger.c:3260
#define for_each_event_chunk(eptr, cptr, evtlist)
Definition: trigger.c:3345
#define GetTriggerSharedData(evt)
Definition: trigger.c:3308
AfterTriggerEventList events
Definition: trigger.c:3412
AfterTriggerEventList * query_stack
Definition: trigger.c:3414
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
void AfterTriggerSetState ( ConstraintsSetStmt stmt)

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

4733 {
4734  int my_level = GetCurrentTransactionNestLevel();
4735 
4736  /* If we haven't already done so, initialize our state. */
4737  if (afterTriggers.state == NULL)
4739 
4740  /*
4741  * If in a subtransaction, and we didn't save the current state already,
4742  * save it so it can be restored if the subtransaction aborts.
4743  */
4744  if (my_level > 1 &&
4745  afterTriggers.state_stack[my_level] == NULL)
4746  {
4747  afterTriggers.state_stack[my_level] =
4749  }
4750 
4751  /*
4752  * Handle SET CONSTRAINTS ALL ...
4753  */
4754  if (stmt->constraints == NIL)
4755  {
4756  /*
4757  * Forget any previous SET CONSTRAINTS commands in this transaction.
4758  */
4760 
4761  /*
4762  * Set the per-transaction ALL state to known.
4763  */
4764  afterTriggers.state->all_isset = true;
4766  }
4767  else
4768  {
4769  Relation conrel;
4770  Relation tgrel;
4771  List *conoidlist = NIL;
4772  List *tgoidlist = NIL;
4773  ListCell *lc;
4774 
4775  /*
4776  * Handle SET CONSTRAINTS constraint-name [, ...]
4777  *
4778  * First, identify all the named constraints and make a list of their
4779  * OIDs. Since, unlike the SQL spec, we allow multiple constraints of
4780  * the same name within a schema, the specifications are not
4781  * necessarily unique. Our strategy is to target all matching
4782  * constraints within the first search-path schema that has any
4783  * matches, but disregard matches in schemas beyond the first match.
4784  * (This is a bit odd but it's the historical behavior.)
4785  */
4787 
4788  foreach(lc, stmt->constraints)
4789  {
4790  RangeVar *constraint = lfirst(lc);
4791  bool found;
4792  List *namespacelist;
4793  ListCell *nslc;
4794 
4795  if (constraint->catalogname)
4796  {
4797  if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
4798  ereport(ERROR,
4799  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4800  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
4801  constraint->catalogname, constraint->schemaname,
4802  constraint->relname)));
4803  }
4804 
4805  /*
4806  * If we're given the schema name with the constraint, look only
4807  * in that schema. If given a bare constraint name, use the
4808  * search path to find the first matching constraint.
4809  */
4810  if (constraint->schemaname)
4811  {
4812  Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
4813  false);
4814 
4815  namespacelist = list_make1_oid(namespaceId);
4816  }
4817  else
4818  {
4819  namespacelist = fetch_search_path(true);
4820  }
4821 
4822  found = false;
4823  foreach(nslc, namespacelist)
4824  {
4825  Oid namespaceId = lfirst_oid(nslc);
4826  SysScanDesc conscan;
4827  ScanKeyData skey[2];
4828  HeapTuple tup;
4829 
4830  ScanKeyInit(&skey[0],
4832  BTEqualStrategyNumber, F_NAMEEQ,
4833  CStringGetDatum(constraint->relname));
4834  ScanKeyInit(&skey[1],
4836  BTEqualStrategyNumber, F_OIDEQ,
4837  ObjectIdGetDatum(namespaceId));
4838 
4839  conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
4840  true, NULL, 2, skey);
4841 
4842  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
4843  {
4845 
4846  if (con->condeferrable)
4847  conoidlist = lappend_oid(conoidlist,
4848  HeapTupleGetOid(tup));
4849  else if (stmt->deferred)
4850  ereport(ERROR,
4851  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4852  errmsg("constraint \"%s\" is not deferrable",
4853  constraint->relname)));
4854  found = true;
4855  }
4856 
4857  systable_endscan(conscan);
4858 
4859  /*
4860  * Once we've found a matching constraint we do not search
4861  * later parts of the search path.
4862  */
4863  if (found)
4864  break;
4865  }
4866 
4867  list_free(namespacelist);
4868 
4869  /*
4870  * Not found ?
4871  */
4872  if (!found)
4873  ereport(ERROR,
4874  (errcode(ERRCODE_UNDEFINED_OBJECT),
4875  errmsg("constraint \"%s\" does not exist",
4876  constraint->relname)));
4877  }
4878 
4879  heap_close(conrel, AccessShareLock);
4880 
4881  /*
4882  * Now, locate the trigger(s) implementing each of these constraints,
4883  * and make a list of their OIDs.
4884  */
4886 
4887  foreach(lc, conoidlist)
4888  {
4889  Oid conoid = lfirst_oid(lc);
4890  bool found;
4891  ScanKeyData skey;
4892  SysScanDesc tgscan;
4893  HeapTuple htup;
4894 
4895  found = false;
4896 
4897  ScanKeyInit(&skey,
4899  BTEqualStrategyNumber, F_OIDEQ,
4900  ObjectIdGetDatum(conoid));
4901 
4902  tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
4903  NULL, 1, &skey);
4904 
4905  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
4906  {
4907  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
4908 
4909  /*
4910  * Silently skip triggers that are marked as non-deferrable in
4911  * pg_trigger. This is not an error condition, since a
4912  * deferrable RI constraint may have some non-deferrable
4913  * actions.
4914  */
4915  if (pg_trigger->tgdeferrable)
4916  tgoidlist = lappend_oid(tgoidlist,
4917  HeapTupleGetOid(htup));
4918 
4919  found = true;
4920  }
4921 
4922  systable_endscan(tgscan);
4923 
4924  /* Safety check: a deferrable constraint should have triggers */
4925  if (!found)
4926  elog(ERROR, "no triggers found for constraint with OID %u",
4927  conoid);
4928  }
4929 
4930  heap_close(tgrel, AccessShareLock);
4931 
4932  /*
4933  * Now we can set the trigger states of individual triggers for this
4934  * xact.
4935  */
4936  foreach(lc, tgoidlist)
4937  {
4938  Oid tgoid = lfirst_oid(lc);
4940  bool found = false;
4941  int i;
4942 
4943  for (i = 0; i < state->numstates; i++)
4944  {
4945  if (state->trigstates[i].sct_tgoid == tgoid)
4946  {
4947  state->trigstates[i].sct_tgisdeferred = stmt->deferred;
4948  found = true;
4949  break;
4950  }
4951  }
4952  if (!found)
4953  {
4955  SetConstraintStateAddItem(state, tgoid, stmt->deferred);
4956  }
4957  }
4958  }
4959 
4960  /*
4961  * SQL99 requires that when a constraint is set to IMMEDIATE, any deferred
4962  * checks against that constraint must be made when the SET CONSTRAINTS
4963  * command is executed -- i.e. the effects of the SET CONSTRAINTS command
4964  * apply retroactively. We've updated the constraints state, so scan the
4965  * list of previously deferred events to fire any that have now become
4966  * immediate.
4967  *
4968  * Obviously, if this was SET ... DEFERRED then it can't have converted
4969  * any unfired events to immediate, so we need do nothing in that case.
4970  */
4971  if (!stmt->deferred)
4972  {
4974  bool snapshot_set = false;
4975 
4976  while (afterTriggerMarkEvents(events, NULL, true))
4977  {
4978  CommandId firing_id = afterTriggers.firing_counter++;
4979 
4980  /*
4981  * Make sure a snapshot has been established in case trigger
4982  * functions need one. Note that we avoid setting a snapshot if
4983  * we don't find at least one trigger that has to be fired now.
4984  * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
4985  * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
4986  * at the start of a transaction it's not possible for any trigger
4987  * events to be queued yet.)
4988  */
4989  if (!snapshot_set)
4990  {
4992  snapshot_set = true;
4993  }
4994 
4995  /*
4996  * We can delete fired events if we are at top transaction level,
4997  * but we'd better not if inside a subtransaction, since the
4998  * subtransaction could later get rolled back.
4999  */
5000  if (afterTriggerInvokeEvents(events, firing_id, NULL,
5001  !IsSubTransaction()))
5002  break; /* all fired */
5003  }
5004 
5005  if (snapshot_set)
5007  }
5008 }
#define NIL
Definition: pg_list.h:69
uint32 CommandId
Definition: c.h:411
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2810
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:3220
#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:4702
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
Definition: trigger.c:3994
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
#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:300
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:3424
SetConstraintState state
Definition: trigger.c:3411
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
#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:4657
#define list_make1_oid(x1)
Definition: pg_list.h:151
Oid MyDatabaseId
Definition: globals.c:76
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
CommandId firing_counter
Definition: trigger.c:3410
#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:4378
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:3922
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
AfterTriggerEventList events
Definition: trigger.c:3412
#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:4141
static AfterTriggersData afterTriggers
Definition: trigger.c:3431
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:4682
TriggerDesc* CopyTriggerDesc ( TriggerDesc trigdesc)

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

1853 {
1854  TriggerDesc *newdesc;
1855  Trigger *trigger;
1856  int i;
1857 
1858  if (trigdesc == NULL || trigdesc->numtriggers <= 0)
1859  return NULL;
1860 
1861  newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
1862  memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
1863 
1864  trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
1865  memcpy(trigger, trigdesc->triggers,
1866  trigdesc->numtriggers * sizeof(Trigger));
1867  newdesc->triggers = trigger;
1868 
1869  for (i = 0; i < trigdesc->numtriggers; i++)
1870  {
1871  trigger->tgname = pstrdup(trigger->tgname);
1872  if (trigger->tgnattr > 0)
1873  {
1874  int16 *newattr;
1875 
1876  newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
1877  memcpy(newattr, trigger->tgattr,
1878  trigger->tgnattr * sizeof(int16));
1879  trigger->tgattr = newattr;
1880  }
1881  if (trigger->tgnargs > 0)
1882  {
1883  char **newargs;
1884  int16 j;
1885 
1886  newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
1887  for (j = 0; j < trigger->tgnargs; j++)
1888  newargs[j] = pstrdup(trigger->tgargs[j]);
1889  trigger->tgargs = newargs;
1890  }
1891  if (trigger->tgqual)
1892  trigger->tgqual = pstrdup(trigger->tgqual);
1893  if (trigger->tgoldtable)
1894  trigger->tgoldtable = pstrdup(trigger->tgoldtable);
1895  if (trigger->tgnewtable)
1896  trigger->tgnewtable = pstrdup(trigger->tgnewtable);
1897  trigger++;
1898  }
1899 
1900  return newdesc;
1901 }
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 138 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(), 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_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().

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

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

1524 {
1525  Relation tgrel;
1526  int nkeys;
1527  ScanKeyData keys[2];
1528  SysScanDesc tgscan;
1529  HeapTuple tuple;
1530  bool found;
1531  bool changed;
1532 
1533  /* Scan the relevant entries in pg_triggers */
1535 
1536  ScanKeyInit(&keys[0],
1538  BTEqualStrategyNumber, F_OIDEQ,
1540  if (tgname)
1541  {
1542  ScanKeyInit(&keys[1],
1544  BTEqualStrategyNumber, F_NAMEEQ,
1545  CStringGetDatum(tgname));
1546  nkeys = 2;
1547  }
1548  else
1549  nkeys = 1;
1550 
1551  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1552  NULL, nkeys, keys);
1553 
1554  found = changed = false;
1555 
1556  while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
1557  {
1558  Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
1559 
1560  if (oldtrig->tgisinternal)
1561  {
1562  /* system trigger ... ok to process? */
1563  if (skip_system)
1564  continue;
1565  if (!superuser())
1566  ereport(ERROR,
1567  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1568  errmsg("permission denied: \"%s\" is a system trigger",
1569  NameStr(oldtrig->tgname))));
1570  }
1571 
1572  found = true;
1573 
1574  if (oldtrig->tgenabled != fires_when)
1575  {
1576  /* need to change this one ... make a copy to scribble on */
1577  HeapTuple newtup = heap_copytuple(tuple);
1578  Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
1579 
1580  newtrig->tgenabled = fires_when;
1581 
1582  CatalogTupleUpdate(tgrel, &newtup->t_self, newtup);
1583 
1584  heap_freetuple(newtup);
1585 
1586  changed = true;
1587  }
1588 
1590  HeapTupleGetOid(tuple), 0);
1591  }
1592 
1593  systable_endscan(tgscan);
1594 
1595  heap_close(tgrel, RowExclusiveLock);
1596 
1597  if (tgname && !found)
1598  ereport(ERROR,
1599  (errcode(ERRCODE_UNDEFINED_OBJECT),
1600  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1601  tgname, RelationGetRelationName(rel))));
1602 
1603  /*
1604  * If we changed anything, broadcast a SI inval message to force each
1605  * backend (including our own!) to rebuild relation's relcache entry.
1606  * Otherwise they will fail to apply the change promptly.
1607  */
1608  if (changed)
1610 }
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:437
#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:417
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecARDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

Definition at line 2474 of file trigger.c.

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

Referenced by ExecDelete(), and ExecSimpleRelationDelete().

2477 {
2478  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2479 
2480  if (trigdesc &&
2481  (trigdesc->trig_delete_after_row || trigdesc->trig_delete_old_table))
2482  {
2483  HeapTuple trigtuple;
2484 
2485  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2486  if (fdw_trigtuple == NULL)
2487  trigtuple = GetTupleForTrigger(estate,
2488  NULL,
2489  relinfo,
2490  tupleid,
2492  NULL);
2493  else
2494  trigtuple = fdw_trigtuple;
2495 
2497  true, trigtuple, NULL, NIL, NULL);
2498  if (trigtuple != fdw_trigtuple)
2499  heap_freetuple(trigtuple);
2500  }
2501 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
bool trig_delete_after_row
Definition: reltrigger.h:66
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#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:2896
bool trig_delete_old_table
Definition: reltrigger.h:77
void ExecARInsertTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
List recheckIndexes 
)

Definition at line 2265 of file trigger.c.

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

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

2267 {
2268  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2269 
2270  if (trigdesc &&
2271  (trigdesc->trig_insert_after_row || trigdesc->trig_insert_new_table))
2273  true, NULL, trigtuple, recheckIndexes, NULL);
2274 }
bool trig_insert_new_table
Definition: reltrigger.h:74
bool trig_insert_after_row
Definition: reltrigger.h:56
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
void ExecARUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple,
HeapTuple  newtuple,
List recheckIndexes 
)

Definition at line 2734 of file trigger.c.

References AfterTriggerSaveEvent(), Assert, GetTupleForTrigger(), GetUpdatedColumns, heap_freetuple(), HeapTupleIsValid, ItemPointerIsValid, LockTupleExclusive, NULL, ResultRelInfo::ri_TrigDesc, TriggerDesc::trig_update_after_row, TriggerDesc::trig_update_new_table, TriggerDesc::trig_update_old_table, and TRIGGER_EVENT_UPDATE.

Referenced by ExecSimpleRelationUpdate(), and ExecUpdate().

2739 {
2740  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2741 
2742  if (trigdesc && (trigdesc->trig_update_after_row ||
2743  trigdesc->trig_update_old_table || trigdesc->trig_update_new_table))
2744  {
2745  HeapTuple trigtuple;
2746 
2747  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2748  if (fdw_trigtuple == NULL)
2749  trigtuple = GetTupleForTrigger(estate,
2750  NULL,
2751  relinfo,
2752  tupleid,
2754  NULL);
2755  else
2756  trigtuple = fdw_trigtuple;
2757 
2759  true, trigtuple, newtuple, recheckIndexes,
2760  GetUpdatedColumns(relinfo, estate));
2761  if (trigtuple != fdw_trigtuple)
2762  heap_freetuple(trigtuple);
2763  }
2764 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
bool trig_update_new_table
Definition: reltrigger.h:76
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
bool trig_update_old_table
Definition: reltrigger.h:75
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
bool trig_update_after_row
Definition: reltrigger.h:61
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#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:54
static HeapTuple GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot **newSlot)
Definition: trigger.c:2896
void ExecASDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2395 of file trigger.c.

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

Referenced by fireASTriggers().

2396 {
2397  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2398 
2399  if (trigdesc && trigdesc->trig_delete_after_statement)
2401  false, NULL, NULL, NIL, NULL);
2402 }
#define NIL
Definition: pg_list.h:69
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
bool trig_delete_after_statement
Definition: reltrigger.h:69
void ExecASInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2190 {
2191  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2192 
2193  if (trigdesc && trigdesc->trig_insert_after_statement)
2195  false, NULL, NULL, NIL, NULL);
2196 }
#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)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
void ExecASTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2885 of file trigger.c.

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

Referenced by ExecuteTruncate().

2886 {
2887  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2888 
2889  if (trigdesc && trigdesc->trig_truncate_after_statement)
2891  false, NULL, NULL, NIL, NULL);
2892 }
#define NIL
Definition: pg_list.h:69
bool trig_truncate_after_statement
Definition: reltrigger.h:72
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:55
void ExecASUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2606 of file trigger.c.

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

Referenced by fireASTriggers().

2607 {
2608  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2609 
2610  if (trigdesc && trigdesc->trig_update_after_statement)
2612  false, NULL, NULL, NIL,
2613  GetUpdatedColumns(relinfo, estate));
2614 }
#define NIL
Definition: pg_list.h:69
bool trig_update_after_statement
Definition: reltrigger.h:64
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, int event, bool row_trigger, HeapTuple oldtup, HeapTuple newtup, List *recheckIndexes, Bitmapset *modifiedCols)
Definition: trigger.c:5091
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#define NULL
Definition: c.h:229
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
bool ExecBRDeleteTriggers ( EState estate,
EPQState epqstate,
ResultRelInfo relinfo,
ItemPointer  tupleid,
HeapTuple  fdw_trigtuple 
)

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

2409 {
2410  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2411  bool result = true;
2412  TriggerData LocTriggerData;
2413  HeapTuple trigtuple;
2414  HeapTuple newtuple;
2415  TupleTableSlot *newSlot;
2416  int i;
2417 
2418  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2419  if (fdw_trigtuple == NULL)
2420  {
2421  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2422  LockTupleExclusive, &newSlot);
2423  if (trigtuple == NULL)
2424  return false;
2425  }
2426  else
2427  trigtuple = fdw_trigtuple;
2428 
2429  LocTriggerData.type = T_TriggerData;
2430  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2433  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2434  LocTriggerData.tg_newtuple = NULL;
2435  LocTriggerData.tg_oldtable = NULL;
2436  LocTriggerData.tg_newtable = NULL;
2437  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2438  for (i = 0; i < trigdesc->numtriggers; i++)
2439  {
2440  Trigger *trigger = &trigdesc->triggers[i];
2441 
2442  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2446  continue;
2447  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2448  NULL, trigtuple, NULL))
2449  continue;
2450 
2451  LocTriggerData.tg_trigtuple = trigtuple;
2452  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2453  LocTriggerData.tg_trigger = trigger;
2454  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2455  i,
2456  relinfo->ri_TrigFunctions,
2457  relinfo->ri_TrigInstrument,
2458  GetPerTupleMemoryContext(estate));
2459  if (newtuple == NULL)
2460  {
2461  result = false; /* tell caller to suppress delete */
2462  break;
2463  }
2464  if (newtuple != trigtuple)
2465  heap_freetuple(newtuple);
2466  }
2467  if (trigtuple != fdw_trigtuple)
2468  heap_freetuple(trigtuple);
2469 
2470  return result;
2471 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
Relation ri_RelationDesc
Definition: execnodes.h:374
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
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:381
#define InvalidBuffer
Definition: buf.h:25
return result
Definition: formatting.c:1632
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:60
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:378
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:3040
#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:461
#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:2896
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecBRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

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

2201 {
2202  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2203  HeapTuple slottuple = ExecMaterializeSlot(slot);
2204  HeapTuple newtuple = slottuple;
2205  HeapTuple oldtuple;
2206  TriggerData LocTriggerData;
2207  int i;
2208 
2209  LocTriggerData.type = T_TriggerData;
2210  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2213  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2214  LocTriggerData.tg_newtuple = NULL;
2215  LocTriggerData.tg_oldtable = NULL;
2216  LocTriggerData.tg_newtable = NULL;
2217  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2218  for (i = 0; i < trigdesc->numtriggers; i++)
2219  {
2220  Trigger *trigger = &trigdesc->triggers[i];
2221 
2222  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2226  continue;
2227  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2228  NULL, NULL, newtuple))
2229  continue;
2230 
2231  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2232  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2233  LocTriggerData.tg_trigger = trigger;
2234  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2235  i,
2236  relinfo->ri_TrigFunctions,
2237  relinfo->ri_TrigInstrument,
2238  GetPerTupleMemoryContext(estate));
2239  if (oldtuple != newtuple && oldtuple != slottuple)
2240  heap_freetuple(oldtuple);
2241  if (newtuple == NULL)
2242  return NULL; /* "do nothing" */
2243  }
2244 
2245  if (newtuple != slottuple)
2246  {
2247  /*
2248  * Return the modified tuple using the es_trig_tuple_slot. We assume
2249  * the tuple was allocated in per-tuple memory context, and therefore
2250  * will go away by itself. The tuple table slot should not try to
2251  * clear it.
2252  */
2253  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2254  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2255 
2256  if (newslot->tts_tupleDescriptor != tupdesc)
2257  ExecSetSlotDescriptor(newslot, tupdesc);
2258  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2259  slot = newslot;
2260  }
2261  return slot;
2262 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:374
#define RelationGetDescr(relation)
Definition: rel.h:429
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:381
#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:60
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:437
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
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:3040
#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:461
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
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 2617 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().

2622 {
2623  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2624  HeapTuple slottuple = ExecMaterializeSlot(slot);
2625  HeapTuple newtuple = slottuple;
2626  TriggerData LocTriggerData;
2627  HeapTuple trigtuple;
2628  HeapTuple oldtuple;
2629  TupleTableSlot *newSlot;
2630  int i;
2631  Bitmapset *updatedCols;
2632  LockTupleMode lockmode;
2633 
2634  /* Determine lock mode to use */
2635  lockmode = ExecUpdateLockMode(estate, relinfo);
2636 
2637  Assert(HeapTupleIsValid(fdw_trigtuple) ^ ItemPointerIsValid(tupleid));
2638  if (fdw_trigtuple == NULL)
2639  {
2640  /* get a copy of the on-disk tuple we are planning to update */
2641  trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2642  lockmode, &newSlot);
2643  if (trigtuple == NULL)
2644  return NULL; /* cancel the update action */
2645  }
2646  else
2647  {
2648  trigtuple = fdw_trigtuple;
2649  newSlot = NULL;
2650  }
2651 
2652  /*
2653  * In READ COMMITTED isolation level it's possible that target tuple was
2654  * changed due to concurrent update. In that case we have a raw subplan
2655  * output tuple in newSlot, and need to run it through the junk filter to
2656  * produce an insertable tuple.
2657  *
2658  * Caution: more than likely, the passed-in slot is the same as the
2659  * junkfilter's output slot, so we are clobbering the original value of
2660  * slottuple by doing the filtering. This is OK since neither we nor our
2661  * caller have any more interest in the prior contents of that slot.
2662  */
2663  if (newSlot != NULL)
2664  {
2665  slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
2666  slottuple = ExecMaterializeSlot(slot);
2667  newtuple = slottuple;
2668  }
2669 
2670 
2671  LocTriggerData.type = T_TriggerData;
2672  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2675  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2676  LocTriggerData.tg_oldtable = NULL;
2677  LocTriggerData.tg_newtable = NULL;
2678  updatedCols = GetUpdatedColumns(relinfo, estate);
2679  for (i = 0; i < trigdesc->numtriggers; i++)
2680  {
2681  Trigger *trigger = &trigdesc->triggers[i];
2682 
2683  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2687  continue;
2688  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2689  updatedCols, trigtuple, newtuple))
2690  continue;
2691 
2692  LocTriggerData.tg_trigtuple = trigtuple;
2693  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2694  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2695  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2696  LocTriggerData.tg_trigger = trigger;
2697  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2698  i,
2699  relinfo->ri_TrigFunctions,
2700  relinfo->ri_TrigInstrument,
2701  GetPerTupleMemoryContext(estate));
2702  if (oldtuple != newtuple && oldtuple != slottuple)
2703  heap_freetuple(oldtuple);
2704  if (newtuple == NULL)
2705  {
2706  if (trigtuple != fdw_trigtuple)
2707  heap_freetuple(trigtuple);
2708  return NULL; /* "do nothing" */
2709  }
2710  }
2711  if (trigtuple != fdw_trigtuple)
2712  heap_freetuple(trigtuple);
2713 
2714  if (newtuple != slottuple)
2715  {
2716  /*
2717  * Return the modified tuple using the es_trig_tuple_slot. We assume
2718  * the tuple was allocated in per-tuple memory context, and therefore
2719  * will go away by itself. The tuple table slot should not try to
2720  * clear it.
2721  */
2722  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2723  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2724 
2725  if (newslot->tts_tupleDescriptor != tupdesc)
2726  ExecSetSlotDescriptor(newslot, tupdesc);
2727  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2728  slot = newslot;
2729  }
2730  return slot;
2731 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
JunkFilter * ri_junkFilter
Definition: execnodes.h:388
Relation ri_RelationDesc
Definition: execnodes.h:374
#define RelationGetDescr(relation)
Definition: rel.h:429
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:381
#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:60
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:437
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
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:3040
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#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:2314
TriggerEvent tg_event
Definition: trigger.h:33
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:461
#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:2896
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
void ExecBSDeleteTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2344 {
2345  TriggerDesc *trigdesc;
2346  int i;
2347  TriggerData LocTriggerData;
2348 
2349  trigdesc = relinfo->ri_TrigDesc;
2350 
2351  if (trigdesc == NULL)
2352  return;
2353  if (!trigdesc->trig_delete_before_statement)
2354  return;
2355 
2356  LocTriggerData.type = T_TriggerData;
2357  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2359  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2360  LocTriggerData.tg_trigtuple = NULL;
2361  LocTriggerData.tg_newtuple = NULL;
2362  LocTriggerData.tg_oldtable = NULL;
2363  LocTriggerData.tg_newtable = NULL;
2364  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2365  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2366  for (i = 0; i < trigdesc->numtriggers; i++)
2367  {
2368  Trigger *trigger = &trigdesc->triggers[i];
2369  HeapTuple newtuple;
2370 
2371  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2375  continue;
2376  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2377  NULL, NULL, NULL))
2378  continue;
2379 
2380  LocTriggerData.tg_trigger = trigger;
2381  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2382  i,
2383  relinfo->ri_TrigFunctions,
2384  relinfo->ri_TrigInstrument,
2385  GetPerTupleMemoryContext(estate));
2386 
2387  if (newtuple)
2388  ereport(ERROR,
2389  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2390  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2391  }
2392 }
Relation ri_RelationDesc
Definition: execnodes.h:374
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
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:381
#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:60
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:378
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:3040
#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:461
#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:2043
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
void ExecBSInsertTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2138 {
2139  TriggerDesc *trigdesc;
2140  int i;
2141  TriggerData LocTriggerData;
2142 
2143  trigdesc = relinfo->ri_TrigDesc;
2144 
2145  if (trigdesc == NULL)
2146  return;
2147  if (!trigdesc->trig_insert_before_statement)
2148  return;
2149 
2150  LocTriggerData.type = T_TriggerData;
2151  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2153  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2154  LocTriggerData.tg_trigtuple = NULL;
2155  LocTriggerData.tg_newtuple = NULL;
2156  LocTriggerData.tg_oldtable = NULL;
2157  LocTriggerData.tg_newtable = NULL;
2158  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2159  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2160  for (i = 0; i < trigdesc->numtriggers; i++)
2161  {
2162  Trigger *trigger = &trigdesc->triggers[i];
2163  HeapTuple newtuple;
2164 
2165  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2169  continue;
2170  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2171  NULL, NULL, NULL))
2172  continue;
2173 
2174  LocTriggerData.tg_trigger = trigger;
2175  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2176  i,
2177  relinfo->ri_TrigFunctions,
2178  relinfo->ri_TrigInstrument,
2179  GetPerTupleMemoryContext(estate));
2180 
2181  if (newtuple)
2182  ereport(ERROR,
2183  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2184  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2185  }
2186 }
Relation ri_RelationDesc
Definition: execnodes.h:374
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:381
#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:60
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:378
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:3040
#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:461
#define TRIGGER_TYPE_BEFORE
Definition: pg_trigger.h:99
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
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:2043
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
void ExecBSTruncateTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2834 {
2835  TriggerDesc *trigdesc;
2836  int i;
2837  TriggerData LocTriggerData;
2838 
2839  trigdesc = relinfo->ri_TrigDesc;
2840 
2841  if (trigdesc == NULL)
2842  return;
2843  if (!trigdesc->trig_truncate_before_statement)
2844  return;
2845 
2846  LocTriggerData.type = T_TriggerData;
2847  LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
2849  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2850  LocTriggerData.tg_trigtuple = NULL;
2851  LocTriggerData.tg_newtuple = NULL;
2852  LocTriggerData.tg_oldtable = NULL;
2853  LocTriggerData.tg_newtable = NULL;
2854  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2855  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2856  for (i = 0; i < trigdesc->numtriggers; i++)
2857  {
2858  Trigger *trigger = &trigdesc->triggers[i];
2859  HeapTuple newtuple;
2860 
2861  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2865  continue;
2866  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2867  NULL, NULL, NULL))
2868  continue;
2869 
2870  LocTriggerData.tg_trigger = trigger;
2871  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2872  i,
2873  relinfo->ri_TrigFunctions,
2874  relinfo->ri_TrigInstrument,
2875  GetPerTupleMemoryContext(estate));
2876 
2877  if (newtuple)
2878  ereport(ERROR,
2879  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2880  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2881  }
2882 }
Relation ri_RelationDesc
Definition: execnodes.h:374
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:381
#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:60
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:378
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:3040
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_TRUNCATE
Definition: trigger.h:55
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:461
#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:2043
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
void ExecBSUpdateTriggers ( EState estate,
ResultRelInfo relinfo 
)

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

2552 {
2553  TriggerDesc *trigdesc;
2554  int i;
2555  TriggerData LocTriggerData;
2556  Bitmapset *updatedCols;
2557 
2558  trigdesc = relinfo->ri_TrigDesc;
2559 
2560  if (trigdesc == NULL)
2561  return;
2562  if (!trigdesc->trig_update_before_statement)
2563  return;
2564 
2565  updatedCols = GetUpdatedColumns(relinfo, estate);
2566 
2567  LocTriggerData.type = T_TriggerData;
2568  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2570  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2571  LocTriggerData.tg_trigtuple = NULL;
2572  LocTriggerData.tg_newtuple = NULL;
2573  LocTriggerData.tg_oldtable = NULL;
2574  LocTriggerData.tg_newtable = NULL;
2575  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2576  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2577  for (i = 0; i < trigdesc->numtriggers; i++)
2578  {
2579  Trigger *trigger = &trigdesc->triggers[i];
2580  HeapTuple newtuple;
2581 
2582  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2586  continue;
2587  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2588  updatedCols, NULL, NULL))
2589  continue;
2590 
2591  LocTriggerData.tg_trigger = trigger;
2592  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2593  i,
2594  relinfo->ri_TrigFunctions,
2595  relinfo->ri_TrigInstrument,
2596  GetPerTupleMemoryContext(estate));
2597 
2598  if (newtuple)
2599  ereport(ERROR,
2600  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2601  errmsg("BEFORE STATEMENT trigger cannot return a value")));
2602  }
2603 }
Relation ri_RelationDesc
Definition: execnodes.h:374
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:381
#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:60
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:378
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:3040
#define GetUpdatedColumns(relinfo, estate)
Definition: trigger.c:75
#define NULL
Definition: c.h:229
TriggerEvent tg_event
Definition: trigger.h:33
#define TRIGGER_EVENT_UPDATE
Definition: trigger.h:54
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:461
#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:2043
#define TRIGGER_TYPE_STATEMENT
Definition: pg_trigger.h:107
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
bool ExecIRDeleteTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple 
)

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

2506 {
2507  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2508  TriggerData LocTriggerData;
2509  HeapTuple rettuple;
2510  int i;
2511 
2512  LocTriggerData.type = T_TriggerData;
2513  LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
2516  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2517  LocTriggerData.tg_newtuple = NULL;
2518  LocTriggerData.tg_oldtable = NULL;
2519  LocTriggerData.tg_newtable = NULL;
2520  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2521  for (i = 0; i < trigdesc->numtriggers; i++)
2522  {
2523  Trigger *trigger = &trigdesc->triggers[i];
2524 
2525  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2529  continue;
2530  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2531  NULL, trigtuple, NULL))
2532  continue;
2533 
2534  LocTriggerData.tg_trigtuple = trigtuple;
2535  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2536  LocTriggerData.tg_trigger = trigger;
2537  rettuple = ExecCallTriggerFunc(&LocTriggerData,
2538  i,
2539  relinfo->ri_TrigFunctions,
2540  relinfo->ri_TrigInstrument,
2541  GetPerTupleMemoryContext(estate));
2542  if (rettuple == NULL)
2543  return false; /* Delete was suppressed */
2544  if (rettuple != trigtuple)
2545  heap_freetuple(rettuple);
2546  }
2547  return true;
2548 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
Relation ri_RelationDesc
Definition: execnodes.h:374
#define TRIGGER_TYPE_DELETE
Definition: pg_trigger.h:101
#define TRIGGER_EVENT_DELETE
Definition: trigger.h:53
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:381
#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:62
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:378
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:3040
#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:461
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecIRInsertTriggers ( EState estate,
ResultRelInfo relinfo,
TupleTableSlot slot 
)

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

2279 {
2280  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2281  HeapTuple slottuple = ExecMaterializeSlot(slot);
2282  HeapTuple newtuple = slottuple;
2283  HeapTuple oldtuple;
2284  TriggerData LocTriggerData;
2285  int i;
2286 
2287  LocTriggerData.type = T_TriggerData;
2288  LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
2291  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2292  LocTriggerData.tg_newtuple = NULL;
2293  LocTriggerData.tg_oldtable = NULL;
2294  LocTriggerData.tg_newtable = NULL;
2295  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2296  for (i = 0; i < trigdesc->numtriggers; i++)
2297  {
2298  Trigger *trigger = &trigdesc->triggers[i];
2299 
2300  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2304  continue;
2305  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2306  NULL, NULL, newtuple))
2307  continue;
2308 
2309  LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2310  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2311  LocTriggerData.tg_trigger = trigger;
2312  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2313  i,
2314  relinfo->ri_TrigFunctions,
2315  relinfo->ri_TrigInstrument,
2316  GetPerTupleMemoryContext(estate));
2317  if (oldtuple != newtuple && oldtuple != slottuple)
2318  heap_freetuple(oldtuple);
2319  if (newtuple == NULL)
2320  return NULL; /* "do nothing" */
2321  }
2322 
2323  if (newtuple != slottuple)
2324  {
2325  /*
2326  * Return the modified tuple using the es_trig_tuple_slot. We assume
2327  * the tuple was allocated in per-tuple memory context, and therefore
2328  * will go away by itself. The tuple table slot should not try to
2329  * clear it.
2330  */
2331  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2332  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2333 
2334  if (newslot->tts_tupleDescriptor != tupdesc)
2335  ExecSetSlotDescriptor(newslot, tupdesc);
2336  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2337  slot = newslot;
2338  }
2339  return slot;
2340 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:374
#define RelationGetDescr(relation)
Definition: rel.h:429
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:381
#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:62
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:437
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
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:3040
#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:461
#define TRIGGER_EVENT_INSERT
Definition: trigger.h:52
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
TupleTableSlot* ExecIRUpdateTriggers ( EState estate,
ResultRelInfo relinfo,
HeapTuple  trigtuple,
TupleTableSlot slot 
)

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

2769 {
2770  TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
2771  HeapTuple slottuple = ExecMaterializeSlot(slot);
2772  HeapTuple newtuple = slottuple;
2773  TriggerData LocTriggerData;
2774  HeapTuple oldtuple;
2775  int i;
2776 
2777  LocTriggerData.type = T_TriggerData;
2778  LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
2781  LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
2782  LocTriggerData.tg_oldtable = NULL;
2783  LocTriggerData.tg_newtable = NULL;
2784  for (i = 0; i < trigdesc->numtriggers; i++)
2785  {
2786  Trigger *trigger = &trigdesc->triggers[i];
2787 
2788  if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2792  continue;
2793  if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
2794  NULL, trigtuple, newtuple))
2795  continue;
2796 
2797  LocTriggerData.tg_trigtuple = trigtuple;
2798  LocTriggerData.tg_newtuple = oldtuple = newtuple;
2799  LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
2800  LocTriggerData.tg_newtuplebuf = InvalidBuffer;
2801  LocTriggerData.tg_trigger = trigger;
2802  newtuple = ExecCallTriggerFunc(&LocTriggerData,
2803  i,
2804  relinfo->ri_TrigFunctions,
2805  relinfo->ri_TrigInstrument,
2806  GetPerTupleMemoryContext(estate));
2807  if (oldtuple != newtuple && oldtuple != slottuple)
2808  heap_freetuple(oldtuple);
2809  if (newtuple == NULL)
2810  return NULL; /* "do nothing" */
2811  }
2812 
2813  if (newtuple != slottuple)
2814  {
2815  /*
2816  * Return the modified tuple using the es_trig_tuple_slot. We assume
2817  * the tuple was allocated in per-tuple memory context, and therefore
2818  * will go away by itself. The tuple table slot should not try to
2819  * clear it.
2820  */
2821  TupleTableSlot *newslot = estate->es_trig_tuple_slot;
2822  TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
2823 
2824  if (newslot->tts_tupleDescriptor != tupdesc)
2825  ExecSetSlotDescriptor(newslot, tupdesc);
2826  ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
2827  slot = newslot;
2828  }
2829  return slot;
2830 }
#define TRIGGER_EVENT_ROW
Definition: trigger.h:58
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:374
#define RelationGetDescr(relation)
Definition: rel.h:429
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:381
#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:62
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:437
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:378
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:3040
#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:54
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:461
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:2043
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:379
Relation tg_relation
Definition: trigger.h:34
void FreeTriggerDesc ( TriggerDesc trigdesc)

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

1908 {
1909  Trigger *trigger;
1910  int i;
1911 
1912  if (trigdesc == NULL)
1913  return;
1914 
1915  trigger = trigdesc->triggers;
1916  for (i = 0; i < trigdesc->numtriggers; i++)
1917  {
1918  pfree(trigger->tgname);
1919  if (trigger->tgnattr > 0)
1920  pfree(trigger->tgattr);
1921  if (trigger->tgnargs > 0)
1922  {
1923  while (--(trigger->tgnargs) >= 0)
1924  pfree(trigger->tgargs[trigger->tgnargs]);
1925  pfree(trigger->tgargs);
1926  }
1927  if (trigger->tgqual)
1928  pfree(trigger->tgqual);
1929  if (trigger->tgoldtable)
1930  pfree(trigger->tgoldtable);
1931  if (trigger->tgnewtable)
1932  pfree(trigger->tgnewtable);
1933  trigger++;
1934  }
1935  pfree(trigdesc->triggers);
1936  pfree(trigdesc);
1937 }
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 1294 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().

1295 {
1296  Relation tgrel;
1297  ScanKeyData skey[2];
1298  SysScanDesc tgscan;
1299  HeapTuple tup;
1300  Oid oid;
1301 
1302  /*
1303  * Find the trigger, verify permissions, set up object address
1304  */
1306 
1307  ScanKeyInit(&skey[0],
1309  BTEqualStrategyNumber, F_OIDEQ,
1310  ObjectIdGetDatum(relid));
1311  ScanKeyInit(&skey[1],
1313  BTEqualStrategyNumber, F_NAMEEQ,
1314  CStringGetDatum(trigname));
1315 
1316  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1317  NULL, 2, skey);
1318 
1319  tup = systable_getnext(tgscan);
1320 
1321  if (!HeapTupleIsValid(tup))
1322  {
1323  if (!missing_ok)
1324  ereport(ERROR,
1325  (errcode(ERRCODE_UNDEFINED_OBJECT),
1326  errmsg("trigger \"%s\" for table \"%s\" does not exist",
1327  trigname, get_rel_name(relid))));
1328  oid = InvalidOid;
1329  }
1330  else
1331  {
1332  oid = HeapTupleGetOid(tup);
1333  }
1334 
1335  systable_endscan(tgscan);
1336  heap_close(tgrel, AccessShareLock);
1337  return oid;
1338 }
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
void RelationBuildTriggers ( Relation  relation)

Definition at line 1624 of file trigger.c.

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

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

1625 {
1626  TriggerDesc *trigdesc;
1627  int numtrigs;
1628  int maxtrigs;
1629  Trigger *triggers;
1630  Relation tgrel;
1631  ScanKeyData skey;
1632  SysScanDesc tgscan;
1633  HeapTuple htup;
1634  MemoryContext oldContext;
1635  int i;
1636 
1637  /*
1638  * Allocate a working array to hold the triggers (the array is extended if
1639  * necessary)
1640  */
1641  maxtrigs = 16;
1642  triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
1643  numtrigs = 0;
1644 
1645  /*
1646  * Note: since we scan the triggers using TriggerRelidNameIndexId, we will
1647  * be reading the triggers in name order, except possibly during
1648  * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
1649  * ensures that triggers will be fired in name order.
1650  */
1651  ScanKeyInit(&skey,
1653  BTEqualStrategyNumber, F_OIDEQ,
1654  ObjectIdGetDatum(RelationGetRelid(relation)));
1655 
1657  tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
1658  NULL, 1, &skey);
1659 
1660  while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
1661  {
1662  Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
1663  Trigger *build;
1664  Datum datum;
1665  bool isnull;
1666 
1667  if (numtrigs >= maxtrigs)
1668  {
1669  maxtrigs *= 2;
1670  triggers = (Trigger *) repalloc(triggers, maxtrigs * sizeof(Trigger));
1671  }
1672  build = &(triggers[numtrigs]);
1673 
1674  build->tgoid = HeapTupleGetOid(htup);
1676  NameGetDatum(&pg_trigger->tgname)));
1677  build->tgfoid = pg_trigger->tgfoid;
1678  build->tgtype = pg_trigger->tgtype;
1679  build->tgenabled = pg_trigger->tgenabled;
1680  build->tgisinternal = pg_trigger->tgisinternal;
1681  build->tgconstrrelid = pg_trigger->tgconstrrelid;
1682  build->tgconstrindid = pg_trigger->tgconstrindid;
1683  build->tgconstraint = pg_trigger->tgconstraint;
1684  build->tgdeferrable = pg_trigger->tgdeferrable;
1685  build->tginitdeferred = pg_trigger->tginitdeferred;
1686  build->tgnargs = pg_trigger->tgnargs;
1687  /* tgattr is first var-width field, so OK to access directly */
1688  build->tgnattr = pg_trigger->tgattr.dim1;
1689  if (build->tgnattr > 0)
1690  {
1691  build->tgattr = (int16 *) palloc(build->tgnattr * sizeof(int16));
1692  memcpy(build->tgattr, &(pg_trigger->tgattr.values),
1693  build->tgnattr * sizeof(int16));
1694  }
1695  else
1696  build->tgattr = NULL;
1697  if (build->tgnargs > 0)
1698  {
1699  bytea *val;
1700  char *p;
1701 
1702  val = DatumGetByteaPP(fastgetattr(htup,
1704  tgrel->rd_att, &isnull));
1705  if (isnull)
1706  elog(ERROR, "tgargs is null in trigger for relation \"%s\"",
1707  RelationGetRelationName(relation));
1708  p = (char *) VARDATA_ANY(val);
1709  build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
1710  for (i = 0; i < build->tgnargs; i++)
1711  {
1712  build->tgargs[i] = pstrdup(p);
1713  p += strlen(p) + 1;
1714  }
1715  }
1716  else
1717  build->tgargs = NULL;
1718 
1720  tgrel->rd_att, &isnull);
1721  if (!isnull)
1722  build->tgoldtable =
1724  else
1725  build->tgoldtable = NULL;
1726 
1728  tgrel->rd_att, &isnull);
1729  if (!isnull)
1730  build->tgnewtable =
1732  else
1733  build->tgnewtable = NULL;
1734 
1735  datum = fastgetattr(htup, Anum_pg_trigger_tgqual,
1736  tgrel->rd_att, &isnull);
1737  if (!isnull)
1738  build->tgqual = TextDatumGetCString(datum);
1739