mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
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.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.91 2002/04/18 20:01:09 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.92 2002/04/19 16:36:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -74,7 +74,7 @@ char *Name_pg_shadow_indices[Num_pg_shadow_indices] =
|
||||
char *Name_pg_statistic_indices[Num_pg_statistic_indices] =
|
||||
{StatisticRelidAttnumIndex};
|
||||
char *Name_pg_trigger_indices[Num_pg_trigger_indices] =
|
||||
{TriggerRelidIndex, TriggerConstrNameIndex, TriggerConstrRelidIndex, TriggerOidIndex};
|
||||
{TriggerRelidNameIndex, TriggerConstrNameIndex, TriggerConstrRelidIndex, TriggerOidIndex};
|
||||
char *Name_pg_type_indices[Num_pg_type_indices] =
|
||||
{TypeNameNspIndex, TypeOidIndex};
|
||||
char *Name_pg_description_indices[Num_pg_description_indices] =
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
74
src/backend/utils/cache/relcache.c
vendored
74
src/backend/utils/cache/relcache.c
vendored
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.161 2002/04/18 20:01:09 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.162 2002/04/19 16:36:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -635,10 +635,10 @@ RelationBuildRuleLock(Relation relation)
|
||||
{
|
||||
MemoryContext rulescxt;
|
||||
MemoryContext oldcxt;
|
||||
HeapTuple pg_rewrite_tuple;
|
||||
Relation pg_rewrite_desc;
|
||||
TupleDesc pg_rewrite_tupdesc;
|
||||
SysScanDesc pg_rewrite_scan;
|
||||
HeapTuple rewrite_tuple;
|
||||
Relation rewrite_desc;
|
||||
TupleDesc rewrite_tupdesc;
|
||||
SysScanDesc rewrite_scan;
|
||||
ScanKeyData key;
|
||||
RuleLock *rulelock;
|
||||
int numlocks;
|
||||
@ -657,7 +657,7 @@ RelationBuildRuleLock(Relation relation)
|
||||
relation->rd_rulescxt = rulescxt;
|
||||
|
||||
/*
|
||||
* form an array to hold the rewrite rules (the array is extended if
|
||||
* allocate an array to hold the rewrite rules (the array is extended if
|
||||
* necessary)
|
||||
*/
|
||||
maxlocks = 4;
|
||||
@ -675,18 +675,22 @@ RelationBuildRuleLock(Relation relation)
|
||||
|
||||
/*
|
||||
* open pg_rewrite and begin a scan
|
||||
*
|
||||
* Note: since we scan the rules using RewriteRelRulenameIndex,
|
||||
* we will be reading the rules in name order, except possibly
|
||||
* during emergency-recovery operations (ie, IsIgnoringSystemIndexes).
|
||||
* This in turn ensures that rules will be fired in name order.
|
||||
*/
|
||||
pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
|
||||
pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
|
||||
pg_rewrite_scan = systable_beginscan(pg_rewrite_desc,
|
||||
RewriteRelRulenameIndex,
|
||||
criticalRelcachesBuilt,
|
||||
SnapshotNow,
|
||||
1, &key);
|
||||
rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock);
|
||||
rewrite_tupdesc = RelationGetDescr(rewrite_desc);
|
||||
rewrite_scan = systable_beginscan(rewrite_desc,
|
||||
RewriteRelRulenameIndex,
|
||||
true, SnapshotNow,
|
||||
1, &key);
|
||||
|
||||
while (HeapTupleIsValid(pg_rewrite_tuple = systable_getnext(pg_rewrite_scan)))
|
||||
while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
|
||||
{
|
||||
Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(pg_rewrite_tuple);
|
||||
Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
|
||||
bool isnull;
|
||||
Datum ruleaction;
|
||||
Datum rule_evqual;
|
||||
@ -697,7 +701,7 @@ RelationBuildRuleLock(Relation relation)
|
||||
rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
|
||||
sizeof(RewriteRule));
|
||||
|
||||
rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
|
||||
rule->ruleId = rewrite_tuple->t_data->t_oid;
|
||||
|
||||
rule->event = rewrite_form->ev_type - '0';
|
||||
rule->attrno = rewrite_form->ev_attr;
|
||||
@ -705,9 +709,9 @@ RelationBuildRuleLock(Relation relation)
|
||||
|
||||
/* Must use heap_getattr to fetch ev_qual and ev_action */
|
||||
|
||||
ruleaction = heap_getattr(pg_rewrite_tuple,
|
||||
ruleaction = heap_getattr(rewrite_tuple,
|
||||
Anum_pg_rewrite_ev_action,
|
||||
pg_rewrite_tupdesc,
|
||||
rewrite_tupdesc,
|
||||
&isnull);
|
||||
Assert(!isnull);
|
||||
ruleaction_str = DatumGetCString(DirectFunctionCall1(textout,
|
||||
@ -717,13 +721,13 @@ RelationBuildRuleLock(Relation relation)
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
pfree(ruleaction_str);
|
||||
|
||||
rule_evqual = heap_getattr(pg_rewrite_tuple,
|
||||
rule_evqual = heap_getattr(rewrite_tuple,
|
||||
Anum_pg_rewrite_ev_qual,
|
||||
pg_rewrite_tupdesc,
|
||||
rewrite_tupdesc,
|
||||
&isnull);
|
||||
Assert(!isnull);
|
||||
rule_evqual_str = DatumGetCString(DirectFunctionCall1(textout,
|
||||
rule_evqual));
|
||||
rule_evqual));
|
||||
oldcxt = MemoryContextSwitchTo(rulescxt);
|
||||
rule->qual = (Node *) stringToNode(rule_evqual_str);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
@ -741,8 +745,8 @@ RelationBuildRuleLock(Relation relation)
|
||||
/*
|
||||
* end the scan and close the attribute relation
|
||||
*/
|
||||
systable_endscan(pg_rewrite_scan);
|
||||
heap_close(pg_rewrite_desc, AccessShareLock);
|
||||
systable_endscan(rewrite_scan);
|
||||
heap_close(rewrite_desc, AccessShareLock);
|
||||
|
||||
/*
|
||||
* form a RuleLock and insert into relation
|
||||
@ -764,9 +768,13 @@ RelationBuildRuleLock(Relation relation)
|
||||
static bool
|
||||
equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* As of 7.3 we assume the rule ordering is repeatable,
|
||||
* because RelationBuildRuleLock should read 'em in a
|
||||
* consistent order. So just compare corresponding slots.
|
||||
*/
|
||||
if (rlock1 != NULL)
|
||||
{
|
||||
if (rlock2 == NULL)
|
||||
@ -776,21 +784,9 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
|
||||
for (i = 0; i < rlock1->numLocks; i++)
|
||||
{
|
||||
RewriteRule *rule1 = rlock1->rules[i];
|
||||
RewriteRule *rule2 = NULL;
|
||||
RewriteRule *rule2 = rlock2->rules[i];
|
||||
|
||||
/*
|
||||
* We can't assume that the rules are always read from
|
||||
* pg_rewrite in the same order; so use the rule OIDs to
|
||||
* identify the rules to compare. (We assume here that the
|
||||
* same OID won't appear twice in either ruleset.)
|
||||
*/
|
||||
for (j = 0; j < rlock2->numLocks; j++)
|
||||
{
|
||||
rule2 = rlock2->rules[j];
|
||||
if (rule1->ruleId == rule2->ruleId)
|
||||
break;
|
||||
}
|
||||
if (j >= rlock2->numLocks)
|
||||
if (rule1->ruleId != rule2->ruleId)
|
||||
return false;
|
||||
if (rule1->event != rule2->event)
|
||||
return false;
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.118 2002/04/18 20:01:10 tgl Exp $
|
||||
* $Id: catversion.h,v 1.119 2002/04/19 16:36:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200204181
|
||||
#define CATALOG_VERSION_NO 200204182
|
||||
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: indexing.h,v 1.65 2002/04/18 20:01:10 tgl Exp $
|
||||
* $Id: indexing.h,v 1.66 2002/04/19 16:36:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -86,7 +86,7 @@
|
||||
#define StatisticRelidAttnumIndex "pg_statistic_relid_att_index"
|
||||
#define TriggerConstrNameIndex "pg_trigger_tgconstrname_index"
|
||||
#define TriggerConstrRelidIndex "pg_trigger_tgconstrrelid_index"
|
||||
#define TriggerRelidIndex "pg_trigger_tgrelid_index"
|
||||
#define TriggerRelidNameIndex "pg_trigger_tgrelid_tgname_index"
|
||||
#define TriggerOidIndex "pg_trigger_oid_index"
|
||||
#define TypeNameNspIndex "pg_type_typname_nsp_index"
|
||||
#define TypeOidIndex "pg_type_oid_index"
|
||||
@ -182,9 +182,11 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_
|
||||
DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index on pg_shadow using btree(usesysid int4_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));
|
||||
/* This following index is not used for a cache and is not unique */
|
||||
DECLARE_INDEX(pg_trigger_tgconstrname_index on pg_trigger using btree(tgconstrname name_ops));
|
||||
/* This following index is not used for a cache and is not unique */
|
||||
DECLARE_INDEX(pg_trigger_tgconstrrelid_index on pg_trigger using btree(tgconstrrelid oid_ops));
|
||||
DECLARE_INDEX(pg_trigger_tgrelid_index on pg_trigger using btree(tgrelid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index on pg_trigger using btree(tgrelid oid_ops, tgname name_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_trigger_oid_index on pg_trigger using btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_type_oid_index on pg_type using btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index on pg_type using btree(typname name_ops, typnamespace oid_ops));
|
||||
|
@ -899,7 +899,7 @@ delete from pktable where base1=2;
|
||||
ERROR: <unnamed> referential integrity violation - key in pktable still referenced from pktable
|
||||
-- fails (1,1) is being referenced (twice)
|
||||
update pktable set base1=3 where base1=1;
|
||||
ERROR: <unnamed> referential integrity violation - key in pktable still referenced from pktable
|
||||
ERROR: <unnamed> referential integrity violation - key referenced from pktable not found in pktable
|
||||
-- this sequence of two deletes will work, since after the first there will be no (2,*) references
|
||||
delete from pktable where base2=2;
|
||||
delete from pktable where base1=2;
|
||||
|
Reference in New Issue
Block a user