Subclasses inherit constraints of super classes properly

This commit is contained in:
Hiroshi Inoue 2000-08-04 06:12:11 +00:00
parent dd8ad64118
commit a1464e971c
1 changed files with 84 additions and 13 deletions

View File

@ -8,11 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
<<<<<<< creatinh.c * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.63 2000/08/04 06:12:11 inoue Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.62 2000/07/04 06:11:27 tgl Exp $
=======
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.62 2000/07/04 06:11:27 tgl Exp $
>>>>>>> 1.58
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -29,13 +25,14 @@
#include "commands/creatinh.h" #include "commands/creatinh.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "optimizer/clauses.h"
/* ---------------- /* ----------------
* local stuff * local stuff
* ---------------- * ----------------
*/ */
static bool checkAttrExists(const char *attributeName, static int checkAttrExists(const char *attributeName,
const char *attributeType, List *schema); const char *attributeType, List *schema);
static List *MergeAttributes(List *schema, List *supers, List **supconstr); static List *MergeAttributes(List *schema, List *supers, List **supconstr);
static void StoreCatalogInheritance(Oid relationId, List *supers); static void StoreCatalogInheritance(Oid relationId, List *supers);
@ -246,6 +243,45 @@ TruncateRelation(char *name)
heap_truncate(name); heap_truncate(name);
} }
/*
* complementary static functions for MergeAttributes().
* Varattnos of pg_relcheck.rcbin should be rewritten when
* subclasses inherit the constraints from the super class.
* Note that these functions rewrite varattnos while walking
* through a node tree.
*/
static bool
change_varattnos_walker(Node *node, const AttrNumber *newattno)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
Assert(newattno != NULL);
if (var->varlevelsup == 0 && var->varno == 1)
{
/*
* ??? the following may be a problem when the
* node is multiply referenced though
* stringToNode() doesn't create such a node
* currently.
*/
Assert(newattno[var->varattno - 1] > 0);
var->varattno = newattno[var->varattno - 1];
return true;
}
else
return false;
}
return expression_tree_walker(node, change_varattnos_walker, (void *)newattno);
}
static bool
change_varattnos_of_a_node(Node *node, const AttrNumber *newattno)
{
return expression_tree_walker(node, change_varattnos_walker, (void *)newattno);
}
/* /*
* MergeAttributes * MergeAttributes
* Returns new schema given initial schema and supers. * Returns new schema given initial schema and supers.
@ -283,6 +319,7 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
List *entry; List *entry;
List *inhSchema = NIL; List *inhSchema = NIL;
List *constraints = NIL; List *constraints = NIL;
int attnums;
/* /*
* Validates that there are no duplications. Validity checking of * Validates that there are no duplications. Validity checking of
@ -325,6 +362,7 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
/* /*
* merge the inherited attributes into the schema * merge the inherited attributes into the schema
*/ */
attnums = 0;
foreach(entry, supers) foreach(entry, supers)
{ {
char *name = strVal(lfirst(entry)); char *name = strVal(lfirst(entry));
@ -333,15 +371,30 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
AttrNumber attrno; AttrNumber attrno;
TupleDesc tupleDesc; TupleDesc tupleDesc;
TupleConstr *constr; TupleConstr *constr;
AttrNumber *newattno, *partialAttidx;
Node *expr;
int i, attidx, attno_exist;
relation = heap_openr(name, AccessShareLock); relation = heap_openr(name, AccessShareLock);
setRelhassubclassInRelation(relation->rd_id, true); setRelhassubclassInRelation(relation->rd_id, true);
tupleDesc = RelationGetDescr(relation); tupleDesc = RelationGetDescr(relation);
/* allocate a new attribute number table and initialize */
newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
for (i = 0; i < tupleDesc->natts; i++)
newattno [i] = 0;
/*
* searching and storing order are different.
* another table is needed.
*/
partialAttidx = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
for (i = 0; i < tupleDesc->natts; i++)
partialAttidx [i] = 0;
constr = tupleDesc->constr; constr = tupleDesc->constr;
if (relation->rd_rel->relkind != RELKIND_RELATION) if (relation->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table", name); elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table", name);
attidx = 0;
for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--) for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--)
{ {
Form_pg_attribute attribute = tupleDesc->attrs[attrno]; Form_pg_attribute attribute = tupleDesc->attrs[attrno];
@ -365,16 +418,21 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
* check validity * check validity
* *
*/ */
if (checkAttrExists(attributeName, attributeType, schema)) if (checkAttrExists(attributeName, attributeType, schema) != 0)
elog(ERROR, "CREATE TABLE: attribute \"%s\" already exists in inherited schema", elog(ERROR, "CREATE TABLE: attribute \"%s\" already exists in inherited schema",
attributeName); attributeName);
if (checkAttrExists(attributeName, attributeType, inhSchema)) if (0 < (attno_exist = checkAttrExists(attributeName, attributeType, inhSchema)))
{
/* /*
* this entry already exists * this entry already exists
*/ */
newattno[attribute->attnum - 1] = attno_exist;
continue; continue;
}
attidx++;
partialAttidx[attribute->attnum - 1] = attidx;
/* /*
* add an entry to the schema * add an entry to the schema
@ -408,6 +466,13 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
} }
partialResult = lcons(def, partialResult); partialResult = lcons(def, partialResult);
} }
for (i = 0; i < tupleDesc->natts; i++)
{
if (partialAttidx[i] > 0)
newattno[i] = attnums + attidx + 1 - partialAttidx[i];
}
attnums += attidx;
pfree(partialAttidx);
if (constr && constr->num_check > 0) if (constr && constr->num_check > 0)
{ {
@ -424,10 +489,14 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
else else
cdef->name = pstrdup(check[i].ccname); cdef->name = pstrdup(check[i].ccname);
cdef->raw_expr = NULL; cdef->raw_expr = NULL;
cdef->cooked_expr = pstrdup(check[i].ccbin); /* adjust varattnos of ccbin here */
expr = stringToNode(check[i].ccbin);
change_varattnos_of_a_node(expr, newattno);
cdef->cooked_expr = nodeToString(expr);
constraints = lappend(constraints, cdef); constraints = lappend(constraints, cdef);
} }
} }
pfree(newattno);
/* /*
* Close the parent rel, but keep our AccessShareLock on it until * Close the parent rel, but keep our AccessShareLock on it until
@ -645,17 +714,19 @@ again:
/* /*
* returns true if attribute already exists in schema, false otherwise. * returns the index(star with 1) if attribute already exists in schema, 0 otherwise.
*/ */
static bool static int
checkAttrExists(const char *attributeName, const char *attributeType, List *schema) checkAttrExists(const char *attributeName, const char *attributeType, List *schema)
{ {
List *s; List *s;
int i = 0;
foreach(s, schema) foreach(s, schema)
{ {
ColumnDef *def = lfirst(s); ColumnDef *def = lfirst(s);
++i;
if (strcmp(attributeName, def->colname) == 0) if (strcmp(attributeName, def->colname) == 0)
{ {
@ -665,10 +736,10 @@ checkAttrExists(const char *attributeName, const char *attributeType, List *sche
if (strcmp(attributeType, def->typename->name) != 0) if (strcmp(attributeType, def->typename->name) != 0)
elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)", elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)",
attributeName, attributeType, def->typename->name); attributeName, attributeType, def->typename->name);
return true; return i;
} }
} }
return false; return 0;
} }