aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c260
1 files changed, 228 insertions, 32 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 5c56a7ccfc9..c9e2d87ff9e 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.139 2002/11/13 00:39:46 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.140 2002/11/23 03:59:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,7 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
FmgrInfo *finfo,
MemoryContext per_tuple_context);
static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
- HeapTuple oldtup, HeapTuple newtup);
+ bool row_trigger, HeapTuple oldtup, HeapTuple newtup);
static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
Relation rel, TriggerDesc *trigdesc, FmgrInfo *finfo,
MemoryContext per_tuple_context);
@@ -147,12 +147,14 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
{
/* foreign key constraint trigger */
- aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_REFERENCES);
+ aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+ ACL_REFERENCES);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, RelationGetRelationName(rel));
if (constrrelid != InvalidOid)
{
- aclresult = pg_class_aclcheck(constrrelid, GetUserId(), ACL_REFERENCES);
+ aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
+ ACL_REFERENCES);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_rel_name(constrrelid));
}
@@ -160,7 +162,8 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
else
{
/* real trigger */
- aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_TRIGGER);
+ aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+ ACL_TRIGGER);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, RelationGetRelationName(rel));
}
@@ -195,10 +198,8 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
TRIGGER_SETT_BEFORE(tgtype);
if (stmt->row)
TRIGGER_SETT_ROW(tgtype);
- else
- elog(ERROR, "CreateTrigger: STATEMENT triggers are unimplemented, yet");
- for (i = 0; i < 3 && stmt->actions[i]; i++)
+ for (i = 0; i < 2 && stmt->actions[i]; i++)
{
switch (stmt->actions[i])
{
@@ -1131,6 +1132,64 @@ ExecCallTriggerFunc(TriggerData *trigdata,
return (HeapTuple) DatumGetPointer(result);
}
+void
+ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc;
+ int ntrigs;
+ int *tgindx;
+ int i;
+ TriggerData LocTriggerData;
+
+ trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc == NULL)
+ return;
+
+ ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_INSERT];
+ tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_INSERT];
+
+ if (ntrigs == 0)
+ return;
+
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
+ TRIGGER_EVENT_BEFORE;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigtuple = NULL;
+ for (i = 0; i < ntrigs; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ HeapTuple newtuple;
+
+ if (!trigger->tgenabled)
+ continue;
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
+ GetPerTupleMemoryContext(estate));
+
+ if (newtuple)
+ elog(ERROR, "BEFORE STATEMENT trigger cannot return a value.");
+ }
+}
+
+void
+ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_INSERT] > 0)
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
+ false, NULL, NULL);
+}
+
HeapTuple
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple)
@@ -1149,7 +1208,9 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));
LocTriggerData.type = T_TriggerData;
- LocTriggerData.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
+ LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
+ TRIGGER_EVENT_ROW |
+ TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
@@ -1177,9 +1238,67 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
+ if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT,
- NULL, trigtuple);
+ true, NULL, trigtuple);
+}
+
+void
+ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc;
+ int ntrigs;
+ int *tgindx;
+ int i;
+ TriggerData LocTriggerData;
+
+ trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc == NULL)
+ return;
+
+ ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_DELETE];
+ tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_DELETE];
+
+ if (ntrigs == 0)
+ return;
+
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
+ TRIGGER_EVENT_BEFORE;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigtuple = NULL;
+ for (i = 0; i < ntrigs; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ HeapTuple newtuple;
+
+ if (!trigger->tgenabled)
+ continue;
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
+ GetPerTupleMemoryContext(estate));
+
+ if (newtuple)
+ elog(ERROR, "BEFORE STATEMENT trigger cannot return a value.");
+ }
+}
+
+void
+ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_DELETE] > 0)
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
+ false, NULL, NULL);
}
bool
@@ -1205,7 +1324,9 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));
LocTriggerData.type = T_TriggerData;
- LocTriggerData.tg_event = TRIGGER_EVENT_DELETE | TRIGGER_EVENT_ROW | TRIGGER_EVENT_BEFORE;
+ LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
+ TRIGGER_EVENT_ROW |
+ TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
for (i = 0; i < ntrigs; i++)
@@ -1235,17 +1356,75 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, NULL);
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE,
- trigtuple, NULL);
+ true, trigtuple, NULL);
heap_freetuple(trigtuple);
}
}
+void
+ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc;
+ int ntrigs;
+ int *tgindx;
+ int i;
+ TriggerData LocTriggerData;
+
+ trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc == NULL)
+ return;
+
+ ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_UPDATE];
+ tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_UPDATE];
+
+ if (ntrigs == 0)
+ return;
+
+ /* Allocate cache space for fmgr lookup info, if not done yet */
+ if (relinfo->ri_TrigFunctions == NULL)
+ relinfo->ri_TrigFunctions = (FmgrInfo *)
+ palloc0(trigdesc->numtriggers * sizeof(FmgrInfo));
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
+ TRIGGER_EVENT_BEFORE;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_trigtuple = NULL;
+ for (i = 0; i < ntrigs; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ HeapTuple newtuple;
+
+ if (!trigger->tgenabled)
+ continue;
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ relinfo->ri_TrigFunctions + tgindx[i],
+ GetPerTupleMemoryContext(estate));
+
+ if (newtuple)
+ elog(ERROR, "BEFORE STATEMENT trigger cannot return a value.");
+ }
+}
+
+void
+ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+
+ if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_UPDATE] > 0)
+ DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
+ false, NULL, NULL);
+}
+
HeapTuple
ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid, HeapTuple newtuple)
@@ -1265,8 +1444,8 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
return NULL;
/*
- * In READ COMMITTED isolevel it's possible that newtuple was changed
- * due to concurrent update.
+ * In READ COMMITTED isolation level it's possible that newtuple was
+ * changed due to concurrent update.
*/
if (newSlot != NULL)
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
@@ -1306,13 +1485,13 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
+ if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, relinfo,
tupleid, NULL);
DeferredTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE,
- trigtuple, newtuple);
+ true, trigtuple, newtuple);
heap_freetuple(trigtuple);
}
}
@@ -1344,7 +1523,7 @@ ltrmark:;
case HeapTupleSelfUpdated:
/* treat it as deleted; do not process */
ReleaseBuffer(buffer);
- return (NULL);
+ return NULL;
case HeapTupleMayBeUpdated:
break;
@@ -1371,12 +1550,12 @@ ltrmark:;
* if tuple was deleted or PlanQual failed for updated
* tuple - we have not process this tuple!
*/
- return (NULL);
+ return NULL;
default:
ReleaseBuffer(buffer);
elog(ERROR, "Unknown status %u from heap_mark4update", test);
- return (NULL);
+ return NULL;
}
}
else
@@ -1466,7 +1645,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
/*
* Not deferrable triggers (i.e. normal AFTER ROW triggers and
- * constraints declared NOT DEFERRABLE, the state is allways false.
+ * constraints declared NOT DEFERRABLE, the state is always false.
*/
if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
return false;
@@ -1590,7 +1769,7 @@ DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
*/
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
- TRIGGER_EVENT_ROW;
+ (event->dte_event & TRIGGER_EVENT_ROW);
LocTriggerData.tg_relation = rel;
LocTriggerData.tg_trigger = NULL;
@@ -2139,7 +2318,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ----------
*/
static void
-DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
+DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger,
HeapTuple oldtup, HeapTuple newtup)
{
Relation rel = relinfo->ri_RelationDesc;
@@ -2152,7 +2331,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
int *tgindx;
ItemPointerData oldctid;
ItemPointerData newctid;
- TriggerData LocTriggerData;
if (deftrig_cxt == NULL)
elog(ERROR,
@@ -2175,14 +2353,25 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
*/
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
- ntriggers = trigdesc->n_after_row[event];
- tgindx = trigdesc->tg_after_row[event];
+ if (row_trigger)
+ {
+ ntriggers = trigdesc->n_after_row[event];
+ tgindx = trigdesc->tg_after_row[event];
+ }
+ else
+ {
+ ntriggers = trigdesc->n_after_statement[event];
+ tgindx = trigdesc->tg_after_statement[event];
+ }
+
new_size = offsetof(DeferredTriggerEventData, dte_item[0]) +
ntriggers * sizeof(DeferredTriggerEventItem);
new_event = (DeferredTriggerEvent) palloc(new_size);
new_event->dte_next = NULL;
new_event->dte_event = event & TRIGGER_EVENT_OPMASK;
+ if (row_trigger)
+ new_event->dte_event |= TRIGGER_EVENT_ROW;
new_event->dte_relid = rel->rd_id;
ItemPointerCopy(&oldctid, &(new_event->dte_oldctid));
ItemPointerCopy(&newctid, &(new_event->dte_newctid));
@@ -2190,15 +2379,21 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
for (i = 0; i < ntriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ DeferredTriggerEventItem *ev_item = &(new_event->dte_item[i]);
- new_event->dte_item[i].dti_tgoid = trigger->tgoid;
- new_event->dte_item[i].dti_state =
+ ev_item->dti_tgoid = trigger->tgoid;
+ ev_item->dti_state =
((trigger->tgdeferrable) ?
TRIGGER_DEFERRED_DEFERRABLE : 0) |
((trigger->tginitdeferred) ?
- TRIGGER_DEFERRED_INITDEFERRED : 0) |
- ((trigdesc->n_before_row[event] > 0) ?
- TRIGGER_DEFERRED_HAS_BEFORE : 0);
+ TRIGGER_DEFERRED_INITDEFERRED : 0);
+
+ if (row_trigger && (trigdesc->n_before_row[event] > 0))
+ ev_item->dti_state |= TRIGGER_DEFERRED_HAS_BEFORE;
+ else if (!row_trigger && (trigdesc->n_before_statement[event] > 0))
+ {
+ ev_item->dti_state |= TRIGGER_DEFERRED_HAS_BEFORE;
+ }
}
MemoryContextSwitchTo(oldcxt);
@@ -2219,6 +2414,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
bool is_ri_trigger;
bool key_unchanged;
+ TriggerData LocTriggerData;
/*
* We are interested in RI_FKEY triggers only.