Code review for LIKE INCLUDING CONSTRAINTS patch --- improve comments,

don't cheat on the raw-vs-cooked status of a constraint.
This commit is contained in:
Tom Lane 2006-10-11 16:42:59 +00:00
parent 3f16647960
commit 8f2f180ff1
3 changed files with 152 additions and 116 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.204 2006/10/06 17:13:59 petere Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.205 2006/10/11 16:42:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -163,6 +163,8 @@ static List *MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr, int *supOidCount); List **supOids, List **supconstr, int *supOidCount);
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
static void add_nonduplicate_constraint(Constraint *cdef,
ConstrCheck *check, int *ncheck);
static bool change_varattnos_walker(Node *node, const AttrNumber *newattno); static bool change_varattnos_walker(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers); static void StoreCatalogInheritance(Oid relationId, List *supers);
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
@ -285,7 +287,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
List *rawDefaults; List *rawDefaults;
Datum reloptions; Datum reloptions;
ListCell *listptr; ListCell *listptr;
int i;
AttrNumber attnum; AttrNumber attnum;
/* /*
@ -378,49 +379,35 @@ DefineRelation(CreateStmt *stmt, char relkind)
localHasOids = interpretOidsOption(stmt->options); localHasOids = interpretOidsOption(stmt->options);
descriptor->tdhasoid = (localHasOids || parentOidCount > 0); descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
if (old_constraints != NIL) if (old_constraints || stmt->constraints)
{ {
ConstrCheck *check = (ConstrCheck *) ConstrCheck *check;
palloc0(list_length(old_constraints) * sizeof(ConstrCheck));
int ncheck = 0; int ncheck = 0;
/* make array that's certainly big enough */
check = (ConstrCheck *)
palloc((list_length(old_constraints) +
list_length(stmt->constraints)) * sizeof(ConstrCheck));
/* deal with constraints from MergeAttributes */
foreach(listptr, old_constraints) foreach(listptr, old_constraints)
{ {
Constraint *cdef = (Constraint *) lfirst(listptr); Constraint *cdef = (Constraint *) lfirst(listptr);
bool dup = false;
if (cdef->contype != CONSTR_CHECK) if (cdef->contype == CONSTR_CHECK)
continue; add_nonduplicate_constraint(cdef, check, &ncheck);
Assert(cdef->name != NULL);
Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
/*
* In multiple-inheritance situations, it's possible to inherit
* the same grandparent constraint through multiple parents.
* Hence, discard inherited constraints that match as to both name
* and expression. Otherwise, gripe if the names conflict.
*/
for (i = 0; i < ncheck; i++)
{
if (strcmp(check[i].ccname, cdef->name) != 0)
continue;
if (strcmp(check[i].ccbin, cdef->cooked_expr) == 0)
{
dup = true;
break;
}
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate check constraint name \"%s\"",
cdef->name)));
}
if (!dup)
{
check[ncheck].ccname = cdef->name;
check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
ncheck++;
}
} }
/*
* analyze.c might have passed some precooked constraints too,
* due to LIKE tab INCLUDING CONSTRAINTS
*/
foreach(listptr, stmt->constraints)
{
Constraint *cdef = (Constraint *) lfirst(listptr);
if (cdef->contype == CONSTR_CHECK && cdef->cooked_expr != NULL)
add_nonduplicate_constraint(cdef, check, &ncheck);
}
/* if we found any, insert 'em into the descriptor */
if (ncheck > 0) if (ncheck > 0)
{ {
if (descriptor->constr == NULL) if (descriptor->constr == NULL)
@ -1118,66 +1105,57 @@ MergeAttributes(List *schema, List *supers, bool istemp,
return schema; return schema;
} }
/*
* Varattnos of pg_constraint.conbin must be rewritten when subclasses inherit
* constraints from parent classes, since the inherited attributes could
* be given different column numbers in multiple-inheritance cases.
*
* Note that the passed node tree is modified in place!
*
* This function is used elsewhere such as in analyze.c
*
*/
/*
* In multiple-inheritance situations, it's possible to inherit
* the same grandparent constraint through multiple parents.
* Hence, we want to discard inherited constraints that match as to
* both name and expression. Otherwise, gripe if there are conflicting
* names. Nonconflicting constraints are added to the array check[]
* of length *ncheck ... caller must ensure there is room!
*/
static void
add_nonduplicate_constraint(Constraint *cdef, ConstrCheck *check, int *ncheck)
{
int i;
/* Should only see precooked constraints here */
Assert(cdef->contype == CONSTR_CHECK);
Assert(cdef->name != NULL);
Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
for (i = 0; i < *ncheck; i++)
{
if (strcmp(check[i].ccname, cdef->name) != 0)
continue;
if (strcmp(check[i].ccbin, cdef->cooked_expr) == 0)
return; /* duplicate constraint, so ignore it */
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate check constraint name \"%s\"",
cdef->name)));
}
/* No match on name, so add it to array */
check[*ncheck].ccname = cdef->name;
check[*ncheck].ccbin = pstrdup(cdef->cooked_expr);
(*ncheck)++;
}
/*
* Replace varattno values in an expression tree according to the given
* map array, that is, varattno N is replaced by newattno[N-1]. It is
* caller's responsibility to ensure that the array is long enough to
* define values for all user varattnos present in the tree. System column
* attnos remain unchanged.
*
* Note that the passed node tree is modified in-place!
*/
void void
change_varattnos_of_a_node(Node *node, const AttrNumber *newattno) change_varattnos_of_a_node(Node *node, const AttrNumber *newattno)
{ {
change_varattnos_walker(node, newattno); /* no setup needed, so away we go */
} (void) change_varattnos_walker(node, newattno);
/* Generate a map for change_varattnos_of_a_node from two tupledesc's. */
AttrNumber *
varattnos_map(TupleDesc old, TupleDesc new)
{
int i,
j;
AttrNumber *attmap = palloc0(sizeof(AttrNumber) * old->natts);
for (i = 1; i <= old->natts; i++)
{
if (old->attrs[i - 1]->attisdropped)
{
attmap[i - 1] = 0;
continue;
}
for (j = 1; j <= new->natts; j++)
if (!strcmp(NameStr(old->attrs[i - 1]->attname), NameStr(new->attrs[j - 1]->attname)))
attmap[i - 1] = j;
}
return attmap;
}
/*
* Generate a map for change_varattnos_of_a_node from a tupledesc and a list of
* ColumnDefs
*/
AttrNumber *
varattnos_map_schema(TupleDesc old, List *schema)
{
int i;
AttrNumber *attmap = palloc0(sizeof(AttrNumber) * old->natts);
for (i = 1; i <= old->natts; i++)
{
if (old->attrs[i - 1]->attisdropped)
{
attmap[i - 1] = 0;
continue;
}
attmap[i - 1] = findAttrByName(NameStr(old->attrs[i - 1]->attname), schema);
}
return attmap;
} }
static bool static bool
@ -1206,6 +1184,59 @@ change_varattnos_walker(Node *node, const AttrNumber *newattno)
(void *) newattno); (void *) newattno);
} }
/*
* Generate a map for change_varattnos_of_a_node from old and new TupleDesc's,
* matching according to column name.
*/
AttrNumber *
varattnos_map(TupleDesc old, TupleDesc new)
{
AttrNumber *attmap;
int i,
j;
attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * old->natts);
for (i = 1; i <= old->natts; i++)
{
if (old->attrs[i - 1]->attisdropped)
continue; /* leave the entry as zero */
for (j = 1; j <= new->natts; j++)
{
if (strcmp(NameStr(old->attrs[i - 1]->attname),
NameStr(new->attrs[j - 1]->attname)) == 0)
{
attmap[i - 1] = j;
break;
}
}
}
return attmap;
}
/*
* Generate a map for change_varattnos_of_a_node from a TupleDesc and a list
* of ColumnDefs
*/
AttrNumber *
varattnos_map_schema(TupleDesc old, List *schema)
{
AttrNumber *attmap;
int i;
attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * old->natts);
for (i = 1; i <= old->natts; i++)
{
if (old->attrs[i - 1]->attisdropped)
continue; /* leave the entry as zero */
attmap[i - 1] = findAttrByName(NameStr(old->attrs[i - 1]->attname),
schema);
}
return attmap;
}
/* /*
* StoreCatalogInheritance * StoreCatalogInheritance
* Updates the system catalogs with proper inheritance information. * Updates the system catalogs with proper inheritance information.

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.352 2006/10/04 00:29:55 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.353 2006/10/11 16:42:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1286,12 +1286,10 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
InhRelation *inhRelation) InhRelation *inhRelation)
{ {
AttrNumber parent_attno; AttrNumber parent_attno;
Relation relation; Relation relation;
TupleDesc tupleDesc; TupleDesc tupleDesc;
TupleConstr *constr; TupleConstr *constr;
AclResult aclresult; AclResult aclresult;
bool including_defaults = false; bool including_defaults = false;
bool including_constraints = false; bool including_constraints = false;
bool including_indexes = false; bool including_indexes = false;
@ -1342,15 +1340,18 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
including_indexes = false; including_indexes = false;
break; break;
default: default:
elog(ERROR, "unrecognized CREATE TABLE LIKE option: %d", option); elog(ERROR, "unrecognized CREATE TABLE LIKE option: %d",
option);
} }
} }
if (including_indexes) if (including_indexes)
elog(ERROR, "TODO"); ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("LIKE INCLUDING INDEXES is not implemented")));
/* /*
* Insert the inherited attributes into the cxt for the new table * Insert the copied attributes into the cxt for the new table
* definition. * definition.
*/ */
for (parent_attno = 1; parent_attno <= tupleDesc->natts; for (parent_attno = 1; parent_attno <= tupleDesc->natts;
@ -1367,7 +1368,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
continue; continue;
/* /*
* Create a new inherited column. * Create a new column, which is marked as NOT inherited.
* *
* For constraints, ONLY the NOT NULL constraint is inherited by the * For constraints, ONLY the NOT NULL constraint is inherited by the
* new column definition per SQL99. * new column definition per SQL99.
@ -1389,7 +1390,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
cxt->columns = lappend(cxt->columns, def); cxt->columns = lappend(cxt->columns, def);
/* /*
* Copy default if any, and the default has been requested * Copy default, if present and the default has been requested
*/ */
if (attribute->atthasdef && including_defaults) if (attribute->atthasdef && including_defaults)
{ {
@ -1419,10 +1420,14 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
} }
} }
/*
* Copy CHECK constraints if requested, being careful to adjust
* attribute numbers
*/
if (including_constraints && tupleDesc->constr) if (including_constraints && tupleDesc->constr)
{ {
int ccnum;
AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns); AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
int ccnum;
for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++) for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
{ {
@ -1435,8 +1440,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
n->contype = CONSTR_CHECK; n->contype = CONSTR_CHECK;
n->name = pstrdup(ccname); n->name = pstrdup(ccname);
n->raw_expr = ccbin_node; n->raw_expr = NULL;
n->cooked_expr = NULL; n->cooked_expr = nodeToString(ccbin_node);
n->indexspace = NULL; n->indexspace = NULL;
cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n); cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n);
} }

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.331 2006/10/04 00:30:09 momjian Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.332 2006/10/11 16:42:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -414,9 +414,19 @@ typedef struct InhRelation
{ {
NodeTag type; NodeTag type;
RangeVar *relation; RangeVar *relation;
List *options; List *options; /* integer List of CreateStmtLikeOption */
} InhRelation; } InhRelation;
typedef enum CreateStmtLikeOption
{
CREATE_TABLE_LIKE_INCLUDING_DEFAULTS,
CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS,
CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS,
CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS,
CREATE_TABLE_LIKE_INCLUDING_INDEXES,
CREATE_TABLE_LIKE_EXCLUDING_INDEXES
} CreateStmtLikeOption;
/* /*
* IndexElem - index parameters (used in CREATE INDEX) * IndexElem - index parameters (used in CREATE INDEX)
* *
@ -1055,16 +1065,6 @@ typedef struct CreateStmt
char *tablespacename; /* table space to use, or NULL */ char *tablespacename; /* table space to use, or NULL */
} CreateStmt; } CreateStmt;
typedef enum CreateStmtLikeOption
{
CREATE_TABLE_LIKE_INCLUDING_DEFAULTS,
CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS,
CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS,
CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS,
CREATE_TABLE_LIKE_INCLUDING_INDEXES,
CREATE_TABLE_LIKE_EXCLUDING_INDEXES
} CreateStmtLikeOption;
/* ---------- /* ----------
* Definitions for plain (non-FOREIGN KEY) constraints in CreateStmt * Definitions for plain (non-FOREIGN KEY) constraints in CreateStmt
* *