1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-25 20:23:07 +03:00

Add system catalog columns pg_constraint.conindid and pg_trigger.tgconstrindid.

conindid is the index supporting a constraint.  We can use this not only for
unique/primary-key constraints, but also foreign-key constraints, which
depend on the unique index that constrains the referenced columns.
tgconstrindid is just copied from the constraint's conindid field, or is
zero for triggers not associated with constraints.

This is mainly intended as infrastructure for upcoming patches, but it has
some virtue in itself, since it exposes a relationship that you formerly
had to grovel in pg_depend to determine.  I simplified one information_schema
view accordingly.  (There is a pg_dump query that could also use conindid,
but I left it alone because it wasn't clear it'd get any faster.)
This commit is contained in:
Tom Lane
2009-07-28 02:56:31 +00:00
parent 36942504fc
commit c1b9ec24ef
15 changed files with 120 additions and 78 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.291 2009/07/20 02:42:27 adunstan Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.292 2009/07/28 02:56:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -152,6 +152,7 @@ typedef struct NewConstraint
char *name; /* Constraint name, or NULL if none */
ConstrType contype; /* CHECK or FOREIGN */
Oid refrelid; /* PK rel, if FOREIGN */
Oid refindid; /* OID of PK's index, if FOREIGN */
Oid conid; /* OID of pg_constraint entry, if FOREIGN */
Node *qual; /* Check expr or FkConstraint struct */
List *qualstate; /* Execution state for CHECK */
@@ -247,9 +248,10 @@ static Oid transformFkeyCheckAttrs(Relation pkrel,
Oid *opclasses);
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
static void validateForeignKeyConstraint(FkConstraint *fkconstraint,
Relation rel, Relation pkrel, Oid constraintOid);
Relation rel, Relation pkrel,
Oid pkindOid, Oid constraintOid);
static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
Oid constraintOid);
Oid constraintOid, Oid indexOid);
static void ATController(Relation rel, List *cmds, bool recurse);
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
bool recurse, bool recursing);
@@ -2915,6 +2917,7 @@ ATRewriteTables(List **wqueue)
refrel = heap_open(con->refrelid, RowShareLock);
validateForeignKeyConstraint(fkconstraint, rel, refrel,
con->refindid,
con->conid);
heap_close(refrel, NoLock);
@@ -4819,6 +4822,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
numfks,
InvalidOid, /* not a domain
* constraint */
indexOid,
RelationGetRelid(pkrel),
pkattnum,
pfeqoperators,
@@ -4828,7 +4832,6 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
fkconstraint->fk_upd_action,
fkconstraint->fk_del_action,
fkconstraint->fk_matchtype,
indexOid,
NULL, /* no check constraint */
NULL,
NULL,
@@ -4838,7 +4841,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
/*
* Create the triggers that will enforce the constraint.
*/
createForeignKeyTriggers(rel, fkconstraint, constrOid);
createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid);
/*
* Tell Phase 3 to check that the constraint is satisfied by existing rows
@@ -4852,6 +4855,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
newcon->name = fkconstraint->constr_name;
newcon->contype = CONSTR_FOREIGN;
newcon->refrelid = RelationGetRelid(pkrel);
newcon->refindid = indexOid;
newcon->conid = constrOid;
newcon->qual = (Node *) fkconstraint;
@@ -5141,6 +5145,7 @@ static void
validateForeignKeyConstraint(FkConstraint *fkconstraint,
Relation rel,
Relation pkrel,
Oid pkindOid,
Oid constraintOid)
{
HeapScanDesc scan;
@@ -5156,6 +5161,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
trig.tgisconstraint = TRUE;
trig.tgconstrrelid = RelationGetRelid(pkrel);
trig.tgconstrindid = pkindOid;
trig.tgconstraint = constraintOid;
trig.tgdeferrable = FALSE;
trig.tginitdeferred = FALSE;
@@ -5209,7 +5215,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
static void
CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
Oid constraintOid, bool on_insert)
Oid constraintOid, Oid indexOid, bool on_insert)
{
CreateTrigStmt *fk_trigger;
@@ -5237,7 +5243,7 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
fk_trigger->constrrel = fkconstraint->pktable;
fk_trigger->args = NIL;
(void) CreateTrigger(fk_trigger, constraintOid, false);
(void) CreateTrigger(fk_trigger, constraintOid, indexOid, false);
/* Make changes-so-far visible */
CommandCounterIncrement();
@@ -5248,7 +5254,7 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
*/
static void
createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
Oid constraintOid)
Oid constraintOid, Oid indexOid)
{
RangeVar *myRel;
CreateTrigStmt *fk_trigger;
@@ -5267,8 +5273,8 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
* Build and execute a CREATE CONSTRAINT TRIGGER statement for the CHECK
* action for both INSERTs and UPDATEs on the referencing table.
*/
CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, true);
CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, false);
CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true);
CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false);
/*
* Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
@@ -5316,7 +5322,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
}
fk_trigger->args = NIL;
(void) CreateTrigger(fk_trigger, constraintOid, false);
(void) CreateTrigger(fk_trigger, constraintOid, indexOid, false);
/* Make changes-so-far visible */
CommandCounterIncrement();
@@ -5367,7 +5373,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
}
fk_trigger->args = NIL;
(void) CreateTrigger(fk_trigger, constraintOid, false);
(void) CreateTrigger(fk_trigger, constraintOid, indexOid, false);
}
/*

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.248 2009/06/18 01:27:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.249 2009/07/28 02:56:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -74,6 +74,9 @@ static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event,
* be made to link the trigger to that constraint. constraintOid is zero when
* executing a user-entered CREATE TRIGGER command.
*
* 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.
*
* 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
@@ -83,7 +86,9 @@ static void AfterTriggerSaveEvent(ResultRelInfo *relinfo, int event,
* but a foreign-key constraint. This is a kluge for backwards compatibility.
*/
Oid
CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid, bool checkPermissions)
CreateTrigger(CreateTrigStmt *stmt,
Oid constraintOid, Oid indexOid,
bool checkPermissions)
{
int16 tgtype;
int2vector *tgattr;
@@ -276,6 +281,7 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid, bool checkPermissions)
values[Anum_pg_trigger_tgconstrname - 1] = DirectFunctionCall1(namein,
CStringGetDatum(constrname));
values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
@@ -410,13 +416,15 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid, bool checkPermissions)
referenced.objectId = RelationGetRelid(rel);
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
if (constrrelid != InvalidOid)
if (OidIsValid(constrrelid))
{
referenced.classId = RelationRelationId;
referenced.objectId = constrrelid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
}
/* Not possible to have an index dependency in this case */
Assert(!OidIsValid(indexOid));
}
/* Keep lock on target rel until end of xact */
@@ -1122,6 +1130,7 @@ RelationBuildTriggers(Relation relation)
build->tgenabled = pg_trigger->tgenabled;
build->tgisconstraint = pg_trigger->tgisconstraint;
build->tgconstrrelid = pg_trigger->tgconstrrelid;
build->tgconstrindid = pg_trigger->tgconstrindid;
build->tgconstraint = pg_trigger->tgconstraint;
build->tgdeferrable = pg_trigger->tgdeferrable;
build->tginitdeferred = pg_trigger->tginitdeferred;
@@ -1467,6 +1476,8 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return false;
if (trig1->tgconstrrelid != trig2->tgconstrrelid)
return false;
if (trig1->tgconstrindid != trig2->tgconstrindid)
return false;
if (trig1->tgconstraint != trig2->tgconstraint)
return false;
if (trig1->tgdeferrable != trig2->tgdeferrable)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.135 2009/07/16 06:33:42 petere Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.136 2009/07/28 02:56:30 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -2293,6 +2293,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
NULL,
0,
domainOid, /* domain constraint */
InvalidOid, /* no associated index */
InvalidOid, /* Foreign key fields */
NULL,
NULL,
@@ -2302,7 +2303,6 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
' ',
' ',
' ',
InvalidOid,
expr, /* Tree form check constraint */
ccbin, /* Binary form check constraint */
ccsrc, /* Source form check constraint */