Commit e0c433c4 authored by Tom Lane's avatar Tom Lane

Change CREATE TABLE so that column default expressions coming from different

inheritance parent tables are compared using equal(), instead of doing
strcmp() on the nodeToString representation.  The old implementation was
always a tad cheesy, and it finally fails completely as of 8.4, now that the
node tree might contain syntax location information.  equal() knows it's
supposed to ignore those fields, but strcmp() hardly can.  Per recent
report from Scott Ribe.
parent 051168b6
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.300 2009/10/05 19:24:37 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.301 2009/10/06 00:55:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -493,7 +493,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
cooked->contype = CONSTR_DEFAULT;
cooked->name = NULL;
cooked->attnum = attnum;
cooked->expr = stringToNode(colDef->cooked_default);
cooked->expr = colDef->cooked_default;
cooked->is_local = true; /* not used for defaults */
cooked->inhcount = 0; /* ditto */
cookedDefaults = lappend(cookedDefaults, cooked);
......@@ -1168,8 +1168,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
List *constraints = NIL;
int parentsWithOids = 0;
bool have_bogus_defaults = false;
char *bogus_marker = "Bogus!"; /* marks conflicting defaults */
int child_attno;
static Node bogus_marker = { 0 }; /* marks conflicting defaults */
/*
* Check for and reject tables with too many columns. We perform this
......@@ -1353,7 +1353,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
*/
if (attribute->atthasdef)
{
char *this_default = NULL;
Node *this_default = NULL;
AttrDefault *attrdef;
int i;
......@@ -1364,7 +1364,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
{
if (attrdef[i].adnum == parent_attno)
{
this_default = attrdef[i].adbin;
this_default = stringToNode(attrdef[i].adbin);
break;
}
}
......@@ -1382,10 +1382,10 @@ MergeAttributes(List *schema, List *supers, bool istemp,
*/
Assert(def->raw_default == NULL);
if (def->cooked_default == NULL)
def->cooked_default = pstrdup(this_default);
else if (strcmp(def->cooked_default, this_default) != 0)
def->cooked_default = this_default;
else if (!equal(def->cooked_default, this_default))
{
def->cooked_default = bogus_marker;
def->cooked_default = &bogus_marker;
have_bogus_defaults = true;
}
}
......@@ -1524,7 +1524,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
{
ColumnDef *def = lfirst(entry);
if (def->cooked_default == bogus_marker)
if (def->cooked_default == &bogus_marker)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
errmsg("column \"%s\" inherits conflicting default values",
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.439 2009/10/05 19:24:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.440 2009/10/06 00:55:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2054,7 +2054,7 @@ _copyColumnDef(ColumnDef *from)
COPY_SCALAR_FIELD(is_local);
COPY_SCALAR_FIELD(is_not_null);
COPY_NODE_FIELD(raw_default);
COPY_STRING_FIELD(cooked_default);
COPY_NODE_FIELD(cooked_default);
COPY_NODE_FIELD(constraints);
return newnode;
......
......@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.362 2009/10/05 19:24:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.363 2009/10/06 00:55:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2072,7 +2072,7 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b)
COMPARE_SCALAR_FIELD(is_local);
COMPARE_SCALAR_FIELD(is_not_null);
COMPARE_NODE_FIELD(raw_default);
COMPARE_STRING_FIELD(cooked_default);
COMPARE_NODE_FIELD(cooked_default);
COMPARE_NODE_FIELD(constraints);
return true;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.364 2009/09/17 20:49:28 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.365 2009/10/06 00:55:26 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -1849,7 +1849,7 @@ _outColumnDef(StringInfo str, ColumnDef *node)
WRITE_BOOL_FIELD(is_local);
WRITE_BOOL_FIELD(is_not_null);
WRITE_NODE_FIELD(raw_default);
WRITE_STRING_FIELD(cooked_default);
WRITE_NODE_FIELD(cooked_default);
WRITE_NODE_FIELD(constraints);
}
......
......@@ -19,7 +19,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.25 2009/07/30 02:45:37 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.26 2009/10/06 00:55:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -644,7 +644,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
*/
if (attribute->atthasdef && including_defaults)
{
char *this_default = NULL;
Node *this_default = NULL;
AttrDefault *attrdef;
int i;
......@@ -655,7 +655,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
{
if (attrdef[i].adnum == parent_attno)
{
this_default = attrdef[i].adbin;
this_default = stringToNode(attrdef[i].adbin);
break;
}
}
......@@ -666,7 +666,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
* but it can't; so default is ready to apply to child.
*/
def->cooked_default = pstrdup(this_default);
def->cooked_default = this_default;
}
}
......
......@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.403 2009/10/05 19:24:48 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.404 2009/10/06 00:55:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -443,10 +443,9 @@ typedef struct RangeFunction
*
* If the column has a default value, we may have the value expression
* in either "raw" form (an untransformed parse tree) or "cooked" form
* (the nodeToString representation of an executable expression tree),
* depending on how this ColumnDef node was created (by parsing, or by
* inheritance from an existing relation). We should never have both
* in the same node!
* (a post-parse-analysis, executable expression tree), depending on
* how this ColumnDef node was created (by parsing, or by inheritance
* from an existing relation). We should never have both in the same node!
*
* The constraints list may contain a CONSTR_DEFAULT item in a raw
* parsetree produced by gram.y, but transformCreateStmt will remove
......@@ -462,7 +461,7 @@ typedef struct ColumnDef
bool is_local; /* column has local (non-inherited) def'n */
bool is_not_null; /* NOT NULL constraint specified? */
Node *raw_default; /* default value (untransformed parse tree) */
char *cooked_default; /* nodeToString representation */
Node *cooked_default; /* default value (transformed expr tree) */
List *constraints; /* other constraints on column */
} ColumnDef;
......
......@@ -571,6 +571,21 @@ order by 1,2;
bar2 | 4 | 4
(8 rows)
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
CREATE TABLE jointchild () INHERITS (firstparent, secondparent); -- ok
NOTICE: merging multiple inherited definitions of column "tomorrow"
CREATE TABLE thirdparent (tomorrow date default now()::date - 1);
CREATE TABLE otherchild () INHERITS (firstparent, thirdparent); -- not ok
NOTICE: merging multiple inherited definitions of column "tomorrow"
ERROR: column "tomorrow" inherits conflicting default values
HINT: To resolve the conflict, specify a default explicitly.
CREATE TABLE otherchild (tomorrow date default now())
INHERITS (firstparent, thirdparent); -- ok, child resolves ambiguous default
NOTICE: merging multiple inherited definitions of column "tomorrow"
NOTICE: merging column "tomorrow" with inherited definition
DROP TABLE firstparent, secondparent, jointchild, thirdparent, otherchild;
/* Test inheritance of structure (LIKE) */
CREATE TABLE inhx (xx text DEFAULT 'text');
/*
......
......@@ -121,6 +121,17 @@ update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
SELECT relname, bar.* FROM bar, pg_class where bar.tableoid = pg_class.oid
order by 1,2;
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
CREATE TABLE jointchild () INHERITS (firstparent, secondparent); -- ok
CREATE TABLE thirdparent (tomorrow date default now()::date - 1);
CREATE TABLE otherchild () INHERITS (firstparent, thirdparent); -- not ok
CREATE TABLE otherchild (tomorrow date default now())
INHERITS (firstparent, thirdparent); -- ok, child resolves ambiguous default
DROP TABLE firstparent, secondparent, jointchild, thirdparent, otherchild;
/* Test inheritance of structure (LIKE) */
CREATE TABLE inhx (xx text DEFAULT 'text');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment