Merge the Constraint and FkConstraint node types into a single type.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 30 Jul 2009 02:45:38 +0000 (02:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 30 Jul 2009 02:45:38 +0000 (02:45 +0000)
This was foreseen to be a good idea long ago, but nobody had got round
to doing it.  The recent patch for deferred unique constraints made
transformConstraintAttrs() ugly enough that I decided it was time.
This change will also greatly simplify parsing of deferred CHECK constraints,
if anyone ever gets around to implementing that.

While at it, add a location field to Constraint, and use that to provide
an error cursor for some of the constraint-related error messages.

12 files changed:
src/backend/catalog/heap.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/commands/typecmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_utilcmd.c
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h

index 588c26ad125dd87c660cced8413e5439eb4b5538..478583a742fb5edc13b22b15a62d5bc6a89b8dd6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.355 2009/07/28 02:56:29 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.356 2009/07/30 02:45:36 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1870,11 +1870,11 @@ AddRelationNewConstraints(Relation rel,
        /*
         * Check name uniqueness, or generate a name if none was given.
         */
-       if (cdef->name != NULL)
+       if (cdef->conname != NULL)
        {
            ListCell   *cell2;
 
-           ccname = cdef->name;
+           ccname = cdef->conname;
            /* Check against other new constraints */
            /* Needed because we don't do CommandCounterIncrement in loop */
            foreach(cell2, checknames)
index 0d3e3bc1670a9c1b8dfef731dbb19e10ff9b971d..53abfec6976c47ba20277816e544ea294f4893d7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.293 2009/07/29 20:56:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.294 2009/07/30 02:45:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,7 +154,7 @@ typedef struct NewConstraint
    Oid         refrelid;       /* PK rel, if FOREIGN */
    Oid         refindid;       /* OID of PK's index, if FOREIGN */
    Oid         conid;          /* OID of pg_constraint entry, if FOREIGN */
-   Node       *qual;           /* Check expr or FkConstraint struct */
+   Node       *qual;           /* Check expr or CONSTR_FOREIGN Constraint */
    List       *qualstate;      /* Execution state for CHECK */
 } NewConstraint;
 
@@ -247,10 +247,10 @@ static Oid transformFkeyCheckAttrs(Relation pkrel,
                        int numattrs, int16 *attnums,
                        Oid *opclasses);
 static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts);
-static void validateForeignKeyConstraint(FkConstraint *fkconstraint,
+static void validateForeignKeyConstraint(Constraint *fkconstraint,
                             Relation rel, Relation pkrel,
                             Oid pkindOid, Oid constraintOid);
-static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
+static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
                         Oid constraintOid, Oid indexOid);
 static void ATController(Relation rel, List *cmds, bool recurse);
 static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
@@ -293,13 +293,13 @@ static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
               IndexStmt *stmt, bool is_rebuild);
 static void ATExecAddConstraint(List **wqueue,
                    AlteredTableInfo *tab, Relation rel,
-                   Node *newConstraint, bool recurse);
+                   Constraint *newConstraint, bool recurse);
 static void ATAddCheckConstraint(List **wqueue,
                     AlteredTableInfo *tab, Relation rel,
                     Constraint *constr,
                     bool recurse, bool recursing);
 static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
-                         FkConstraint *fkconstraint);
+                         Constraint *fkconstraint);
 static void ATExecDropConstraint(Relation rel, const char *constrName,
                                 DropBehavior behavior,
                                 bool recurse, bool recursing,
@@ -2637,10 +2637,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
            ATExecAddIndex(tab, rel, (IndexStmt *) cmd->def, true);
            break;
        case AT_AddConstraint:  /* ADD CONSTRAINT */
-           ATExecAddConstraint(wqueue, tab, rel, cmd->def, false);
+           ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
+                               false);
            break;
        case AT_AddConstraintRecurse:   /* ADD CONSTRAINT with recursion */
-           ATExecAddConstraint(wqueue, tab, rel, cmd->def, true);
+           ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
+                               true);
            break;
        case AT_DropConstraint: /* DROP CONSTRAINT */
            ATExecDropConstraint(rel, cmd->name, cmd->behavior,
@@ -2905,7 +2907,7 @@ ATRewriteTables(List **wqueue)
 
            if (con->contype == CONSTR_FOREIGN)
            {
-               FkConstraint *fkconstraint = (FkConstraint *) con->qual;
+               Constraint *fkconstraint = (Constraint *) con->qual;
                Relation    refrel;
 
                if (rel == NULL)
@@ -4405,69 +4407,55 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
  */
 static void
 ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
-                   Node *newConstraint, bool recurse)
+                   Constraint *newConstraint, bool recurse)
 {
-   switch (nodeTag(newConstraint))
+   Assert(IsA(newConstraint, Constraint));
+
+   /*
+    * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
+    * arriving here (see the preprocessing done in parse_utilcmd.c).  Use a
+    * switch anyway to make it easier to add more code later.
+    */
+   switch (newConstraint->contype)
    {
-       case T_Constraint:
-           {
-               Constraint *constr = (Constraint *) newConstraint;
+       case CONSTR_CHECK:
+           ATAddCheckConstraint(wqueue, tab, rel,
+                                newConstraint, recurse, false);
+           break;
 
-               /*
-                * Currently, we only expect to see CONSTR_CHECK nodes
-                * arriving here (see the preprocessing done in
-                * parse_utilcmd.c).  Use a switch anyway to make it easier to
-                * add more code later.
-                */
-               switch (constr->contype)
-               {
-                   case CONSTR_CHECK:
-                       ATAddCheckConstraint(wqueue, tab, rel,
-                                            constr, recurse, false);
-                       break;
-                   default:
-                       elog(ERROR, "unrecognized constraint type: %d",
-                            (int) constr->contype);
-               }
-               break;
-           }
-       case T_FkConstraint:
+       case CONSTR_FOREIGN:
+           /*
+            * Note that we currently never recurse for FK constraints, so
+            * the "recurse" flag is silently ignored.
+            *
+            * Assign or validate constraint name
+            */
+           if (newConstraint->conname)
            {
-               FkConstraint *fkconstraint = (FkConstraint *) newConstraint;
-
-               /*
-                * Note that we currently never recurse for FK constraints, so
-                * the "recurse" flag is silently ignored.
-                *
-                * Assign or validate constraint name
-                */
-               if (fkconstraint->constr_name)
-               {
-                   if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
-                                            RelationGetRelid(rel),
-                                            RelationGetNamespace(rel),
-                                            fkconstraint->constr_name))
-                       ereport(ERROR,
-                               (errcode(ERRCODE_DUPLICATE_OBJECT),
-                                errmsg("constraint \"%s\" for relation \"%s\" already exists",
-                                       fkconstraint->constr_name,
-                                       RelationGetRelationName(rel))));
-               }
-               else
-                   fkconstraint->constr_name =
-                       ChooseConstraintName(RelationGetRelationName(rel),
-                                   strVal(linitial(fkconstraint->fk_attrs)),
-                                            "fkey",
-                                            RelationGetNamespace(rel),
-                                            NIL);
-
-               ATAddForeignKeyConstraint(tab, rel, fkconstraint);
-
-               break;
+               if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+                                        RelationGetRelid(rel),
+                                        RelationGetNamespace(rel),
+                                        newConstraint->conname))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DUPLICATE_OBJECT),
+                            errmsg("constraint \"%s\" for relation \"%s\" already exists",
+                                   newConstraint->conname,
+                                   RelationGetRelationName(rel))));
            }
+           else
+               newConstraint->conname =
+                   ChooseConstraintName(RelationGetRelationName(rel),
+                                        strVal(linitial(newConstraint->fk_attrs)),
+                                        "fkey",
+                                        RelationGetNamespace(rel),
+                                        NIL);
+
+           ATAddForeignKeyConstraint(tab, rel, newConstraint);
+           break;
+
        default:
-           elog(ERROR, "unrecognized node type: %d",
-                (int) nodeTag(newConstraint));
+           elog(ERROR, "unrecognized constraint type: %d",
+                (int) newConstraint->contype);
    }
 }
 
@@ -4526,12 +4514,12 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
        tab->constraints = lappend(tab->constraints, newcon);
 
        /* Save the actually assigned name if it was defaulted */
-       if (constr->name == NULL)
-           constr->name = ccon->name;
+       if (constr->conname == NULL)
+           constr->conname = ccon->name;
    }
 
    /* At this point we must have a locked-down name to use */
-   Assert(constr->name != NULL);
+   Assert(constr->conname != NULL);
 
    /* Advance command counter in case same table is visited multiple times */
    CommandCounterIncrement();
@@ -4583,7 +4571,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
  */
 static void
 ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
-                         FkConstraint *fkconstraint)
+                         Constraint *fkconstraint)
 {
    Relation    pkrel;
    int16       pkattnum[INDEX_MAX_KEYS];
@@ -4798,7 +4786,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                     errmsg("foreign key constraint \"%s\" "
                            "cannot be implemented",
-                           fkconstraint->constr_name),
+                           fkconstraint->conname),
                     errdetail("Key columns \"%s\" and \"%s\" "
                               "are of incompatible types: %s and %s.",
                               strVal(list_nth(fkconstraint->fk_attrs, i)),
@@ -4814,7 +4802,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
    /*
     * Record the FK constraint in pg_constraint.
     */
-   constrOid = CreateConstraintEntry(fkconstraint->constr_name,
+   constrOid = CreateConstraintEntry(fkconstraint->conname,
                                      RelationGetNamespace(rel),
                                      CONSTRAINT_FOREIGN,
                                      fkconstraint->deferrable,
@@ -4854,7 +4842,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
        NewConstraint *newcon;
 
        newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
-       newcon->name = fkconstraint->constr_name;
+       newcon->name = fkconstraint->conname;
        newcon->contype = CONSTR_FOREIGN;
        newcon->refrelid = RelationGetRelid(pkrel);
        newcon->refindid = indexOid;
@@ -5156,7 +5144,7 @@ checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
  * Caller must have opened and locked both relations.
  */
 static void
-validateForeignKeyConstraint(FkConstraint *fkconstraint,
+validateForeignKeyConstraint(Constraint *fkconstraint,
                             Relation rel,
                             Relation pkrel,
                             Oid pkindOid,
@@ -5171,7 +5159,7 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
     */
    MemSet(&trig, 0, sizeof(trig));
    trig.tgoid = InvalidOid;
-   trig.tgname = fkconstraint->constr_name;
+   trig.tgname = fkconstraint->conname;
    trig.tgenabled = TRIGGER_FIRES_ON_ORIGIN;
    trig.tgisconstraint = TRUE;
    trig.tgconstrrelid = RelationGetRelid(pkrel);
@@ -5228,13 +5216,13 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
 }
 
 static void
-CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
+CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint,
                     Oid constraintOid, Oid indexOid, bool on_insert)
 {
    CreateTrigStmt *fk_trigger;
 
    fk_trigger = makeNode(CreateTrigStmt);
-   fk_trigger->trigname = fkconstraint->constr_name;
+   fk_trigger->trigname = fkconstraint->conname;
    fk_trigger->relation = myRel;
    fk_trigger->before = false;
    fk_trigger->row = true;
@@ -5268,7 +5256,7 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
  * Create the triggers that implement an FK constraint.
  */
 static void
-createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
+createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
                         Oid constraintOid, Oid indexOid)
 {
    RangeVar   *myRel;
@@ -5296,7 +5284,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
     * DELETE action on the referenced table.
     */
    fk_trigger = makeNode(CreateTrigStmt);
-   fk_trigger->trigname = fkconstraint->constr_name;
+   fk_trigger->trigname = fkconstraint->conname;
    fk_trigger->relation = fkconstraint->pktable;
    fk_trigger->before = false;
    fk_trigger->row = true;
@@ -5348,7 +5336,7 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
     * UPDATE action on the referenced table.
     */
    fk_trigger = makeNode(CreateTrigStmt);
-   fk_trigger->trigname = fkconstraint->constr_name;
+   fk_trigger->trigname = fkconstraint->conname;
    fk_trigger->relation = fkconstraint->pktable;
    fk_trigger->before = false;
    fk_trigger->row = true;
index b84731126a1303e2fe9af1b75e0b9852c9ffbe71..7bc82127893bd666ce085c269298d0b713a69bdd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.250 2009/07/29 20:56:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.251 2009/07/30 02:45:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -607,12 +607,14 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
        /* OK, we have a set, so make the FK constraint ALTER TABLE cmd */
        AlterTableStmt *atstmt = makeNode(AlterTableStmt);
        AlterTableCmd *atcmd = makeNode(AlterTableCmd);
-       FkConstraint *fkcon = makeNode(FkConstraint);
+       Constraint *fkcon = makeNode(Constraint);
 
        ereport(NOTICE,
                (errmsg("converting trigger group into constraint \"%s\" %s",
                        constr_name, buf.data),
                 errdetail("%s", _(funcdescr[funcnum]))));
+       fkcon->contype = CONSTR_FOREIGN;
+       fkcon->location = -1;
        if (funcnum == 2)
        {
            /* This trigger is on the FK table */
@@ -642,9 +644,9 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
        atcmd->subtype = AT_AddConstraint;
        atcmd->def = (Node *) fkcon;
        if (strcmp(constr_name, "<unnamed>") == 0)
-           fkcon->constr_name = NULL;
+           fkcon->conname = NULL;
        else
-           fkcon->constr_name = constr_name;
+           fkcon->conname = constr_name;
        fkcon->fk_attrs = fk_attrs;
        fkcon->pk_attrs = pk_attrs;
        fkcon->fk_matchtype = fk_matchtype;
index 1d3077cc32400a95db15ae12a0da00ed85b35df0..5fa2ac6bc90e235cc5f588d55529aeaefca4ca97 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.136 2009/07/28 02:56:30 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.137 2009/07/30 02:45:36 tgl Exp $
  *
  * DESCRIPTION
  *   The "DefineFoo" routines take the parse tree and pick out the
@@ -867,22 +867,11 @@ DefineDomain(CreateDomainStmt *stmt)
     */
    foreach(listptr, schema)
    {
-       Node       *newConstraint = lfirst(listptr);
-       Constraint *constr;
-
-       /* Check for unsupported constraint types */
-       if (IsA(newConstraint, FkConstraint))
-           ereport(ERROR,
-                   (errcode(ERRCODE_SYNTAX_ERROR),
-               errmsg("foreign key constraints not possible for domains")));
+       Constraint *constr = lfirst(listptr);
 
-       /* otherwise it should be a plain Constraint */
-       if (!IsA(newConstraint, Constraint))
+       if (!IsA(constr, Constraint))
            elog(ERROR, "unrecognized node type: %d",
-                (int) nodeTag(newConstraint));
-
-       constr = (Constraint *) newConstraint;
-
+                (int) nodeTag(constr));
        switch (constr->contype)
        {
            case CONSTR_DEFAULT:
@@ -995,6 +984,12 @@ DefineDomain(CreateDomainStmt *stmt)
                errmsg("primary key constraints not possible for domains")));
                break;
 
+           case CONSTR_FOREIGN:
+               ereport(ERROR,
+                       (errcode(ERRCODE_SYNTAX_ERROR),
+               errmsg("foreign key constraints not possible for domains")));
+               break;
+
            case CONSTR_ATTR_DEFERRABLE:
            case CONSTR_ATTR_NOT_DEFERRABLE:
            case CONSTR_ATTR_DEFERRED:
@@ -1849,13 +1844,6 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
    /* Check it's a domain and check user has permission for ALTER DOMAIN */
    checkDomainOwner(tup, typename);
 
-   /* Check for unsupported constraint types */
-   if (IsA(newConstraint, FkConstraint))
-       ereport(ERROR,
-               (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("foreign key constraints not possible for domains")));
-
-   /* otherwise it should be a plain Constraint */
    if (!IsA(newConstraint, Constraint))
        elog(ERROR, "unrecognized node type: %d",
             (int) nodeTag(newConstraint));
@@ -1880,6 +1868,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
                errmsg("primary key constraints not possible for domains")));
            break;
 
+       case CONSTR_FOREIGN:
+           ereport(ERROR,
+                   (errcode(ERRCODE_SYNTAX_ERROR),
+               errmsg("foreign key constraints not possible for domains")));
+           break;
+
        case CONSTR_ATTR_DEFERRABLE:
        case CONSTR_ATTR_NOT_DEFERRABLE:
        case CONSTR_ATTR_DEFERRED:
@@ -2188,23 +2182,23 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
    /*
     * Assign or validate constraint name
     */
-   if (constr->name)
+   if (constr->conname)
    {
        if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
                                 domainOid,
                                 domainNamespace,
-                                constr->name))
+                                constr->conname))
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("constraint \"%s\" for domain \"%s\" already exists",
-                       constr->name, domainName)));
+                       constr->conname, domainName)));
    }
    else
-       constr->name = ChooseConstraintName(domainName,
-                                           NULL,
-                                           "check",
-                                           domainNamespace,
-                                           NIL);
+       constr->conname = ChooseConstraintName(domainName,
+                                              NULL,
+                                              "check",
+                                              domainNamespace,
+                                              NIL);
 
    /*
     * Convert the A_EXPR in raw_expr into an EXPR
@@ -2284,7 +2278,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
    /*
     * Store the constraint in pg_constraint
     */
-   CreateConstraintEntry(constr->name, /* Constraint Name */
+   CreateConstraintEntry(constr->conname,      /* Constraint Name */
                          domainNamespace,      /* namespace */
                          CONSTRAINT_CHECK,     /* Constraint Type */
                          false,    /* Is Deferrable */
index d10a9eb6cc5e8586095c67749d6ce76979e3116a..48039b86cb9735e0389d4e3d0e1f49ed50e69398 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.436 2009/07/29 20:56:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.437 2009/07/30 02:45:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1738,25 +1738,6 @@ _copyRangeTblEntry(RangeTblEntry *from)
    return newnode;
 }
 
-static FkConstraint *
-_copyFkConstraint(FkConstraint *from)
-{
-   FkConstraint *newnode = makeNode(FkConstraint);
-
-   COPY_STRING_FIELD(constr_name);
-   COPY_NODE_FIELD(pktable);
-   COPY_NODE_FIELD(fk_attrs);
-   COPY_NODE_FIELD(pk_attrs);
-   COPY_SCALAR_FIELD(fk_matchtype);
-   COPY_SCALAR_FIELD(fk_upd_action);
-   COPY_SCALAR_FIELD(fk_del_action);
-   COPY_SCALAR_FIELD(deferrable);
-   COPY_SCALAR_FIELD(initdeferred);
-   COPY_SCALAR_FIELD(skip_validation);
-
-   return newnode;
-}
-
 static SortGroupClause *
 _copySortGroupClause(SortGroupClause *from)
 {
@@ -2085,14 +2066,22 @@ _copyConstraint(Constraint *from)
    Constraint *newnode = makeNode(Constraint);
 
    COPY_SCALAR_FIELD(contype);
-   COPY_STRING_FIELD(name);
+   COPY_STRING_FIELD(conname);
+   COPY_SCALAR_FIELD(deferrable);
+   COPY_SCALAR_FIELD(initdeferred);
+   COPY_LOCATION_FIELD(location);
    COPY_NODE_FIELD(raw_expr);
    COPY_STRING_FIELD(cooked_expr);
    COPY_NODE_FIELD(keys);
    COPY_NODE_FIELD(options);
    COPY_STRING_FIELD(indexspace);
-   COPY_SCALAR_FIELD(deferrable);
-   COPY_SCALAR_FIELD(initdeferred);
+   COPY_NODE_FIELD(pktable);
+   COPY_NODE_FIELD(fk_attrs);
+   COPY_NODE_FIELD(pk_attrs);
+   COPY_SCALAR_FIELD(fk_matchtype);
+   COPY_SCALAR_FIELD(fk_upd_action);
+   COPY_SCALAR_FIELD(fk_del_action);
+   COPY_SCALAR_FIELD(skip_validation);
 
    return newnode;
 }
@@ -4082,9 +4071,6 @@ copyObject(void *from)
        case T_CommonTableExpr:
            retval = _copyCommonTableExpr(from);
            break;
-       case T_FkConstraint:
-           retval = _copyFkConstraint(from);
-           break;
        case T_PrivGrantee:
            retval = _copyPrivGrantee(from);
            break;
index 6fceab27855df108f677efaca80581349505fec2..6c75f2e2747f0e94c69a3cd026596a2cb912b1c1 100644 (file)
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.359 2009/07/29 20:56:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.360 2009/07/30 02:45:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2064,14 +2064,22 @@ static bool
 _equalConstraint(Constraint *a, Constraint *b)
 {
    COMPARE_SCALAR_FIELD(contype);
-   COMPARE_STRING_FIELD(name);
+   COMPARE_STRING_FIELD(conname);
+   COMPARE_SCALAR_FIELD(deferrable);
+   COMPARE_SCALAR_FIELD(initdeferred);
+   COMPARE_LOCATION_FIELD(location);
    COMPARE_NODE_FIELD(raw_expr);
    COMPARE_STRING_FIELD(cooked_expr);
    COMPARE_NODE_FIELD(keys);
    COMPARE_NODE_FIELD(options);
    COMPARE_STRING_FIELD(indexspace);
-   COMPARE_SCALAR_FIELD(deferrable);
-   COMPARE_SCALAR_FIELD(initdeferred);
+   COMPARE_NODE_FIELD(pktable);
+   COMPARE_NODE_FIELD(fk_attrs);
+   COMPARE_NODE_FIELD(pk_attrs);
+   COMPARE_SCALAR_FIELD(fk_matchtype);
+   COMPARE_SCALAR_FIELD(fk_upd_action);
+   COMPARE_SCALAR_FIELD(fk_del_action);
+   COMPARE_SCALAR_FIELD(skip_validation);
 
    return true;
 }
@@ -2189,23 +2197,6 @@ _equalCommonTableExpr(CommonTableExpr *a, CommonTableExpr *b)
    return true;
 }
 
-static bool
-_equalFkConstraint(FkConstraint *a, FkConstraint *b)
-{
-   COMPARE_STRING_FIELD(constr_name);
-   COMPARE_NODE_FIELD(pktable);
-   COMPARE_NODE_FIELD(fk_attrs);
-   COMPARE_NODE_FIELD(pk_attrs);
-   COMPARE_SCALAR_FIELD(fk_matchtype);
-   COMPARE_SCALAR_FIELD(fk_upd_action);
-   COMPARE_SCALAR_FIELD(fk_del_action);
-   COMPARE_SCALAR_FIELD(deferrable);
-   COMPARE_SCALAR_FIELD(initdeferred);
-   COMPARE_SCALAR_FIELD(skip_validation);
-
-   return true;
-}
-
 static bool
 _equalXmlSerialize(XmlSerialize *a, XmlSerialize *b)
 {
@@ -2859,9 +2850,6 @@ equal(void *a, void *b)
        case T_CommonTableExpr:
            retval = _equalCommonTableExpr(a, b);
            break;
-       case T_FkConstraint:
-           retval = _equalFkConstraint(a, b);
-           break;
        case T_PrivGrantee:
            retval = _equalPrivGrantee(a, b);
            break;
index 4dc9bd4bbf7c1ad73277b22eb2359a6cbbba3fbb..61c0e21db0843767bb587e04baaee94103494b10 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.41 2009/07/16 06:33:42 petere Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.42 2009/07/30 02:45:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -903,6 +903,9 @@ exprLocation(Node *expr)
        case T_TypeName:
            loc = ((TypeName *) expr)->location;
            break;
+       case T_Constraint:
+           loc = ((Constraint *) expr)->location;
+           break;
        case T_XmlSerialize:
            /* XMLSERIALIZE keyword should always be the first thing */
            loc = ((XmlSerialize *) expr)->location;
index e4de1c5aee2c54c37705a6a63db37fe621c45345..454a8d088670ab494520e4f625cc739554e9040c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.362 2009/07/29 20:56:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.363 2009/07/30 02:45:37 tgl Exp $
  *
  * NOTES
  *   Every node type that can appear in stored rules' parsetrees *must*
@@ -2277,18 +2277,39 @@ _outConstraint(StringInfo str, Constraint *node)
 {
    WRITE_NODE_TYPE("CONSTRAINT");
 
-   WRITE_STRING_FIELD(name);
+   WRITE_STRING_FIELD(conname);
+   WRITE_BOOL_FIELD(deferrable);
+   WRITE_BOOL_FIELD(initdeferred);
+   WRITE_LOCATION_FIELD(location);
 
    appendStringInfo(str, " :contype ");
    switch (node->contype)
    {
+       case CONSTR_NULL:
+           appendStringInfo(str, "NULL");
+           break;
+
+       case CONSTR_NOTNULL:
+           appendStringInfo(str, "NOT_NULL");
+           break;
+
+       case CONSTR_DEFAULT:
+           appendStringInfo(str, "DEFAULT");
+           WRITE_NODE_FIELD(raw_expr);
+           WRITE_STRING_FIELD(cooked_expr);
+           break;
+
+       case CONSTR_CHECK:
+           appendStringInfo(str, "CHECK");
+           WRITE_NODE_FIELD(raw_expr);
+           WRITE_STRING_FIELD(cooked_expr);
+           break;
+
        case CONSTR_PRIMARY:
            appendStringInfo(str, "PRIMARY_KEY");
            WRITE_NODE_FIELD(keys);
            WRITE_NODE_FIELD(options);
            WRITE_STRING_FIELD(indexspace);
-           WRITE_BOOL_FIELD(deferrable);
-           WRITE_BOOL_FIELD(initdeferred);
            break;
 
        case CONSTR_UNIQUE:
@@ -2296,47 +2317,40 @@ _outConstraint(StringInfo str, Constraint *node)
            WRITE_NODE_FIELD(keys);
            WRITE_NODE_FIELD(options);
            WRITE_STRING_FIELD(indexspace);
-           WRITE_BOOL_FIELD(deferrable);
-           WRITE_BOOL_FIELD(initdeferred);
            break;
 
-       case CONSTR_CHECK:
-           appendStringInfo(str, "CHECK");
-           WRITE_NODE_FIELD(raw_expr);
-           WRITE_STRING_FIELD(cooked_expr);
+       case CONSTR_FOREIGN:
+           appendStringInfo(str, "FOREIGN_KEY");
+           WRITE_NODE_FIELD(pktable);
+           WRITE_NODE_FIELD(fk_attrs);
+           WRITE_NODE_FIELD(pk_attrs);
+           WRITE_CHAR_FIELD(fk_matchtype);
+           WRITE_CHAR_FIELD(fk_upd_action);
+           WRITE_CHAR_FIELD(fk_del_action);
+           WRITE_BOOL_FIELD(skip_validation);
            break;
 
-       case CONSTR_DEFAULT:
-           appendStringInfo(str, "DEFAULT");
-           WRITE_NODE_FIELD(raw_expr);
-           WRITE_STRING_FIELD(cooked_expr);
+       case CONSTR_ATTR_DEFERRABLE:
+           appendStringInfo(str, "ATTR_DEFERRABLE");
            break;
 
-       case CONSTR_NOTNULL:
-           appendStringInfo(str, "NOT_NULL");
+       case CONSTR_ATTR_NOT_DEFERRABLE:
+           appendStringInfo(str, "ATTR_NOT_DEFERRABLE");
            break;
 
-       default:
-           appendStringInfo(str, "<unrecognized_constraint>");
+       case CONSTR_ATTR_DEFERRED:
+           appendStringInfo(str, "ATTR_DEFERRED");
            break;
-   }
-}
 
-static void
-_outFkConstraint(StringInfo str, FkConstraint *node)
-{
-   WRITE_NODE_TYPE("FKCONSTRAINT");
+       case CONSTR_ATTR_IMMEDIATE:
+           appendStringInfo(str, "ATTR_IMMEDIATE");
+           break;
 
-   WRITE_STRING_FIELD(constr_name);
-   WRITE_NODE_FIELD(pktable);
-   WRITE_NODE_FIELD(fk_attrs);
-   WRITE_NODE_FIELD(pk_attrs);
-   WRITE_CHAR_FIELD(fk_matchtype);
-   WRITE_CHAR_FIELD(fk_upd_action);
-   WRITE_CHAR_FIELD(fk_del_action);
-   WRITE_BOOL_FIELD(deferrable);
-   WRITE_BOOL_FIELD(initdeferred);
-   WRITE_BOOL_FIELD(skip_validation);
+       default:
+           appendStringInfo(str, "<unrecognized_constraint %d>",
+                            (int) node->contype);
+           break;
+   }
 }
 
 
@@ -2765,9 +2779,6 @@ _outNode(StringInfo str, void *obj)
            case T_Constraint:
                _outConstraint(str, obj);
                break;
-           case T_FkConstraint:
-               _outFkConstraint(str, obj);
-               break;
            case T_FuncCall:
                _outFuncCall(str, obj);
                break;
index 0547b64a6e76ae3c4c9c28a7b6c791c3a0b9a3be..543aea9928369021b4b597492519421cebd92909 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.674 2009/07/29 20:56:19 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.675 2009/07/30 02:45:37 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -2172,24 +2172,11 @@ ColQualList:
 ColConstraint:
            CONSTRAINT name ColConstraintElem
                {
-                   switch (nodeTag($3))
-                   {
-                       case T_Constraint:
-                           {
-                               Constraint *n = (Constraint *)$3;
-                               n->name = $2;
-                           }
-                           break;
-                       case T_FkConstraint:
-                           {
-                               FkConstraint *n = (FkConstraint *)$3;
-                               n->constr_name = $2;
-                           }
-                           break;
-                       default:
-                           break;
-                   }
-                   $$ = $3;
+                   Constraint *n = (Constraint *) $3;
+                   Assert(IsA(n, Constraint));
+                   n->conname = $2;
+                   n->location = @1;
+                   $$ = (Node *) n;
                }
            | ColConstraintElem                     { $$ = $1; }
            | ConstraintAttr                        { $$ = $1; }
@@ -2215,94 +2202,66 @@ ColConstraintElem:
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_NOTNULL;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
-                   n->keys = NULL;
-                   n->indexspace = NULL;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
            | NULL_P
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_NULL;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
-                   n->keys = NULL;
-                   n->indexspace = NULL;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
            | UNIQUE opt_definition OptConsTableSpace
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_UNIQUE;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
+                   n->location = @1;
                    n->keys = NULL;
                    n->options = $2;
                    n->indexspace = $3;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
                    $$ = (Node *)n;
                }
            | PRIMARY KEY opt_definition OptConsTableSpace
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_PRIMARY;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
+                   n->location = @1;
                    n->keys = NULL;
                    n->options = $3;
                    n->indexspace = $4;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
                    $$ = (Node *)n;
                }
            | CHECK '(' a_expr ')'
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_CHECK;
-                   n->name = NULL;
+                   n->location = @1;
                    n->raw_expr = $3;
                    n->cooked_expr = NULL;
-                   n->keys = NULL;
-                   n->indexspace = NULL;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
                    $$ = (Node *)n;
                }
            | DEFAULT b_expr
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_DEFAULT;
-                   n->name = NULL;
+                   n->location = @1;
                    n->raw_expr = $2;
                    n->cooked_expr = NULL;
-                   n->keys = NULL;
-                   n->indexspace = NULL;
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
                    $$ = (Node *)n;
                }
            | REFERENCES qualified_name opt_column_list key_match key_actions
                {
-                   FkConstraint *n = makeNode(FkConstraint);
-                   n->constr_name      = NULL;
+                   Constraint *n = makeNode(Constraint);
+                   n->contype = CONSTR_FOREIGN;
+                   n->location = @1;
                    n->pktable          = $2;
                    n->fk_attrs         = NIL;
                    n->pk_attrs         = $3;
                    n->fk_matchtype     = $4;
                    n->fk_upd_action    = (char) ($5 >> 8);
                    n->fk_del_action    = (char) ($5 & 0xFF);
-                   n->deferrable       = FALSE;
-                   n->initdeferred     = FALSE;
+                   n->skip_validation  = FALSE;
                    $$ = (Node *)n;
                }
        ;
@@ -2324,24 +2283,28 @@ ConstraintAttr:
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_ATTR_DEFERRABLE;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
            | NOT DEFERRABLE
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
            | INITIALLY DEFERRED
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_ATTR_DEFERRED;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
            | INITIALLY IMMEDIATE
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_ATTR_IMMEDIATE;
+                   n->location = @1;
                    $$ = (Node *)n;
                }
        ;
@@ -2387,24 +2350,11 @@ TableLikeOption:
 TableConstraint:
            CONSTRAINT name ConstraintElem
                {
-                   switch (nodeTag($3))
-                   {
-                       case T_Constraint:
-                           {
-                               Constraint *n = (Constraint *)$3;
-                               n->name = $2;
-                           }
-                           break;
-                       case T_FkConstraint:
-                           {
-                               FkConstraint *n = (FkConstraint *)$3;
-                               n->constr_name = $2;
-                           }
-                           break;
-                       default:
-                           break;
-                   }
-                   $$ = $3;
+                   Constraint *n = (Constraint *) $3;
+                   Assert(IsA(n, Constraint));
+                   n->conname = $2;
+                   n->location = @1;
+                   $$ = (Node *) n;
                }
            | ConstraintElem                        { $$ = $1; }
        ;
@@ -2414,17 +2364,14 @@ ConstraintElem:
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_CHECK;
-                   n->name = NULL;
+                   n->location = @1;
                    n->raw_expr = $3;
                    n->cooked_expr = NULL;
-                   n->indexspace = NULL;
                    if ($5 != 0)
                        ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("CHECK constraints cannot be deferred"),
                                 parser_errposition(@5)));
-                   n->deferrable = FALSE;
-                   n->initdeferred = FALSE;
                    $$ = (Node *)n;
                }
            | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
@@ -2432,9 +2379,7 @@ ConstraintElem:
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_UNIQUE;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
+                   n->location = @1;
                    n->keys = $3;
                    n->options = $5;
                    n->indexspace = $6;
@@ -2447,9 +2392,7 @@ ConstraintElem:
                {
                    Constraint *n = makeNode(Constraint);
                    n->contype = CONSTR_PRIMARY;
-                   n->name = NULL;
-                   n->raw_expr = NULL;
-                   n->cooked_expr = NULL;
+                   n->location = @1;
                    n->keys = $4;
                    n->options = $6;
                    n->indexspace = $7;
@@ -2460,14 +2403,16 @@ ConstraintElem:
            | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
                opt_column_list key_match key_actions ConstraintAttributeSpec
                {
-                   FkConstraint *n = makeNode(FkConstraint);
-                   n->constr_name      = NULL;
+                   Constraint *n = makeNode(Constraint);
+                   n->contype = CONSTR_FOREIGN;
+                   n->location = @1;
                    n->pktable          = $7;
                    n->fk_attrs         = $4;
                    n->pk_attrs         = $8;
                    n->fk_matchtype     = $9;
                    n->fk_upd_action    = (char) ($10 >> 8);
                    n->fk_del_action    = (char) ($10 & 0xFF);
+                   n->skip_validation  = FALSE;
                    n->deferrable       = ($11 & 1) != 0;
                    n->initdeferred     = ($11 & 2) != 0;
                    $$ = (Node *)n;
index 94c8c5977bc5f995bd270022ac4b227c138b681b..7a11eb96edd6723c6ee09568dc23ea92a20e3d64 100644 (file)
@@ -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.24 2009/07/29 20:56:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.25 2009/07/30 02:45:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -112,7 +112,7 @@ static void transformFKConstraints(ParseState *pstate,
                       CreateStmtContext *cxt,
                       bool skipValidation,
                       bool isAddConstraint);
-static void transformConstraintAttrs(List *constraintList);
+static void transformConstraintAttrs(ParseState *pstate, List *constraintList);
 static void transformColumnType(ParseState *pstate, ColumnDef *column);
 static void setSchemaName(char *context_schema, char **stmt_schema_name);
 
@@ -199,11 +199,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
                                         (Constraint *) element);
                break;
 
-           case T_FkConstraint:
-               /* No pre-transformation needed */
-               cxt.fkconstraints = lappend(cxt.fkconstraints, element);
-               break;
-
            case T_InhRelation:
                transformInhRelation(pstate, &cxt,
                                     (InhRelation *) element);
@@ -295,7 +290,8 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
        if (is_serial && column->typeName->arrayBounds != NIL)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                    errmsg("array of serial is not implemented")));
+                    errmsg("array of serial is not implemented"),
+                    parser_errposition(pstate, column->typeName->location)));
    }
 
    /* Do necessary work on the column type declaration */
@@ -397,18 +393,19 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 
        constraint = makeNode(Constraint);
        constraint->contype = CONSTR_DEFAULT;
+       constraint->location = -1;
        constraint->raw_expr = (Node *) funccallnode;
        constraint->cooked_expr = NULL;
-       constraint->keys = NIL;
        column->constraints = lappend(column->constraints, constraint);
 
        constraint = makeNode(Constraint);
        constraint->contype = CONSTR_NOTNULL;
+       constraint->location = -1;
        column->constraints = lappend(column->constraints, constraint);
    }
 
    /* Process column constraints, if any... */
-   transformConstraintAttrs(column->constraints);
+   transformConstraintAttrs(pstate, column->constraints);
 
    saw_nullable = false;
    saw_default = false;
@@ -416,21 +413,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
    foreach(clist, column->constraints)
    {
        constraint = lfirst(clist);
-
-       /*
-        * If this column constraint is a FOREIGN KEY constraint, then we fill
-        * in the current attribute's name and throw it into the list of FK
-        * constraints to be processed later.
-        */
-       if (IsA(constraint, FkConstraint))
-       {
-           FkConstraint *fkconstraint = (FkConstraint *) constraint;
-
-           fkconstraint->fk_attrs = list_make1(makeString(column->colname));
-           cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint);
-           continue;
-       }
-
        Assert(IsA(constraint, Constraint));
 
        switch (constraint->contype)
@@ -440,7 +422,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
-                                 column->colname, cxt->relation->relname)));
+                                   column->colname, cxt->relation->relname),
+                            parser_errposition(pstate,
+                                               constraint->location)));
                column->is_not_null = FALSE;
                saw_nullable = true;
                break;
@@ -450,7 +434,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
-                                 column->colname, cxt->relation->relname)));
+                                   column->colname, cxt->relation->relname),
+                            parser_errposition(pstate,
+                                               constraint->location)));
                column->is_not_null = TRUE;
                saw_nullable = true;
                break;
@@ -460,7 +446,9 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
-                                 column->colname, cxt->relation->relname)));
+                                   column->colname, cxt->relation->relname),
+                            parser_errposition(pstate,
+                                               constraint->location)));
                column->raw_default = constraint->raw_expr;
                Assert(constraint->cooked_expr == NULL);
                saw_default = true;
@@ -477,6 +465,15 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
                break;
 
+           case CONSTR_FOREIGN:
+               /*
+                * Fill in the current attribute's name and throw it into the
+                * list of FK constraints to be processed later.
+                */
+               constraint->fk_attrs = list_make1(makeString(column->colname));
+               cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
+               break;
+
            case CONSTR_ATTR_DEFERRABLE:
            case CONSTR_ATTR_NOT_DEFERRABLE:
            case CONSTR_ATTR_DEFERRED:
@@ -511,6 +508,10 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
            cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
            break;
 
+       case CONSTR_FOREIGN:
+           cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
+           break;
+
        case CONSTR_NULL:
        case CONSTR_NOTNULL:
        case CONSTR_DEFAULT:
@@ -688,11 +689,11 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
            change_varattnos_of_a_node(ccbin_node, attmap);
 
            n->contype = CONSTR_CHECK;
-           n->name = pstrdup(ccname);
+           n->location = -1;
+           n->conname = pstrdup(ccname);
            n->raw_expr = NULL;
            n->cooked_expr = nodeToString(ccbin_node);
-           n->indexspace = NULL;
-           cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n);
+           cxt->ckconstraints = lappend(cxt->ckconstraints, n);
        }
    }
 
@@ -1121,8 +1122,8 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
    index->deferrable = constraint->deferrable;
    index->initdeferred = constraint->initdeferred;
 
-   if (constraint->name != NULL)
-       index->idxname = pstrdup(constraint->name);
+   if (constraint->conname != NULL)
+       index->idxname = pstrdup(constraint->conname);
    else
        index->idxname = NULL;  /* DefineIndex will choose name */
 
@@ -1281,9 +1282,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt,
    {
        foreach(fkclist, cxt->fkconstraints)
        {
-           FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist);
+           Constraint *constraint = (Constraint *) lfirst(fkclist);
 
-           fkconstraint->skip_validation = true;
+           constraint->skip_validation = true;
        }
    }
 
@@ -1308,12 +1309,12 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt,
 
        foreach(fkclist, cxt->fkconstraints)
        {
-           FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist);
+           Constraint *constraint = (Constraint *) lfirst(fkclist);
            AlterTableCmd *altercmd = makeNode(AlterTableCmd);
 
            altercmd->subtype = AT_ProcessedConstraint;
            altercmd->name = NULL;
-           altercmd->def = (Node *) fkconstraint;
+           altercmd->def = (Node *) constraint;
            alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
        }
 
@@ -1784,12 +1785,11 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
                 * The original AddConstraint cmd node doesn't go to newcmds
                 */
                if (IsA(cmd->def, Constraint))
+               {
                    transformTableConstraint(pstate, &cxt,
                                             (Constraint *) cmd->def);
-               else if (IsA(cmd->def, FkConstraint))
-               {
-                   cxt.fkconstraints = lappend(cxt.fkconstraints, cmd->def);
-                   skipValidation = false;
+                   if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
+                       skipValidation = false;
                }
                else
                    elog(ERROR, "unrecognized node type: %d",
@@ -1886,145 +1886,112 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
  * for other constraint types.
  */
 static void
-transformConstraintAttrs(List *constraintList)
+transformConstraintAttrs(ParseState *pstate, List *constraintList)
 {
-   Node       *lastprimarynode = NULL;
+   Constraint *lastprimarycon = NULL;
    bool        saw_deferrability = false;
    bool        saw_initially = false;
    ListCell   *clist;
 
-#define SUPPORTS_ATTRS(node)                               \
-   ((node) != NULL &&                                      \
-    (IsA((node), FkConstraint) ||                          \
-     (IsA((node), Constraint) &&                           \
-      (((Constraint *) (node))->contype == CONSTR_PRIMARY || \
-       ((Constraint *) (node))->contype == CONSTR_UNIQUE))))
+#define SUPPORTS_ATTRS(node)               \
+   ((node) != NULL &&                      \
+    ((node)->contype == CONSTR_PRIMARY ||  \
+     (node)->contype == CONSTR_UNIQUE ||   \
+     (node)->contype == CONSTR_FOREIGN))
 
    foreach(clist, constraintList)
    {
-       Node       *node = lfirst(clist);
+       Constraint *con = (Constraint *) lfirst(clist);
 
-       if (!IsA(node, Constraint))
+       if (!IsA(con, Constraint))
+           elog(ERROR, "unrecognized node type: %d",
+                (int) nodeTag(con));
+       switch (con->contype)
        {
-           lastprimarynode = node;
-           /* reset flags for new primary node */
-           saw_deferrability = false;
-           saw_initially = false;
-       }
-       else
-       {
-           Constraint *con = (Constraint *) node;
-
-           switch (con->contype)
-           {
-               case CONSTR_ATTR_DEFERRABLE:
-                   if (!SUPPORTS_ATTRS(lastprimarynode))
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("misplaced DEFERRABLE clause")));
-                   if (saw_deferrability)
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed")));
-                   saw_deferrability = true;
-                   if (IsA(lastprimarynode, FkConstraint))
-                       ((FkConstraint *) lastprimarynode)->deferrable = true;
-                   else
-                       ((Constraint *) lastprimarynode)->deferrable = true;
-                   break;
+           case CONSTR_ATTR_DEFERRABLE:
+               if (!SUPPORTS_ATTRS(lastprimarycon))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("misplaced DEFERRABLE clause"),
+                            parser_errposition(pstate, con->location)));
+               if (saw_deferrability)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
+                            parser_errposition(pstate, con->location)));
+               saw_deferrability = true;
+               lastprimarycon->deferrable = true;
+               break;
 
-               case CONSTR_ATTR_NOT_DEFERRABLE:
-                   if (!SUPPORTS_ATTRS(lastprimarynode))
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("misplaced NOT DEFERRABLE clause")));
-                   if (saw_deferrability)
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed")));
-                   saw_deferrability = true;
-                   if (IsA(lastprimarynode, FkConstraint))
-                   {
-                       ((FkConstraint *) lastprimarynode)->deferrable = false;
-                       if (saw_initially &&
-                           ((FkConstraint *) lastprimarynode)->initdeferred)
-                           ereport(ERROR,
-                                   (errcode(ERRCODE_SYNTAX_ERROR),
-                                    errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
-                   }
-                   else
-                   {
-                       ((Constraint *) lastprimarynode)->deferrable = false;
-                       if (saw_initially &&
-                           ((Constraint *) lastprimarynode)->initdeferred)
-                           ereport(ERROR,
-                                   (errcode(ERRCODE_SYNTAX_ERROR),
-                                    errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
-                   }
-                   break;
+           case CONSTR_ATTR_NOT_DEFERRABLE:
+               if (!SUPPORTS_ATTRS(lastprimarycon))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("misplaced NOT DEFERRABLE clause"),
+                            parser_errposition(pstate, con->location)));
+               if (saw_deferrability)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
+                            parser_errposition(pstate, con->location)));
+               saw_deferrability = true;
+               lastprimarycon->deferrable = false;
+               if (saw_initially &&
+                   lastprimarycon->initdeferred)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
+                            parser_errposition(pstate, con->location)));
+               break;
 
-               case CONSTR_ATTR_DEFERRED:
-                   if (!SUPPORTS_ATTRS(lastprimarynode))
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                            errmsg("misplaced INITIALLY DEFERRED clause")));
-                   if (saw_initially)
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed")));
-                   saw_initially = true;
+           case CONSTR_ATTR_DEFERRED:
+               if (!SUPPORTS_ATTRS(lastprimarycon))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("misplaced INITIALLY DEFERRED clause"),
+                            parser_errposition(pstate, con->location)));
+               if (saw_initially)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
+                            parser_errposition(pstate, con->location)));
+               saw_initially = true;
+               lastprimarycon->initdeferred = true;
 
-                   /*
-                    * If only INITIALLY DEFERRED appears, assume DEFERRABLE
-                    */
-                   if (IsA(lastprimarynode, FkConstraint))
-                   {
-                       ((FkConstraint *) lastprimarynode)->initdeferred = true;
-
-                       if (!saw_deferrability)
-                           ((FkConstraint *) lastprimarynode)->deferrable = true;
-                       else if (!((FkConstraint *) lastprimarynode)->deferrable)
-                           ereport(ERROR,
-                                   (errcode(ERRCODE_SYNTAX_ERROR),
-                                    errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
-                   }
-                   else
-                   {
-                       ((Constraint *) lastprimarynode)->initdeferred = true;
-
-                       if (!saw_deferrability)
-                           ((Constraint *) lastprimarynode)->deferrable = true;
-                       else if (!((Constraint *) lastprimarynode)->deferrable)
-                           ereport(ERROR,
-                                   (errcode(ERRCODE_SYNTAX_ERROR),
-                                    errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
-                   }
-                   break;
+               /*
+                * If only INITIALLY DEFERRED appears, assume DEFERRABLE
+                */
+               if (!saw_deferrability)
+                   lastprimarycon->deferrable = true;
+               else if (!lastprimarycon->deferrable)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
+                            parser_errposition(pstate, con->location)));
+               break;
 
-               case CONSTR_ATTR_IMMEDIATE:
-                   if (!SUPPORTS_ATTRS(lastprimarynode))
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                           errmsg("misplaced INITIALLY IMMEDIATE clause")));
-                   if (saw_initially)
-                       ereport(ERROR,
-                               (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed")));
-                   saw_initially = true;
-                   if (IsA(lastprimarynode, FkConstraint))
-                       ((FkConstraint *) lastprimarynode)->initdeferred = false;
-                   else
-                       ((Constraint *) lastprimarynode)->initdeferred = false;
-                   break;
+           case CONSTR_ATTR_IMMEDIATE:
+               if (!SUPPORTS_ATTRS(lastprimarycon))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("misplaced INITIALLY IMMEDIATE clause"),
+                            parser_errposition(pstate, con->location)));
+               if (saw_initially)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_SYNTAX_ERROR),
+                            errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
+                            parser_errposition(pstate, con->location)));
+               saw_initially = true;
+               lastprimarycon->initdeferred = false;
+               break;
 
-               default:
-                   /* Otherwise it's not an attribute */
-                   lastprimarynode = node;
-                   /* reset flags for new primary node */
-                   saw_deferrability = false;
-                   saw_initially = false;
-                   break;
-           }
+           default:
+               /* Otherwise it's not an attribute */
+               lastprimarycon = con;
+               /* reset flags for new primary node */
+               saw_deferrability = false;
+               saw_initially = false;
+               break;
        }
    }
 }
index f255c44d1cb8f0bbf4b0de78b8514052837aad99..b29f7203cab76522bd2e46a3c419d705a6e8ac93 100644 (file)
@@ -7,7 +7,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/nodes.h,v 1.223 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.224 2009/07/30 02:45:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -364,7 +364,6 @@ typedef enum NodeTag
    T_RangeTblEntry,
    T_SortGroupClause,
    T_WindowClause,
-   T_FkConstraint,
    T_PrivGrantee,
    T_FuncWithArgs,
    T_AccessPriv,
index ae2f087360887092d1cc2bd5f95765a30f47c12a..d0573455a0572acc4c4544b910005648ddc34d9e 100644 (file)
@@ -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.399 2009/07/29 20:56:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.400 2009/07/30 02:45:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1317,10 +1317,10 @@ typedef struct VariableShowStmt
 /* ----------------------
  *     Create Table Statement
  *
- * NOTE: in the raw gram.y output, ColumnDef, Constraint, and FkConstraint
- * nodes are intermixed in tableElts, and constraints is NIL.  After parse
- * analysis, tableElts contains just ColumnDefs, and constraints contains
- * just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present
+ * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are
+ * intermixed in tableElts, and constraints is NIL.  After parse analysis,
+ * tableElts contains just ColumnDefs, and constraints contains just
+ * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present
  * implementation).
  * ----------------------
  */
@@ -1339,23 +1339,32 @@ typedef struct CreateStmt
 } CreateStmt;
 
 /* ----------
- * Definitions for plain (non-FOREIGN KEY) constraints in CreateStmt
+ * Definitions for constraints in CreateStmt
  *
- * XXX probably these ought to be unified with FkConstraints at some point?
- * To this end we include CONSTR_FOREIGN in the ConstrType enum, even though
- * the parser does not generate it.
+ * Note that column defaults are treated as a type of constraint,
+ * even though that's a bit odd semantically.
  *
- * For constraints that use expressions (CONSTR_DEFAULT, CONSTR_CHECK)
+ * For constraints that use expressions (CONSTR_CHECK, CONSTR_DEFAULT)
  * we may have the expression in either "raw" form (an untransformed
  * parse tree) or "cooked" form (the nodeToString representation of
  * an executable expression tree), depending on how this Constraint
  * node was created (by parsing, or by inheritance from an existing
  * relation).  We should never have both in the same node!
  *
+ * FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype
+ * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are
+ * stored into pg_constraint.confmatchtype.  Changing the code values may
+ * require an initdb!
+ *
+ * If skip_validation is true then we skip checking that the existing rows
+ * in the table satisfy the constraint, and just install the catalog entries
+ * for the constraint. This is currently used only during CREATE TABLE
+ * (when we know the table must be empty).
+ *
  * Constraint attributes (DEFERRABLE etc) are initially represented as
  * separate Constraint nodes for simplicity of parsing.  parse_utilcmd.c makes
- * a pass through the constraints list to attach the info to the appropriate
- * Constraint and FkConstraint nodes.
+ * a pass through the constraints list to insert the info into the appropriate
+ * Constraint node.
  * ----------
  */
 
@@ -1365,69 +1374,56 @@ typedef enum ConstrType         /* types of constraints */
    CONSTR_NOTNULL,
    CONSTR_DEFAULT,
    CONSTR_CHECK,
-   CONSTR_FOREIGN,
    CONSTR_PRIMARY,
    CONSTR_UNIQUE,
+   CONSTR_FOREIGN,
    CONSTR_ATTR_DEFERRABLE,     /* attributes for previous constraint node */
    CONSTR_ATTR_NOT_DEFERRABLE,
    CONSTR_ATTR_DEFERRED,
    CONSTR_ATTR_IMMEDIATE
 } ConstrType;
 
-typedef struct Constraint
-{
-   NodeTag     type;
-   ConstrType  contype;
-   char       *name;           /* name, or NULL if unnamed */
-   Node       *raw_expr;       /* expr, as untransformed parse tree */
-   char       *cooked_expr;    /* expr, as nodeToString representation */
-   List       *keys;           /* String nodes naming referenced column(s) */
-   List       *options;        /* options from WITH clause */
-   char       *indexspace;     /* index tablespace for PKEY/UNIQUE
-                                * constraints; NULL for default */
-   bool        deferrable;     /* DEFERRABLE */
-   bool        initdeferred;   /* INITIALLY DEFERRED */
-} Constraint;
-
-/* ----------
- * Definitions for FOREIGN KEY constraints in CreateStmt
- *
- * Note: FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype
- * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are
- * stored into pg_constraint.confmatchtype.  Changing the code values may
- * require an initdb!
- *
- * If skip_validation is true then we skip checking that the existing rows
- * in the table satisfy the constraint, and just install the catalog entries
- * for the constraint. This is currently used only during CREATE TABLE
- * (when we know the table must be empty).
- * ----------
- */
+/* Foreign key action codes */
 #define FKCONSTR_ACTION_NOACTION   'a'
 #define FKCONSTR_ACTION_RESTRICT   'r'
 #define FKCONSTR_ACTION_CASCADE        'c'
 #define FKCONSTR_ACTION_SETNULL        'n'
 #define FKCONSTR_ACTION_SETDEFAULT 'd'
 
+/* Foreign key matchtype codes */
 #define FKCONSTR_MATCH_FULL            'f'
 #define FKCONSTR_MATCH_PARTIAL     'p'
 #define FKCONSTR_MATCH_UNSPECIFIED 'u'
 
-typedef struct FkConstraint
+typedef struct Constraint
 {
    NodeTag     type;
-   char       *constr_name;    /* Constraint name, or NULL if unnamed */
+   ConstrType  contype;        /* see above */
+
+   /* Fields used for most/all constraint types: */
+   char       *conname;        /* Constraint name, or NULL if unnamed */
+   bool        deferrable;     /* DEFERRABLE? */
+   bool        initdeferred;   /* INITIALLY DEFERRED? */
+   int         location;       /* token location, or -1 if unknown */
+
+   /* Fields used for constraints with expressions (CHECK and DEFAULT): */
+   Node       *raw_expr;       /* expr, as untransformed parse tree */
+   char       *cooked_expr;    /* expr, as nodeToString representation */
+
+   /* Fields used for index constraints (UNIQUE and PRIMARY KEY): */
+   List       *keys;           /* String nodes naming referenced column(s) */
+   List       *options;        /* options from WITH clause */
+   char       *indexspace;     /* index tablespace; NULL for default */
+
+   /* Fields used for FOREIGN KEY constraints: */
    RangeVar   *pktable;        /* Primary key table */
    List       *fk_attrs;       /* Attributes of foreign key */
    List       *pk_attrs;       /* Corresponding attrs in PK table */
    char        fk_matchtype;   /* FULL, PARTIAL, UNSPECIFIED */
    char        fk_upd_action;  /* ON UPDATE action */
    char        fk_del_action;  /* ON DELETE action */
-   bool        deferrable;     /* DEFERRABLE */
-   bool        initdeferred;   /* INITIALLY DEFERRED */
    bool        skip_validation;    /* skip validation of existing rows? */
-} FkConstraint;
-
+} Constraint;
 
 /* ----------------------
  *     Create/Drop Table Space Statements