diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-19 16:36:08 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-19 16:36:08 +0000 |
commit | 201737168c4ed5b14313d111d8d746c7f072f24e (patch) | |
tree | 4936cf1082506bbf110dbf49d7e219f92e729c0d /src/backend/commands | |
parent | 87d00363cb46aa5f69ec4ed7874c356a0db8f25a (diff) | |
download | postgresql-201737168c4ed5b14313d111d8d746c7f072f24e.tar.gz postgresql-201737168c4ed5b14313d111d8d746c7f072f24e.zip |
pg_trigger's index on tgrelid is replaced by a unique index on
(tgrelid, tgname). This provides an additional check on trigger name
uniqueness per-table (which was already enforced by the code anyway).
With this change, RelationBuildTriggers will read the triggers in
order by tgname, since it's scanning using this index. Since a
predictable trigger ordering has been requested for some time, document
this behavior as a feature. Also document that rules fire in name
order, since yesterday's changes to pg_rewrite indexing cause that too.
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/comment.c | 23 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 6 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 86 |
3 files changed, 63 insertions, 52 deletions
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 07b14ca4fe2..63c023cf0e2 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1999-2001, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.42 2002/04/18 20:01:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.43 2002/04/19 16:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -753,7 +753,7 @@ CommentTrigger(List *qualname, char *comment) Relation pg_trigger, relation; HeapTuple triggertuple; - HeapScanDesc scan; + SysScanDesc scan; ScanKeyData entry[2]; Oid oid; @@ -774,17 +774,22 @@ CommentTrigger(List *qualname, char *comment) elog(ERROR, "you are not permitted to comment on trigger '%s' for relation '%s'", trigname, RelationGetRelationName(relation)); - /* Fetch the trigger oid from pg_trigger */ - + /* + * Fetch the trigger tuple from pg_trigger. There can be only one + * because of the unique index. + */ pg_trigger = heap_openr(TriggerRelationName, AccessShareLock); - ScanKeyEntryInitialize(&entry[0], 0x0, Anum_pg_trigger_tgrelid, + ScanKeyEntryInitialize(&entry[0], 0x0, + Anum_pg_trigger_tgrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); - ScanKeyEntryInitialize(&entry[1], 0x0, Anum_pg_trigger_tgname, + ScanKeyEntryInitialize(&entry[1], 0x0, + Anum_pg_trigger_tgname, F_NAMEEQ, CStringGetDatum(trigname)); - scan = heap_beginscan(pg_trigger, 0, SnapshotNow, 2, entry); - triggertuple = heap_getnext(scan, 0); + scan = systable_beginscan(pg_trigger, TriggerRelidNameIndex, true, + SnapshotNow, 2, entry); + triggertuple = systable_getnext(scan); /* If no trigger exists for the relation specified, notify user */ @@ -794,7 +799,7 @@ CommentTrigger(List *qualname, char *comment) oid = triggertuple->t_data->t_oid; - heap_endscan(scan); + systable_endscan(scan); /* Create the comments with the pg_trigger oid */ diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 8abd8cf80de..b0b73af76e4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.3 2002/04/18 20:01:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.4 2002/04/19 16:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2909,10 +2909,10 @@ update_ri_trigger_args(Oid relid, if (fk_scan) irel = index_openr(TriggerConstrRelidIndex); else - irel = index_openr(TriggerRelidIndex); + irel = index_openr(TriggerRelidNameIndex); ScanKeyEntryInitialize(&skey[0], 0x0, - 1, /* always column 1 of index */ + 1, /* column 1 of index in either case */ F_OIDEQ, ObjectIdGetDatum(relid)); idxtgscan = index_beginscan(irel, false, 1, skey); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 891b9f3cfba..c00b4bebac8 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.113 2002/04/12 20:38:24 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.114 2002/04/19 16:36:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -90,14 +90,15 @@ CreateTrigger(CreateTrigStmt *stmt) elog(ERROR, "permission denied"); /* - * If trigger is a constraint, user trigger name as constraint name + * If trigger is an RI constraint, use trigger name as constraint name * and build a unique trigger name instead. */ if (stmt->isconstraint) { constrname = stmt->trigname; + snprintf(constrtrigname, sizeof(constrtrigname), + "RI_ConstraintTrigger_%u", newoid()); stmt->trigname = constrtrigname; - sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid()); if (stmt->constrrel != NULL) constrrelid = RangeVarGetRelid(stmt->constrrel, false); @@ -139,15 +140,20 @@ CreateTrigger(CreateTrigStmt *stmt) } /* - * Scan pg_trigger for existing triggers on relation. NOTE that this - * is cool only because we have AccessExclusiveLock on the relation, - * so the trigger set won't be changing underneath us. + * Scan pg_trigger for existing triggers on relation. We do this mainly + * because we must count them; a secondary benefit is to give a nice + * error message if there's already a trigger of the same name. (The + * unique index on tgrelid/tgname would complain anyway.) + * + * NOTE that this is cool only because we have AccessExclusiveLock on the + * relation, so the trigger set won't be changing underneath us. */ tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); - ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, + ScanKeyEntryInitialize(&key, 0, + Anum_pg_trigger_tgrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); - tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true, + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { @@ -336,15 +342,20 @@ DropTrigger(Oid relid, const char *trigname) /* * Search pg_trigger, delete target trigger, count remaining triggers - * for relation. Note this is OK only because we have - * AccessExclusiveLock on the rel, so no one else is creating/deleting - * triggers on this rel at the same time. + * for relation. (Although we could fetch and delete the target + * trigger directly, we'd still have to scan the remaining triggers, + * so we may as well do both in one indexscan.) + * + * Note this is OK only because we have AccessExclusiveLock on the rel, + * so no one else is creating/deleting triggers on this rel at the same + * time. */ tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); - ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, + ScanKeyEntryInitialize(&key, 0, + Anum_pg_trigger_tgrelid, F_OIDEQ, ObjectIdGetDatum(relid)); - tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true, + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { @@ -409,10 +420,11 @@ RelationRemoveTriggers(Relation rel) bool found = false; tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); - ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, + ScanKeyEntryInitialize(&key, 0, + Anum_pg_trigger_tgrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); - tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true, + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = systable_getnext(tgscan))) @@ -462,7 +474,8 @@ RelationRemoveTriggers(Relation rel) /* * Also drop all constraint triggers referencing this relation */ - ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid, + ScanKeyEntryInitialize(&key, 0, + Anum_pg_trigger_tgconstrrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); tgscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true, @@ -502,7 +515,7 @@ RelationBuildTriggers(Relation relation) { TriggerDesc *trigdesc; int ntrigs = relation->rd_rel->reltriggers; - Trigger *triggers = NULL; + Trigger *triggers; int found = 0; Relation tgrel; ScanKeyData skey; @@ -511,6 +524,15 @@ RelationBuildTriggers(Relation relation) struct varlena *val; bool isnull; + triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext, + ntrigs * sizeof(Trigger)); + + /* + * Note: since we scan the triggers using TriggerRelidNameIndex, + * we will be reading the triggers in name order, except possibly + * during emergency-recovery operations (ie, IsIgnoringSystemIndexes). + * This in turn ensures that triggers will be fired in name order. + */ ScanKeyEntryInitialize(&skey, (bits16) 0x0, (AttrNumber) Anum_pg_trigger_tgrelid, @@ -518,7 +540,7 @@ RelationBuildTriggers(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); tgrel = heap_openr(TriggerRelationName, AccessShareLock); - tgscan = systable_beginscan(tgrel, TriggerRelidIndex, true, + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndex, true, SnapshotNow, 1, &skey); while (HeapTupleIsValid(htup = systable_getnext(tgscan))) @@ -526,16 +548,9 @@ RelationBuildTriggers(Relation relation) Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup); Trigger *build; - if (found == ntrigs) + if (found >= ntrigs) elog(ERROR, "RelationBuildTriggers: unexpected record found for rel %s", RelationGetRelationName(relation)); - - if (triggers == NULL) - triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext, - sizeof(Trigger)); - else - triggers = (Trigger *) repalloc(triggers, - (found + 1) * sizeof(Trigger)); build = &(triggers[found]); build->tgoid = htup->t_data->t_oid; @@ -730,6 +745,9 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) * 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. + * + * As of 7.3 we assume trigger set ordering is significant in the + * comparison; so we just compare corresponding slots of the two sets. */ if (trigdesc1 != NULL) { @@ -740,21 +758,9 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) for (i = 0; i < trigdesc1->numtriggers; i++) { Trigger *trig1 = trigdesc1->triggers + i; - Trigger *trig2 = NULL; + Trigger *trig2 = trigdesc2->triggers + i; - /* - * We can't assume that the triggers are always read from - * pg_trigger in the same order; so use the trigger OIDs to - * identify the triggers to compare. (We assume here that the - * same OID won't appear twice in either trigger set.) - */ - for (j = 0; j < trigdesc2->numtriggers; j++) - { - trig2 = trigdesc2->triggers + j; - if (trig1->tgoid == trig2->tgoid) - break; - } - if (j >= trigdesc2->numtriggers) + if (trig1->tgoid != trig2->tgoid) return false; if (strcmp(trig1->tgname, trig2->tgname) != 0) return false; |