aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-10-10 13:43:33 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2010-10-10 13:45:07 -0400
commit2ec993a7cbdd8e251817ac6bbc9a704ce8346f73 (patch)
tree1568fb4b00b6fa7997755113a3d0bbfead45c1fb /src/backend/commands/trigger.c
parentf7b15b5098ee89a2628129fbbef9901bded9d27b (diff)
downloadpostgresql-2ec993a7cbdd8e251817ac6bbc9a704ce8346f73.tar.gz
postgresql-2ec993a7cbdd8e251817ac6bbc9a704ce8346f73.zip
Support triggers on views.
This patch adds the SQL-standard concept of an INSTEAD OF trigger, which is fired instead of performing a physical insert/update/delete. The trigger function is passed the entire old and/or new rows of the view, and must figure out what to do to the underlying tables to implement the update. So this feature can be used to implement updatable views using trigger programming style rather than rule hacking. In passing, this patch corrects the names of some columns in the information_schema.triggers view. It seems the SQL committee renamed them somewhere between SQL:99 and SQL:2003. Dean Rasheed, reviewed by Bernd Helmle; some additional hacking by me.
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c577
1 files changed, 338 insertions, 239 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f0b32ddd37f..d69fdcf410a 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -63,7 +63,7 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
/* Local function prototypes */
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
-static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
+static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger);
static HeapTuple GetTupleForTrigger(EState *estate,
EPQState *epqstate,
ResultRelInfo *relinfo,
@@ -150,10 +150,45 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
*/
rel = heap_openrv(stmt->relation, ShareRowExclusiveLock);
- if (rel->rd_rel->relkind != RELKIND_RELATION)
+ /*
+ * Triggers must be on tables or views, and there are additional
+ * relation-type-specific restrictions.
+ */
+ if (rel->rd_rel->relkind == RELKIND_RELATION)
+ {
+ /* Tables can't have INSTEAD OF triggers */
+ if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+ stmt->timing != TRIGGER_TYPE_AFTER)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is a table",
+ RelationGetRelationName(rel)),
+ errdetail("Tables cannot have INSTEAD OF triggers.")));
+ }
+ else if (rel->rd_rel->relkind == RELKIND_VIEW)
+ {
+ /*
+ * Views can have INSTEAD OF triggers (which we check below are
+ * row-level), or statement-level BEFORE/AFTER triggers.
+ */
+ if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is a view",
+ RelationGetRelationName(rel)),
+ errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
+ /* Disallow TRUNCATE triggers on VIEWs */
+ if (TRIGGER_FOR_TRUNCATE(stmt->events))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is a view",
+ RelationGetRelationName(rel)),
+ errdetail("Views cannot have TRUNCATE triggers.")));
+ }
+ else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table",
+ errmsg("\"%s\" is not a table or view",
RelationGetRelationName(rel))));
if (!allowSystemTableMods && IsSystemRelation(rel))
@@ -186,10 +221,9 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
/* Compute tgtype */
TRIGGER_CLEAR_TYPE(tgtype);
- if (stmt->before)
- TRIGGER_SETT_BEFORE(tgtype);
if (stmt->row)
TRIGGER_SETT_ROW(tgtype);
+ tgtype |= stmt->timing;
tgtype |= stmt->events;
/* Disallow ROW-level TRUNCATE triggers */
@@ -198,6 +232,23 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
+ /* INSTEAD triggers must be row-level, and can't have WHEN or columns */
+ if (TRIGGER_FOR_INSTEAD(tgtype))
+ {
+ if (!TRIGGER_FOR_ROW(tgtype))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
+ if (stmt->whenClause)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
+ if (stmt->columns != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("INSTEAD OF triggers cannot have column lists")));
+ }
+
/*
* Parse the WHEN clause, if any
*/
@@ -1031,10 +1082,11 @@ RemoveTriggerById(Oid trigOid)
rel = heap_open(relid, ShareRowExclusiveLock);
- if (rel->rd_rel->relkind != RELKIND_RELATION)
+ if (rel->rd_rel->relkind != RELKIND_RELATION &&
+ rel->rd_rel->relkind != RELKIND_VIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is not a table",
+ errmsg("\"%s\" is not a table or view",
RelationGetRelationName(rel))));
if (!allowSystemTableMods && IsSystemRelation(rel))
@@ -1472,7 +1524,7 @@ RelationBuildTriggers(Relation relation)
trigdesc->triggers = triggers;
trigdesc->numtriggers = numtrigs;
for (i = 0; i < numtrigs; i++)
- InsertTrigger(trigdesc, &(triggers[i]), i);
+ SetTriggerFlags(trigdesc, &(triggers[i]));
/* Copy completed trigdesc into cache storage */
oldContext = MemoryContextSwitchTo(CacheMemoryContext);
@@ -1484,84 +1536,65 @@ RelationBuildTriggers(Relation relation)
}
/*
- * Insert the given trigger into the appropriate index list(s) for it
- *
- * To simplify storage management, we allocate each index list at the max
- * possible size (trigdesc->numtriggers) if it's used at all. This does
- * not waste space permanently since we're only building a temporary
- * trigdesc at this point.
+ * Update the TriggerDesc's hint flags to include the specified trigger
*/
static void
-InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx)
+SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger)
{
- uint16 *n;
- int **t,
- **tp;
-
- if (TRIGGER_FOR_ROW(trigger->tgtype))
- {
- /* ROW trigger */
- if (TRIGGER_FOR_BEFORE(trigger->tgtype))
- {
- n = trigdesc->n_before_row;
- t = trigdesc->tg_before_row;
- }
- else
- {
- n = trigdesc->n_after_row;
- t = trigdesc->tg_after_row;
- }
- }
- else
- {
- /* STATEMENT trigger */
- if (TRIGGER_FOR_BEFORE(trigger->tgtype))
- {
- n = trigdesc->n_before_statement;
- t = trigdesc->tg_before_statement;
- }
- else
- {
- n = trigdesc->n_after_statement;
- t = trigdesc->tg_after_statement;
- }
- }
-
- if (TRIGGER_FOR_INSERT(trigger->tgtype))
- {
- tp = &(t[TRIGGER_EVENT_INSERT]);
- if (*tp == NULL)
- *tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));
- (*tp)[n[TRIGGER_EVENT_INSERT]] = indx;
- (n[TRIGGER_EVENT_INSERT])++;
- }
-
- if (TRIGGER_FOR_DELETE(trigger->tgtype))
- {
- tp = &(t[TRIGGER_EVENT_DELETE]);
- if (*tp == NULL)
- *tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));
- (*tp)[n[TRIGGER_EVENT_DELETE]] = indx;
- (n[TRIGGER_EVENT_DELETE])++;
- }
-
- if (TRIGGER_FOR_UPDATE(trigger->tgtype))
- {
- tp = &(t[TRIGGER_EVENT_UPDATE]);
- if (*tp == NULL)
- *tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));
- (*tp)[n[TRIGGER_EVENT_UPDATE]] = indx;
- (n[TRIGGER_EVENT_UPDATE])++;
- }
-
- if (TRIGGER_FOR_TRUNCATE(trigger->tgtype))
- {
- tp = &(t[TRIGGER_EVENT_TRUNCATE]);
- if (*tp == NULL)
- *tp = (int *) palloc(trigdesc->numtriggers * sizeof(int));
- (*tp)[n[TRIGGER_EVENT_TRUNCATE]] = indx;
- (n[TRIGGER_EVENT_TRUNCATE])++;
- }
+ int16 tgtype = trigger->tgtype;
+
+ trigdesc->trig_insert_before_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
+ trigdesc->trig_insert_after_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
+ trigdesc->trig_insert_instead_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_INSERT);
+ trigdesc->trig_insert_before_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
+ trigdesc->trig_insert_after_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
+ trigdesc->trig_update_before_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
+ trigdesc->trig_update_after_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
+ trigdesc->trig_update_instead_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_UPDATE);
+ trigdesc->trig_update_before_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
+ trigdesc->trig_update_after_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
+ trigdesc->trig_delete_before_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
+ trigdesc->trig_delete_after_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
+ trigdesc->trig_delete_instead_row |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_DELETE);
+ trigdesc->trig_delete_before_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
+ trigdesc->trig_delete_after_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
+ /* there are no row-level truncate triggers */
+ trigdesc->trig_truncate_before_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_TRUNCATE);
+ trigdesc->trig_truncate_after_statement |=
+ TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_AFTER, TRIGGER_TYPE_TRUNCATE);
}
/*
@@ -1573,9 +1606,6 @@ TriggerDesc *
CopyTriggerDesc(TriggerDesc *trigdesc)
{
TriggerDesc *newdesc;
- uint16 *n;
- int **t,
- *tnew;
Trigger *trigger;
int i;
@@ -1617,59 +1647,6 @@ CopyTriggerDesc(TriggerDesc *trigdesc)
trigger++;
}
- n = newdesc->n_before_statement;
- t = newdesc->tg_before_statement;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- {
- if (n[i] > 0)
- {
- tnew = (int *) palloc(n[i] * sizeof(int));
- memcpy(tnew, t[i], n[i] * sizeof(int));
- t[i] = tnew;
- }
- else
- t[i] = NULL;
- }
- n = newdesc->n_before_row;
- t = newdesc->tg_before_row;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- {
- if (n[i] > 0)
- {
- tnew = (int *) palloc(n[i] * sizeof(int));
- memcpy(tnew, t[i], n[i] * sizeof(int));
- t[i] = tnew;
- }
- else
- t[i] = NULL;
- }
- n = newdesc->n_after_row;
- t = newdesc->tg_after_row;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- {
- if (n[i] > 0)
- {
- tnew = (int *) palloc(n[i] * sizeof(int));
- memcpy(tnew, t[i], n[i] * sizeof(int));
- t[i] = tnew;
- }
- else
- t[i] = NULL;
- }
- n = newdesc->n_after_statement;
- t = newdesc->tg_after_statement;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- {
- if (n[i] > 0)
- {
- tnew = (int *) palloc(n[i] * sizeof(int));
- memcpy(tnew, t[i], n[i] * sizeof(int));
- t[i] = tnew;
- }
- else
- t[i] = NULL;
- }
-
return newdesc;
}
@@ -1679,30 +1656,12 @@ CopyTriggerDesc(TriggerDesc *trigdesc)
void
FreeTriggerDesc(TriggerDesc *trigdesc)
{
- int **t;
Trigger *trigger;
int i;
if (trigdesc == NULL)
return;
- t = trigdesc->tg_before_statement;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- if (t[i] != NULL)
- pfree(t[i]);
- t = trigdesc->tg_before_row;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- if (t[i] != NULL)
- pfree(t[i]);
- t = trigdesc->tg_after_row;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- if (t[i] != NULL)
- pfree(t[i]);
- t = trigdesc->tg_after_statement;
- for (i = 0; i < TRIGGER_NUM_EVENT_CLASSES; i++)
- if (t[i] != NULL)
- pfree(t[i]);
-
trigger = trigdesc->triggers;
for (i = 0; i < trigdesc->numtriggers; i++)
{
@@ -1734,9 +1693,8 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
j;
/*
- * We need not examine the "index" data, just the trigger array itself; if
- * we have the same triggers with the same types, the derived index data
- * should match.
+ * We need not examine the hint flags, just the trigger array itself; if
+ * we have the same triggers with the same types, the flags should match.
*
* As of 7.3 we assume trigger set ordering is significant in the
* comparison; so we just compare corresponding slots of the two sets.
@@ -1889,8 +1847,6 @@ void
ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc;
- int ntrigs;
- int *tgindx;
int i;
TriggerData LocTriggerData;
@@ -1898,11 +1854,7 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
if (trigdesc == NULL)
return;
-
- ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_INSERT];
- tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_INSERT];
-
- if (ntrigs == 0)
+ if (!trigdesc->trig_insert_before_statement)
return;
LocTriggerData.type = T_TriggerData;
@@ -1913,18 +1865,23 @@ ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
HeapTuple newtuple;
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_INSERT))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, NULL))
continue;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -1941,7 +1898,7 @@ ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_INSERT] > 0)
+ if (trigdesc && trigdesc->trig_insert_after_statement)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
false, NULL, NULL, NIL, NULL);
}
@@ -1951,8 +1908,6 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
- int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
HeapTuple newtuple = trigtuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
@@ -1965,10 +1920,15 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_INSERT))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, newtuple))
continue;
@@ -1977,7 +1937,7 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -1995,17 +1955,61 @@ ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
+ if (trigdesc && trigdesc->trig_insert_after_row)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
true, NULL, trigtuple, recheckIndexes, NULL);
}
+HeapTuple
+ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
+ HeapTuple trigtuple)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ HeapTuple newtuple = trigtuple;
+ HeapTuple oldtuple;
+ TriggerData LocTriggerData;
+ int i;
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
+ TRIGGER_EVENT_ROW |
+ TRIGGER_EVENT_INSTEAD;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+ for (i = 0; i < trigdesc->numtriggers; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[i];
+
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD,
+ TRIGGER_TYPE_INSERT))
+ continue;
+ if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
+ NULL, NULL, newtuple))
+ continue;
+
+ LocTriggerData.tg_trigtuple = oldtuple = newtuple;
+ LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_trigger = trigger;
+ newtuple = ExecCallTriggerFunc(&LocTriggerData,
+ i,
+ relinfo->ri_TrigFunctions,
+ relinfo->ri_TrigInstrument,
+ GetPerTupleMemoryContext(estate));
+ if (oldtuple != newtuple && oldtuple != trigtuple)
+ heap_freetuple(oldtuple);
+ if (newtuple == NULL)
+ break;
+ }
+ return newtuple;
+}
+
void
ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc;
- int ntrigs;
- int *tgindx;
int i;
TriggerData LocTriggerData;
@@ -2013,11 +2017,7 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
if (trigdesc == NULL)
return;
-
- ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_DELETE];
- tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_DELETE];
-
- if (ntrigs == 0)
+ if (!trigdesc->trig_delete_before_statement)
return;
LocTriggerData.type = T_TriggerData;
@@ -2028,18 +2028,23 @@ ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
HeapTuple newtuple;
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_DELETE))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, NULL))
continue;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -2056,7 +2061,7 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_DELETE] > 0)
+ if (trigdesc && trigdesc->trig_delete_after_statement)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
false, NULL, NULL, NIL, NULL);
}
@@ -2067,8 +2072,6 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
ItemPointer tupleid)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
- int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
bool result = true;
TriggerData LocTriggerData;
HeapTuple trigtuple;
@@ -2088,10 +2091,15 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_DELETE))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, trigtuple, NULL))
continue;
@@ -2100,7 +2108,7 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -2123,7 +2131,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ if (trigdesc && trigdesc->trig_delete_after_row)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
tupleid, NULL);
@@ -2134,12 +2142,55 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
}
}
+bool
+ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
+ HeapTuple trigtuple)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ TriggerData LocTriggerData;
+ HeapTuple rettuple;
+ int i;
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
+ TRIGGER_EVENT_ROW |
+ TRIGGER_EVENT_INSTEAD;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ LocTriggerData.tg_newtuple = NULL;
+ LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+ for (i = 0; i < trigdesc->numtriggers; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[i];
+
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD,
+ TRIGGER_TYPE_DELETE))
+ continue;
+ if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
+ NULL, trigtuple, NULL))
+ continue;
+
+ LocTriggerData.tg_trigtuple = trigtuple;
+ LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_trigger = trigger;
+ rettuple = ExecCallTriggerFunc(&LocTriggerData,
+ i,
+ relinfo->ri_TrigFunctions,
+ relinfo->ri_TrigInstrument,
+ GetPerTupleMemoryContext(estate));
+ if (rettuple == NULL)
+ return false; /* Delete was suppressed */
+ if (rettuple != trigtuple)
+ heap_freetuple(rettuple);
+ }
+ return true;
+}
+
void
ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc;
- int ntrigs;
- int *tgindx;
int i;
TriggerData LocTriggerData;
Bitmapset *modifiedCols;
@@ -2148,11 +2199,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
if (trigdesc == NULL)
return;
-
- ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_UPDATE];
- tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_UPDATE];
-
- if (ntrigs == 0)
+ if (!trigdesc->trig_update_before_statement)
return;
modifiedCols = GetModifiedColumns(relinfo, estate);
@@ -2165,18 +2212,23 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
HeapTuple newtuple;
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_UPDATE))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
modifiedCols, NULL, NULL))
continue;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -2193,7 +2245,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_UPDATE] > 0)
+ if (trigdesc && trigdesc->trig_update_after_statement)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
false, NULL, NULL, NIL,
GetModifiedColumns(relinfo, estate));
@@ -2205,8 +2257,6 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
ItemPointer tupleid, HeapTuple newtuple)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- int ntrigs = trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
- int *tgindx = trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
TriggerData LocTriggerData;
HeapTuple trigtuple;
HeapTuple oldtuple;
@@ -2235,10 +2285,15 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_UPDATE))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
modifiedCols, trigtuple, newtuple))
continue;
@@ -2249,7 +2304,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -2269,7 +2324,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
+ if (trigdesc && trigdesc->trig_update_after_row)
{
HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
tupleid, NULL);
@@ -2281,12 +2336,57 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
}
}
+HeapTuple
+ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
+ HeapTuple oldtuple, HeapTuple newtuple)
+{
+ TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
+ TriggerData LocTriggerData;
+ HeapTuple intuple = newtuple;
+ HeapTuple rettuple;
+ int i;
+
+ LocTriggerData.type = T_TriggerData;
+ LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
+ TRIGGER_EVENT_ROW |
+ TRIGGER_EVENT_INSTEAD;
+ LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
+ for (i = 0; i < trigdesc->numtriggers; i++)
+ {
+ Trigger *trigger = &trigdesc->triggers[i];
+
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_ROW,
+ TRIGGER_TYPE_INSTEAD,
+ TRIGGER_TYPE_UPDATE))
+ continue;
+ if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
+ NULL, oldtuple, newtuple))
+ continue;
+
+ LocTriggerData.tg_trigtuple = oldtuple;
+ LocTriggerData.tg_newtuple = newtuple;
+ LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_newtuplebuf = InvalidBuffer;
+ LocTriggerData.tg_trigger = trigger;
+ rettuple = ExecCallTriggerFunc(&LocTriggerData,
+ i,
+ relinfo->ri_TrigFunctions,
+ relinfo->ri_TrigInstrument,
+ GetPerTupleMemoryContext(estate));
+ if (newtuple != rettuple && newtuple != intuple)
+ heap_freetuple(newtuple);
+ newtuple = rettuple;
+ if (newtuple == NULL)
+ break;
+ }
+ return newtuple;
+}
+
void
ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc;
- int ntrigs;
- int *tgindx;
int i;
TriggerData LocTriggerData;
@@ -2294,11 +2394,7 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
if (trigdesc == NULL)
return;
-
- ntrigs = trigdesc->n_before_statement[TRIGGER_EVENT_TRUNCATE];
- tgindx = trigdesc->tg_before_statement[TRIGGER_EVENT_TRUNCATE];
-
- if (ntrigs == 0)
+ if (!trigdesc->trig_truncate_before_statement)
return;
LocTriggerData.type = T_TriggerData;
@@ -2309,18 +2405,23 @@ ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
- for (i = 0; i < ntrigs; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
HeapTuple newtuple;
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ TRIGGER_TYPE_STATEMENT,
+ TRIGGER_TYPE_BEFORE,
+ TRIGGER_TYPE_TRUNCATE))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, NULL))
continue;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
- tgindx[i],
+ i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
@@ -2337,7 +2438,7 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_TRUNCATE] > 0)
+ if (trigdesc && trigdesc->trig_truncate_after_statement)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_TRUNCATE,
false, NULL, NULL, NIL, NULL);
}
@@ -4250,9 +4351,9 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
AfterTriggerEventData new_event;
AfterTriggerSharedData new_shared;
+ int tgtype_event;
+ int tgtype_level;
int i;
- int ntriggers;
- int *tgindx;
/*
* Check state. We use normal tests not Asserts because it is possible to
@@ -4275,6 +4376,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
switch (event)
{
case TRIGGER_EVENT_INSERT:
+ tgtype_event = TRIGGER_TYPE_INSERT;
if (row_trigger)
{
Assert(oldtup == NULL);
@@ -4291,6 +4393,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
}
break;
case TRIGGER_EVENT_DELETE:
+ tgtype_event = TRIGGER_TYPE_DELETE;
if (row_trigger)
{
Assert(oldtup != NULL);
@@ -4307,6 +4410,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
}
break;
case TRIGGER_EVENT_UPDATE:
+ tgtype_event = TRIGGER_TYPE_UPDATE;
if (row_trigger)
{
Assert(oldtup != NULL);
@@ -4324,6 +4428,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
}
break;
case TRIGGER_EVENT_TRUNCATE:
+ tgtype_event = TRIGGER_TYPE_TRUNCATE;
Assert(oldtup == NULL);
Assert(newtup == NULL);
ItemPointerSetInvalid(&(new_event.ate_ctid1));
@@ -4331,27 +4436,21 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
break;
default:
elog(ERROR, "invalid after-trigger event code: %d", event);
+ tgtype_event = 0; /* keep compiler quiet */
break;
}
- /*
- * Scan the appropriate set of triggers
- */
- 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];
- }
+ tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
- for (i = 0; i < ntriggers; i++)
+ for (i = 0; i < trigdesc->numtriggers; i++)
{
- Trigger *trigger = &trigdesc->triggers[tgindx[i]];
+ Trigger *trigger = &trigdesc->triggers[i];
+ if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
+ tgtype_level,
+ TRIGGER_TYPE_AFTER,
+ tgtype_event))
+ continue;
if (!TriggerEnabled(estate, relinfo, trigger, event,
modifiedCols, oldtup, newtup))
continue;