Thread: ERROR: column "id" inherits conflicting default values

ERROR: column "id" inherits conflicting default values

From
Scott Ribe
Date:
In 8.4.1, trying to load a dump from 8.3.5, I get that error from this
statement:

CREATE TABLE "PatientDocument" (
)
INHERITS ("PatientRelated", "Document");

But I do not see any conflict:

# \d "PatientRelated"
                  Table "v2.PatientRelated"
Column | Type   |                        Modifiers
-------+--------+---------------------------------------------------------
 id    | bigint | not null default nextval(('"DbRowIds"'::text)::regclass)
...

# \d "Document"
                     Table "v2.Document"
Column | Type   |                          Modifiers
-------+--------+---------------------------------------------------------
 id    | bigint | not null default nextval(('"DbRowIds"'::text)::regclass)
...

Should I really have to re-specify the default in this case???

--
Scott Ribe
scott_ribe@killerbytes.com
http://www.killerbytes.com/
(303) 722-0567 voice



Re: ERROR: column "id" inherits conflicting default values

From
Tom Lane
Date:
Scott Ribe <scott_ribe@killerbytes.com> writes:
> Should I really have to re-specify the default in this case???

Works for me:

regression=# create sequence s1;
CREATE SEQUENCE
regression=# create table t1 (f1 bigint default nextval('s1'::text::regclass));
CREATE TABLE
regression=# create table t2 (f1 bigint default nextval('s1'::text::regclass));
CREATE TABLE
regression=# create table t3 (f2 int) inherits(t1,t2);
NOTICE:  merging multiple inherited definitions of column "f1"
CREATE TABLE
regression=# \d t3
                     Table "public.t3"
 Column |  Type   |                Modifiers
--------+---------+-----------------------------------------
 f1     | bigint  | default nextval(('s1'::text)::regclass)
 f2     | integer |
Inherits: t1,
          t2


Can you show an actual test case?

            regards, tom lane

Re: ERROR: column "id" inherits conflicting default values

From
Scott Ribe
Date:
> Can you show an actual test case?

create sequence "DbRowIds";

create table "PatientRelated" (id int8 not null default
nextval('"DbRowIds"'));

create table "Document"  (id int8 not null default nextval('"DbRowIds"'));

create table "PatientDocument" () inherits ("PatientRelated", "Document");

--
Scott Ribe
scott_ribe@killerbytes.com
http://www.killerbytes.com/
(303) 722-0567 voice



Re: ERROR: column "id" inherits conflicting default values

From
Tom Lane
Date:
Scott Ribe <scott_ribe@killerbytes.com> writes:
>> Can you show an actual test case?

> create sequence "DbRowIds";

> create table "PatientRelated" (id int8 not null default
> nextval('"DbRowIds"'));

> create table "Document"  (id int8 not null default nextval('"DbRowIds"'));

> create table "PatientDocument" () inherits ("PatientRelated", "Document");

Huh, so it turns out it depends on the exact length of the commands :-(

The code is comparing strings like this:

(gdb) p def->cooked_default
$3 = 0x4015c7a0 "{FUNCEXPR :funcid 1574 :funcresulttype 20 :funcretset false :funcformat 0 :args ({CONST :consttype
2205:consttypmod -1 :constlen 4 :constbyval true :constisnull false :location 64 :constvalue 4 [ 0 2 108 85 ]})
:location56}" 
(gdb) p this_default
$4 = 0x40125ae0 "{FUNCEXPR :funcid 1574 :funcresulttype 20 :funcretset false :funcformat 0 :args ({CONST :consttype
2205:consttypmod -1 :constlen 4 :constbyval true :constisnull false :location 59 :constvalue 4 [ 0 2 108 85 ]})
:location51}" 

The location fields shouldn't be considered relevant, but since it's a
plain strcmp() they matter.  This used to work as expected, and got
broken by the addition of more syntax location tracking support in 8.4.

I guess we're going to have to rewrite that code to not store the cooked
defaults in string form.  If they were node trees then equal() would do
the right thing.

            regards, tom lane

Re: ERROR: column "id" inherits conflicting default values

From
Tom Lane
Date:
I wrote:
> I guess we're going to have to rewrite that code to not store the cooked
> defaults in string form.  If they were node trees then equal() would do
> the right thing.

The attached patch should fix this.

            regards, tom lane

Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.288.2.1
diff -c -r1.288.2.1 tablecmds.c
*** src/backend/commands/tablecmds.c    7 Aug 2009 15:28:07 -0000    1.288.2.1
--- src/backend/commands/tablecmds.c    6 Oct 2009 00:25:31 -0000
***************
*** 486,492 ****
              cooked->contype = CONSTR_DEFAULT;
              cooked->name = NULL;
              cooked->attnum = attnum;
!             cooked->expr = stringToNode(colDef->cooked_default);
              cooked->is_local = true;    /* not used for defaults */
              cooked->inhcount = 0;        /* ditto */
              cookedDefaults = lappend(cookedDefaults, cooked);
--- 486,492 ----
              cooked->contype = CONSTR_DEFAULT;
              cooked->name = NULL;
              cooked->attnum = attnum;
!             cooked->expr = colDef->cooked_default;
              cooked->is_local = true;    /* not used for defaults */
              cooked->inhcount = 0;        /* ditto */
              cookedDefaults = lappend(cookedDefaults, cooked);
***************
*** 1136,1143 ****
      List       *constraints = NIL;
      int            parentsWithOids = 0;
      bool        have_bogus_defaults = false;
-     char       *bogus_marker = "Bogus!";        /* marks conflicting defaults */
      int            child_attno;

      /*
       * Check for and reject tables with too many columns. We perform this
--- 1136,1143 ----
      List       *constraints = NIL;
      int            parentsWithOids = 0;
      bool        have_bogus_defaults = false;
      int            child_attno;
+     static Node    bogus_marker = { 0 };        /* marks conflicting defaults */

      /*
       * Check for and reject tables with too many columns. We perform this
***************
*** 1321,1327 ****
               */
              if (attribute->atthasdef)
              {
!                 char       *this_default = NULL;
                  AttrDefault *attrdef;
                  int            i;

--- 1321,1327 ----
               */
              if (attribute->atthasdef)
              {
!                 Node       *this_default = NULL;
                  AttrDefault *attrdef;
                  int            i;

***************
*** 1332,1338 ****
                  {
                      if (attrdef[i].adnum == parent_attno)
                      {
!                         this_default = attrdef[i].adbin;
                          break;
                      }
                  }
--- 1332,1338 ----
                  {
                      if (attrdef[i].adnum == parent_attno)
                      {
!                         this_default = stringToNode(attrdef[i].adbin);
                          break;
                      }
                  }
***************
*** 1350,1359 ****
                   */
                  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 = bogus_marker;
                      have_bogus_defaults = true;
                  }
              }
--- 1350,1359 ----
                   */
                  Assert(def->raw_default == NULL);
                  if (def->cooked_default == NULL)
!                     def->cooked_default = this_default;
!                 else if (!equal(def->cooked_default, this_default))
                  {
!                     def->cooked_default = &bogus_marker;
                      have_bogus_defaults = true;
                  }
              }
***************
*** 1492,1498 ****
          {
              ColumnDef  *def = lfirst(entry);

!             if (def->cooked_default == bogus_marker)
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                    errmsg("column \"%s\" inherits conflicting default values",
--- 1492,1498 ----
          {
              ColumnDef  *def = lfirst(entry);

!             if (def->cooked_default == &bogus_marker)
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
                    errmsg("column \"%s\" inherits conflicting default values",
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.432
diff -c -r1.432 copyfuncs.c
*** src/backend/nodes/copyfuncs.c    18 Jun 2009 01:27:02 -0000    1.432
--- src/backend/nodes/copyfuncs.c    6 Oct 2009 00:25:33 -0000
***************
*** 2073,2079 ****
      COPY_SCALAR_FIELD(is_local);
      COPY_SCALAR_FIELD(is_not_null);
      COPY_NODE_FIELD(raw_default);
!     COPY_STRING_FIELD(cooked_default);
      COPY_NODE_FIELD(constraints);

      return newnode;
--- 2073,2079 ----
      COPY_SCALAR_FIELD(is_local);
      COPY_SCALAR_FIELD(is_not_null);
      COPY_NODE_FIELD(raw_default);
!     COPY_NODE_FIELD(cooked_default);
      COPY_NODE_FIELD(constraints);

      return newnode;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.355
diff -c -r1.355 equalfuncs.c
*** src/backend/nodes/equalfuncs.c    18 Jun 2009 01:27:02 -0000    1.355
--- src/backend/nodes/equalfuncs.c    6 Oct 2009 00:25:33 -0000
***************
*** 2052,2058 ****
      COMPARE_SCALAR_FIELD(is_local);
      COMPARE_SCALAR_FIELD(is_not_null);
      COMPARE_NODE_FIELD(raw_default);
!     COMPARE_STRING_FIELD(cooked_default);
      COMPARE_NODE_FIELD(constraints);

      return true;
--- 2052,2058 ----
      COMPARE_SCALAR_FIELD(is_local);
      COMPARE_SCALAR_FIELD(is_not_null);
      COMPARE_NODE_FIELD(raw_default);
!     COMPARE_NODE_FIELD(cooked_default);
      COMPARE_NODE_FIELD(constraints);

      return true;
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.360
diff -c -r1.360 outfuncs.c
*** src/backend/nodes/outfuncs.c    11 Jun 2009 14:48:58 -0000    1.360
--- src/backend/nodes/outfuncs.c    6 Oct 2009 00:25:33 -0000
***************
*** 1837,1843 ****
      WRITE_BOOL_FIELD(is_local);
      WRITE_BOOL_FIELD(is_not_null);
      WRITE_NODE_FIELD(raw_default);
!     WRITE_STRING_FIELD(cooked_default);
      WRITE_NODE_FIELD(constraints);
  }

--- 1837,1843 ----
      WRITE_BOOL_FIELD(is_local);
      WRITE_BOOL_FIELD(is_not_null);
      WRITE_NODE_FIELD(raw_default);
!     WRITE_NODE_FIELD(cooked_default);
      WRITE_NODE_FIELD(constraints);
  }

Index: src/backend/parser/parse_utilcmd.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/parse_utilcmd.c,v
retrieving revision 2.21
diff -c -r2.21 parse_utilcmd.c
*** src/backend/parser/parse_utilcmd.c    11 Jun 2009 14:49:00 -0000    2.21
--- src/backend/parser/parse_utilcmd.c    6 Oct 2009 00:25:33 -0000
***************
*** 642,648 ****
           */
          if (attribute->atthasdef && including_defaults)
          {
!             char       *this_default = NULL;
              AttrDefault *attrdef;
              int            i;

--- 642,648 ----
           */
          if (attribute->atthasdef && including_defaults)
          {
!             Node       *this_default = NULL;
              AttrDefault *attrdef;
              int            i;

***************
*** 653,659 ****
              {
                  if (attrdef[i].adnum == parent_attno)
                  {
!                     this_default = attrdef[i].adbin;
                      break;
                  }
              }
--- 653,659 ----
              {
                  if (attrdef[i].adnum == parent_attno)
                  {
!                     this_default = stringToNode(attrdef[i].adbin);
                      break;
                  }
              }
***************
*** 664,670 ****
               * but it can't; so default is ready to apply to child.
               */

!             def->cooked_default = pstrdup(this_default);
          }
      }

--- 664,670 ----
               * but it can't; so default is ready to apply to child.
               */

!             def->cooked_default = this_default;
          }
      }

Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.395
diff -c -r1.395 parsenodes.h
*** src/include/nodes/parsenodes.h    18 Jun 2009 01:27:02 -0000    1.395
--- src/include/nodes/parsenodes.h    6 Oct 2009 00:25:33 -0000
***************
*** 443,452 ****
   *
   * 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!
   *
   * The constraints list may contain a CONSTR_DEFAULT item in a raw
   * parsetree produced by gram.y, but transformCreateStmt will remove
--- 443,451 ----
   *
   * If the column has a default value, we may have the value expression
   * in either "raw" form (an untransformed parse tree) or "cooked" form
!  * (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,468 ****
      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 */
      List       *constraints;    /* other constraints on column */
  } ColumnDef;

--- 461,467 ----
      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) */
!     Node       *cooked_default; /* default value (transformed expr tree) */
      List       *constraints;    /* other constraints on column */
  } ColumnDef;

Index: src/test/regress/expected/inherit.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/inherit.out,v
retrieving revision 1.26
diff -c -r1.26 inherit.out
*** src/test/regress/expected/inherit.out    11 Jun 2008 21:53:49 -0000    1.26
--- src/test/regress/expected/inherit.out    6 Oct 2009 00:25:34 -0000
***************
*** 571,576 ****
--- 571,591 ----
   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');
  /*
Index: src/test/regress/sql/inherit.sql
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/sql/inherit.sql,v
retrieving revision 1.12
diff -c -r1.12 inherit.sql
*** src/test/regress/sql/inherit.sql    9 May 2008 23:32:05 -0000    1.12
--- src/test/regress/sql/inherit.sql    6 Oct 2009 00:25:34 -0000
***************
*** 121,126 ****
--- 121,137 ----
  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');