diff options
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r-- | src/backend/commands/trigger.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 0cc33aae6b6..b84731126a1 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 - * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.249 2009/07/28 02:56:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.250 2009/07/29 20:56:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,7 +63,8 @@ static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, Instrumentation *instr, MemoryContext per_tuple_context); static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, - bool row_trigger, HeapTuple oldtup, HeapTuple newtup); + bool row_trigger, HeapTuple oldtup, HeapTuple newtup, + List *recheckIndexes); /* @@ -77,6 +78,10 @@ static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, * indexOid, if nonzero, is the OID of an index associated with the constraint. * We do nothing with this except store it into pg_trigger.tgconstrindid. * + * prefix is NULL for user-created triggers. For internally generated + * constraint triggers, it is a prefix string to use in building the + * trigger name. (stmt->trigname is the constraint name in such cases.) + * * If checkPermissions is true we require ACL_TRIGGER permissions on the * relation. If not, the caller already checked permissions. (This is * currently redundant with constraintOid being zero, but it's clearer to @@ -87,7 +92,7 @@ static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, */ Oid CreateTrigger(CreateTrigStmt *stmt, - Oid constraintOid, Oid indexOid, + Oid constraintOid, Oid indexOid, const char *prefix, bool checkPermissions) { int16 tgtype; @@ -216,20 +221,20 @@ CreateTrigger(CreateTrigStmt *stmt, trigoid = GetNewOid(tgrel); /* - * If trigger is for an RI constraint, the passed-in name is the - * constraint name; save that and build a unique trigger name to avoid - * collisions with user-selected trigger names. + * If trigger is for a constraint, stmt->trigname is the constraint + * name; save that and build a unique trigger name based on the supplied + * prefix, to avoid collisions with user-selected trigger names. */ - if (OidIsValid(constraintOid)) + if (prefix != NULL) { snprintf(constrtrigname, sizeof(constrtrigname), - "RI_ConstraintTrigger_%u", trigoid); + "%s_%u", prefix, trigoid); trigname = constrtrigname; constrname = stmt->trigname; } else if (stmt->isconstraint) { - /* constraint trigger: trigger name is also constraint name */ + /* user constraint trigger: trigger name is also constraint name */ trigname = stmt->trigname; constrname = stmt->trigname; } @@ -1650,7 +1655,7 @@ ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo) if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_INSERT] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT, - false, NULL, NULL); + false, NULL, NULL, NIL); } HeapTuple @@ -1706,13 +1711,13 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, - HeapTuple trigtuple) + HeapTuple trigtuple, List *recheckIndexes) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; if (trigdesc && trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_INSERT, - true, NULL, trigtuple); + true, NULL, trigtuple, recheckIndexes); } void @@ -1781,7 +1786,7 @@ ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo) if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_DELETE] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, - false, NULL, NULL); + false, NULL, NULL, NIL); } bool @@ -1858,7 +1863,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, tupleid, NULL); AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_DELETE, - true, trigtuple, NULL); + true, trigtuple, NULL, NIL); heap_freetuple(trigtuple); } } @@ -1929,7 +1934,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo) if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_UPDATE] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, - false, NULL, NULL); + false, NULL, NULL, NIL); } HeapTuple @@ -1999,7 +2004,8 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, - ItemPointer tupleid, HeapTuple newtuple) + ItemPointer tupleid, HeapTuple newtuple, + List *recheckIndexes) { TriggerDesc *trigdesc = relinfo->ri_TrigDesc; @@ -2009,7 +2015,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, tupleid, NULL); AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_UPDATE, - true, trigtuple, newtuple); + true, trigtuple, newtuple, recheckIndexes); heap_freetuple(trigtuple); } } @@ -2080,7 +2086,7 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo) if (trigdesc && trigdesc->n_after_statement[TRIGGER_EVENT_TRUNCATE] > 0) AfterTriggerSaveEvent(relinfo, TRIGGER_EVENT_TRUNCATE, - false, NULL, NULL); + false, NULL, NULL, NIL); } @@ -3793,15 +3799,18 @@ AfterTriggerPendingOnRel(Oid relid) /* ---------- * AfterTriggerSaveEvent() * - * Called by ExecA[RS]...Triggers() to add the event to the queue. + * Called by ExecA[RS]...Triggers() to queue up the triggers that should + * be fired for an event. * - * NOTE: should be called only if we've determined that an event must - * be added to the queue. + * NOTE: this is called whenever there are any triggers associated with + * the event (even if they are disabled). This function decides which + * triggers actually need to be queued. * ---------- */ static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger, - HeapTuple oldtup, HeapTuple newtup) + HeapTuple oldtup, HeapTuple newtup, + List *recheckIndexes) { Relation rel = relinfo->ri_RelationDesc; TriggerDesc *trigdesc = relinfo->ri_TrigDesc; @@ -3962,6 +3971,17 @@ AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event, bool row_trigger, } /* + * If the trigger is a deferred unique constraint check trigger, + * only queue it if the unique constraint was potentially violated, + * which we know from index insertion time. + */ + if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK) + { + if (!list_member_oid(recheckIndexes, trigger->tgconstrindid)) + continue; /* Uniqueness definitely not violated */ + } + + /* * Fill in event structure and add it to the current query's queue. */ new_shared.ats_event = |