From a1464e971c4d834925804054cb372086f8ce43aa Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Fri, 4 Aug 2000 06:12:11 +0000 Subject: [PATCH] Subclasses inherit constraints of super classes properly --- src/backend/commands/creatinh.c | 97 ++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c index 1c49045330..e39c24f8df 100644 --- a/src/backend/commands/creatinh.c +++ b/src/backend/commands/creatinh.c @@ -8,11 +8,7 @@ * * * IDENTIFICATION -<<<<<<< creatinh.c - * $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 + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.63 2000/08/04 06:12:11 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -29,13 +25,14 @@ #include "commands/creatinh.h" #include "miscadmin.h" #include "utils/syscache.h" +#include "optimizer/clauses.h" /* ---------------- * local stuff * ---------------- */ -static bool checkAttrExists(const char *attributeName, +static int checkAttrExists(const char *attributeName, const char *attributeType, List *schema); static List *MergeAttributes(List *schema, List *supers, List **supconstr); static void StoreCatalogInheritance(Oid relationId, List *supers); @@ -246,6 +243,45 @@ TruncateRelation(char *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 * Returns new schema given initial schema and supers. @@ -283,6 +319,7 @@ MergeAttributes(List *schema, List *supers, List **supconstr) List *entry; List *inhSchema = NIL; List *constraints = NIL; + int attnums; /* * 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 */ + attnums = 0; foreach(entry, supers) { char *name = strVal(lfirst(entry)); @@ -333,15 +371,30 @@ MergeAttributes(List *schema, List *supers, List **supconstr) AttrNumber attrno; TupleDesc tupleDesc; TupleConstr *constr; + AttrNumber *newattno, *partialAttidx; + Node *expr; + int i, attidx, attno_exist; relation = heap_openr(name, AccessShareLock); setRelhassubclassInRelation(relation->rd_id, true); 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; if (relation->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table", name); + attidx = 0; for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--) { Form_pg_attribute attribute = tupleDesc->attrs[attrno]; @@ -365,16 +418,21 @@ MergeAttributes(List *schema, List *supers, List **supconstr) * check validity * */ - if (checkAttrExists(attributeName, attributeType, schema)) + if (checkAttrExists(attributeName, attributeType, schema) != 0) elog(ERROR, "CREATE TABLE: attribute \"%s\" already exists in inherited schema", attributeName); - if (checkAttrExists(attributeName, attributeType, inhSchema)) + if (0 < (attno_exist = checkAttrExists(attributeName, attributeType, inhSchema))) + { /* * this entry already exists */ + newattno[attribute->attnum - 1] = attno_exist; continue; + } + attidx++; + partialAttidx[attribute->attnum - 1] = attidx; /* * add an entry to the schema @@ -408,6 +466,13 @@ MergeAttributes(List *schema, List *supers, List **supconstr) } 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) { @@ -424,10 +489,14 @@ MergeAttributes(List *schema, List *supers, List **supconstr) else cdef->name = pstrdup(check[i].ccname); 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); } } + pfree(newattno); /* * 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) { List *s; + int i = 0; foreach(s, schema) { ColumnDef *def = lfirst(s); + ++i; 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) elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)", attributeName, attributeType, def->typename->name); - return true; + return i; } } - return false; + return 0; }