]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add SQL92-compliant syntax for constraints.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Thu, 4 Dec 1997 23:07:23 +0000 (23:07 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Thu, 4 Dec 1997 23:07:23 +0000 (23:07 +0000)
Implement PRIMARY KEY and UNIQUE clauses using indices.

src/backend/parser/analyze.c
src/backend/parser/gram.y

index 30bdd9c0627e227154a986d1fde805d7fc7ab982..63b990aa7472fc7097ea6f9377927790434ddb1d 100644 (file)
@@ -7,13 +7,14 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.51 1997/11/26 01:11:03 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.52 1997/12/04 23:07:18 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 
 #include "postgres.h"
@@ -39,7 +40,9 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
 static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
 static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
 static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
+static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
 
+List   *extras = NIL;
 
 /*
  * parse_analyze -
@@ -65,6 +68,17 @@ parse_analyze(List *pl)
        {
                pstate = make_parsestate();
                result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
+               if (extras != NIL)
+               {
+                       result->len += length(extras);
+                       result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
+                       while (extras != NIL)
+                       {
+                               result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
+                               extras = lnext(extras);
+                       }
+               }
+               extras = NIL;
                pl = lnext(pl);
                if (pstate->p_target_relation != NULL)
                        heap_close(pstate->p_target_relation);
@@ -90,6 +104,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
                         *      Non-optimizable statements
                         *------------------------
                         */
+               case T_CreateStmt:
+                       result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
+                       break;
+
                case T_IndexStmt:
                        result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
                        break;
@@ -309,6 +327,316 @@ transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
        return (Query *) qry;
 }
 
+/* makeTableName()
+ * Create a table name from a list of fields.
+ */
+static char *
+makeTableName(void *elem,...);
+
+static char *
+makeTableName(void *elem,...)
+{
+       va_list args;
+
+       char   *name;
+       char    buf[NAMEDATALEN+1];
+
+       strcpy(buf,"");
+
+       va_start(args,elem);
+
+       name = elem;
+       while (name != NULL)
+       {
+               /* not enough room for next part? then return nothing */
+               if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
+                       return (NULL);
+
+               if (strlen(buf) > 0) strcat(buf,"_");
+               strcat(buf,name);
+
+               name = va_arg(args,void *);
+       }
+
+       va_end(args);
+
+       name = palloc(strlen(buf)+1);
+       strcpy(name,buf);
+
+       return (name);
+} /* makeTableName() */
+
+/*
+ * transformCreateStmt -
+ *       transforms the "create table" statement
+ *       SQL92 allows constraints to be scattered all over, so thumb through
+ *        the columns and collect all constraints into one place.
+ *       If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
+ *        then expand those into multiple IndexStmt blocks.
+ *       - thomas 1997-12-02
+ */
+static Query *
+transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
+{
+       Query      *q;
+       List       *elements;
+       Node       *element;
+       List       *columns;
+       List       *dlist;
+       ColumnDef  *column;
+       List       *constraints, *clist;
+       Constraint *constraint;
+       List       *keys;
+       Ident      *key;
+       List       *ilist;
+       IndexStmt  *index;
+       IndexElem  *iparam;
+
+       q = makeNode(Query);
+       q->commandType = CMD_UTILITY;
+
+       elements = stmt->tableElts;
+       constraints = stmt->constraints;
+       columns = NIL;
+       dlist = NIL;
+
+       while (elements != NIL)
+       {
+               element = lfirst(elements);
+               switch (nodeTag(element))
+               {
+                       case T_ColumnDef:
+                               column = (ColumnDef *) element;
+#if PARSEDEBUG
+printf("transformCreateStmt- found column %s\n",column->colname);
+#endif
+                               columns = lappend(columns,column);
+                               if (column->constraints != NIL)
+                               {
+#if PARSEDEBUG
+printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
+#endif
+                                       clist = column->constraints;
+                                       while (clist != NIL)
+                                       {
+                                               constraint = lfirst(clist);
+                                               switch (constraint->contype)
+                                               {
+                                                       case CONSTR_NOTNULL:
+#if PARSEDEBUG
+printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
+#endif
+                                                               if (column->is_not_null)
+                                                                       elog(WARN,"CREATE TABLE/NOT NULL already specified"
+                                                                               " for %s.%s", stmt->relname, column->colname);
+                                                               column->is_not_null = TRUE;
+                                                               break;
+
+                                                       case CONSTR_DEFAULT:
+#if PARSEDEBUG
+printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
+#endif
+                                                               if (column->defval != NULL)
+                                                                       elog(WARN,"CREATE TABLE/DEFAULT multiple values specified"
+                                                                               " for %s.%s", stmt->relname, column->colname);
+                                                               column->defval = constraint->def;
+                                                               break;
+
+                                                       case CONSTR_PRIMARY:
+#if PARSEDEBUG
+printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
+#endif
+                                                               if (constraint->name == NULL)
+                                                                       constraint->name = makeTableName(stmt->relname, "pkey", NULL);
+                                                               if (constraint->keys == NIL)
+                                                                       constraint->keys = lappend(constraint->keys, column);
+                                                               dlist = lappend(dlist, constraint);
+                                                               break;
+
+                                                       case CONSTR_UNIQUE:
+#if PARSEDEBUG
+printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
+#endif
+                                                               if (constraint->name == NULL)
+                                                                       constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
+                                                               if (constraint->keys == NIL)
+                                                                       constraint->keys = lappend(constraint->keys, column);
+                                                               dlist = lappend(dlist, constraint);
+                                                               break;
+
+                                                       case CONSTR_CHECK:
+#if PARSEDEBUG
+printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
+#endif
+                                                               constraints = lappend(constraints, constraint);
+                                                               if (constraint->name == NULL)
+                                                                       constraint->name = makeTableName(stmt->relname, ".", column->colname, NULL);
+                                                               break;
+
+                                                       default:
+                                                               elog(WARN,"parser: internal error; unrecognized constraint",NULL);
+                                                               break;
+                                               }
+                                               clist = lnext(clist);
+                                       }
+                               }
+                               break;
+
+                       case T_Constraint:
+                               constraint = (Constraint *) element;
+#if PARSEDEBUG
+printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
+#endif
+                               switch (constraint->contype)
+                               {
+                                       case CONSTR_PRIMARY:
+#if PARSEDEBUG
+printf("transformCreateStmt- found PRIMARY KEY clause\n");
+#endif
+                                               if (constraint->name == NULL)
+                                                       constraint->name = makeTableName(stmt->relname, "pkey", NULL);
+                                               dlist = lappend(dlist, constraint);
+                                               break;
+
+                                       case CONSTR_UNIQUE:
+#if PARSEDEBUG
+printf("transformCreateStmt- found UNIQUE clause\n");
+#endif
+#if FALSE
+                                               if (constraint->name == NULL)
+                                                       constraint->name = makeTableName(stmt->relname, "key", NULL);
+#endif
+                                               dlist = lappend(dlist, constraint);
+                                               break;
+
+                                       case CONSTR_CHECK:
+#if PARSEDEBUG
+printf("transformCreateStmt- found CHECK clause\n");
+#endif
+                                               constraints = lappend(constraints, constraint);
+                                               break;
+
+                                       case CONSTR_NOTNULL:
+                                       case CONSTR_DEFAULT:
+                                               elog(WARN,"parser: internal error; illegal context for constraint",NULL);
+                                               break;
+                                       default:
+                                               elog(WARN,"parser: internal error; unrecognized constraint",NULL);
+                                               break;
+                               }
+                               break;
+
+                       default:
+                               elog(WARN,"parser: internal error; unrecognized node",NULL);
+               }
+
+               elements = lnext(elements);
+       }
+
+       stmt->tableElts = columns;
+       stmt->constraints = constraints;
+
+/* Now run through the "deferred list" to complete the query transformation.
+ * For PRIMARY KEYs, mark each column as NOT NULL and create an index.
+ * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
+ *
+ * Note that this code does not currently look for all possible redundant cases
+ *  and either ignore or stop with warning. The create will fail later when
+ *  names for indices turn out to be redundant, or a user might just find
+ *  extra useless indices which might kill performance. - thomas 1997-12-04
+ */
+       ilist = NIL;
+       while (dlist != NIL)
+       {
+               constraint = lfirst(dlist);
+               if (nodeTag(constraint) != T_Constraint)
+                       elog(WARN,"parser: internal error; unrecognized deferred node",NULL);
+
+               if ((constraint->contype != CONSTR_PRIMARY)
+                && (constraint->contype != CONSTR_UNIQUE))
+                       elog(WARN,"parser: internal error; illegal deferred constraint",NULL);
+
+#if PARSEDEBUG
+printf("transformCreateStmt- found deferred constraint %s\n",
+ ((constraint->name != NULL)? constraint->name: "(unknown)"));
+#endif
+
+#if PARSEDEBUG
+printf("transformCreateStmt- found deferred %s clause\n",
+ (constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
+#endif
+               index = makeNode(IndexStmt);
+               ilist = lappend(ilist, index);
+
+               index->unique = TRUE;
+               if (constraint->name != NULL)
+                       index->idxname = constraint->name;
+               else if (constraint->contype == CONSTR_PRIMARY)
+                       index->idxname = makeTableName(stmt->relname, "pkey", NULL);
+               else
+                       index->idxname = NULL;
+
+               index->relname = stmt->relname;
+               index->accessMethod = "btree";
+               index->indexParams = NIL;
+               index->withClause = NIL;
+               index->whereClause = NULL;
+               keys = constraint->keys;
+               while (keys != NIL)
+               {
+                       key = lfirst(keys);
+#if PARSEDEBUG
+printf("transformCreateStmt- check key %s for column match\n", key->name);
+#endif
+                       columns = stmt->tableElts;
+                       column = NULL;
+                       while (columns != NIL)
+                       {
+                               column = lfirst(columns);
+#if PARSEDEBUG
+printf("transformCreateStmt- check column %s for key match\n", column->colname);
+#endif
+                               if (strcasecmp(column->colname,key->name) == 0) break;
+                               else column = NULL;
+                               columns = lnext(columns);
+                       }
+                       if (column == NULL)
+                               elog(WARN,"parser: column '%s' in key does not exist",key->name);
+
+                       if (constraint->contype == CONSTR_PRIMARY)
+                       {
+#if PARSEDEBUG
+printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
+#endif
+                               column->is_not_null = TRUE;
+                       }
+                       iparam = makeNode(IndexElem);
+                       iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
+                       iparam->args = NIL;
+                       iparam->class = NULL;
+                       iparam->tname = NULL;
+                       index->indexParams = lappend(index->indexParams, iparam);
+
+                       if (index->idxname == NULL)
+                               index->idxname = makeTableName(stmt->relname, iparam->name, "key", NULL);
+
+                       keys = lnext(keys);
+               }
+
+               if (index->idxname == NULL)
+                       elog(WARN,"parser: unable to construct implicit index for table %s"
+                               "; name too long", stmt->relname);
+
+               dlist = lnext(dlist);
+       }
+
+       q->utilityStmt = (Node *) stmt;
+       extras = ilist;
+
+       return q;
+} /* transformCreateStmt() */
+
 /*
  * transformIndexStmt -
  *       transforms the qualification of the index statement
index a7bc22d67c2b17c19e8e4704d47cca475792ae95..145a2f0e3d2f9d06ca14344c94a39cc5f32bc6a0 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.76 1997/12/04 00:26:57 scrappy Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.77 1997/12/04 23:07:23 thomas Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -39,6 +39,7 @@
 #include "nodes/parsenodes.h"
 #include "nodes/print.h"
 #include "parser/gramparse.h"
+#include "parser/parse_type.h"
 #include "utils/acl.h"
 #include "utils/palloc.h"
 #include "catalog/catname.h"
@@ -91,8 +92,6 @@ Oid   param_type(int t); /* used in parse_expr.c */
 
        Attr                            *attr;
 
-       ColumnDef                       *coldef;
-       ConstraintDef           *constrdef;
        TypeName                        *typnam;
        DefElem                         *defelt;
        ParamString                     *param;
@@ -149,8 +148,8 @@ Oid param_type(int t); /* used in parse_expr.c */
 %type <chr>            operation, TriggerOneEvent
 
 %type <list>   stmtblock, stmtmulti,
-               relation_name_list, OptTableElementList, tableElementList,
-               OptInherit, OptConstraint, ConstraintList, definition,
+               relation_name_list, OptTableElementList,
+               OptInherit, definition,
                opt_with, def_args, def_name_list, func_argtypes,
                oper_argtypes, OptStmtList, OptStmtBlock, OptStmtMulti,
                opt_column_list, columnList, opt_va_list, va_list,
@@ -184,7 +183,8 @@ Oid param_type(int t); /* used in parse_expr.c */
 %type <dstmt>  def_rest
 %type <astmt>  insert_rest
 
-%type <coldef> columnDef, alter_clause
+%type <node>   OptTableElement, ConstraintElem
+%type <node>   columnDef, alter_clause
 %type <defelt> def_elem
 %type <node>   def_arg, columnElem, where_clause,
                                a_expr, a_expr_or_null, AexprConst,
@@ -211,12 +211,11 @@ Oid       param_type(int t); /* used in parse_expr.c */
 %type <str>            Id, var_value, zone_value
 %type <str>            ColId, ColLabel
 
-%type <constrdef>      ConstraintElem, ConstraintDef
-
-%type <list>   constraint_elem
+%type <node>   TableConstraint
+%type <list>   constraint_expr
 %type <list>   default_expr
-%type <str>            opt_default
-%type <boolean>        opt_constraint
+%type <list>   ColQualList
+%type <node>   ColConstraint, ColConstraintElem
 %type <list>   key_actions, key_action
 %type <str>            key_match, key_reference
 
@@ -236,7 +235,7 @@ Oid param_type(int t); /* used in parse_expr.c */
  */
 
 /* Keywords (in SQL92 reserved words) */
-%token ACTION, ADD, ALL, ALTER, AND, ARCHIVE, AS, ASC,
+%token ACTION, ADD, ALL, ALTER, AND, AS, ASC,
                BEGIN_TRANS, BETWEEN, BOTH, BY,
                CASCADE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COLLATE, COLUMN, COMMIT, 
                CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME, 
@@ -276,6 +275,9 @@ Oid param_type(int t); /* used in parse_expr.c */
                SEQUENCE, SETOF, SHOW, STDIN, STDOUT, TRUSTED, 
                VACUUM, VERBOSE, VERSION
 
+/* Keywords (obsolete; retain temporarily for parser - thomas 1997-12-04) */
+%token ARCHIVE
+
 /*
  * Tokens for pg_passwd support.  The CREATEDB and CREATEUSER tokens should go away
  * when some sort of pg_privileges relation is introduced.
@@ -566,9 +568,9 @@ alter_clause:  ADD opt_column columnDef
                                {
                                        $$ = $3;
                                }
-                       | ADD '(' tableElementList ')'
+                       | ADD '(' OptTableElementList ')'
                                {
-                                       ColumnDef *lp = lfirst($3);
+                                       Node *lp = lfirst($3);
 
                                        if (length($3) != 1)
                                                elog(WARN,"ALTER TABLE/ADD() allows one column only",NULL);
@@ -576,7 +578,7 @@ alter_clause:  ADD opt_column columnDef
                                }
                        | DROP opt_column ColId
                                {       elog(WARN,"ALTER TABLE/DROP COLUMN not yet implemented",NULL); }
-                       | ALTER opt_column ColId SET opt_default
+                       | ALTER opt_column ColId SET DEFAULT default_expr
                                {       elog(WARN,"ALTER TABLE/ALTER COLUMN/SET DEFAULT not yet implemented",NULL); }
                        | ALTER opt_column ColId DROP DEFAULT
                                {       elog(WARN,"ALTER TABLE/ALTER COLUMN/DROP DEFAULT not yet implemented",NULL); }
@@ -584,130 +586,6 @@ alter_clause:  ADD opt_column columnDef
                                {       elog(WARN,"ALTER TABLE/ADD CONSTRAINT not yet implemented",NULL); }
                ;
 
-columnDef:  ColId Typename opt_default opt_constraint
-                               {
-                                       $$ = makeNode(ColumnDef);
-                                       $$->colname = $1;
-                                       $$->typename = $2;
-                                       $$->defval = $3;
-                                       $$->is_not_null = $4;
-                               }
-               ;
-
-opt_default:  DEFAULT default_expr
-                               {
-                                       $$ = FlattenStringList($2);
-                               }
-                       | /*EMPTY*/             { $$ = NULL; }
-       ;
-
-default_expr:  AexprConst
-                               {       $$ = makeConstantList((A_Const *) $1); }
-                       | Pnull
-                               {       $$ = lcons( makeString("NULL"), NIL); }
-                       | '-' default_expr %prec UMINUS
-                               {       $$ = lcons( makeString( "-"), $2); }
-                       | default_expr '+' default_expr
-                               {       $$ = nconc( $1, lcons( makeString( "+"), $3)); }
-                       | default_expr '-' default_expr
-                               {       $$ = nconc( $1, lcons( makeString( "-"), $3)); }
-                       | default_expr '/' default_expr
-                               {       $$ = nconc( $1, lcons( makeString( "/"), $3)); }
-                       | default_expr '*' default_expr
-                               {       $$ = nconc( $1, lcons( makeString( "*"), $3)); }
-                       | default_expr '=' default_expr
-                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
-                       | default_expr '<' default_expr
-                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
-                       | default_expr '>' default_expr
-                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
-                       | ':' default_expr
-                               {       $$ = lcons( makeString( ":"), $2); }
-                       | ';' default_expr
-                               {       $$ = lcons( makeString( ";"), $2); }
-                       | '|' default_expr
-                               {       $$ = lcons( makeString( "|"), $2); }
-                       | default_expr TYPECAST Typename
-                               {
-                                       $3->name = fmtId($3->name);
-                                       $$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
-                               }
-                       | CAST default_expr AS Typename
-                               {
-                                       $4->name = fmtId($4->name);
-                                       $$ = nconc( lcons( makeString( "CAST"), $2), makeList( makeString("AS"), $4, -1));
-                               }
-                       | '(' default_expr ')'
-                               {       $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
-                       | name '(' default_expr ')'
-                               {
-                                       $$ = makeList( makeString($1), makeString("("), -1);
-                                       $$ = nconc( $$, $3);
-                                       $$ = lappend( $$, makeString(")"));
-                               }
-                       | name '(' ')'
-                               {
-                                       $$ = makeList( makeString($1), makeString("("), -1);
-                                       $$ = lappend( $$, makeString(")"));
-                               }
-                       | default_expr Op default_expr
-                               {
-                                       if (!strcmp("<=", $2) || !strcmp(">=", $2))
-                                               elog(WARN,"boolean expressions not supported in DEFAULT",NULL);
-                                       $$ = nconc( $1, lcons( makeString( $2), $3));
-                               }
-                       | Op default_expr
-                               {       $$ = lcons( makeString( $1), $2); }
-                       | default_expr Op
-                               {       $$ = lappend( $1, makeString( $2)); }
-                       /* XXX - thomas 1997-10-07 v6.2 function-specific code to be changed */
-                       | CURRENT_DATE
-                               {       $$ = lcons( makeString( "date( 'current'::datetime + '0 sec')"), NIL); }
-                       | CURRENT_TIME
-                               {       $$ = lcons( makeString( "'now'::time"), NIL); }
-                       | CURRENT_TIME '(' Iconst ')'
-                               {
-                                       if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIME(p) precision must be zero",NULL);
-                                       $$ = lcons( makeString( "'now'::time"), NIL);
-                               }
-                       | CURRENT_TIMESTAMP
-                               {       $$ = lcons( makeString( "now()"), NIL); }
-                       | CURRENT_TIMESTAMP '(' Iconst ')'
-                               {
-                                       if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIMESTAMP(p) precision must be zero",NULL);
-                                       $$ = lcons( makeString( "now()"), NIL);
-                               }
-                       | CURRENT_USER
-                               {       $$ = lcons( makeString( "CURRENT_USER"), NIL); }
-               ;
-
-opt_constraint:  NOT NULL_P                                            { $$ = TRUE; }
-                       | NOT NULL_P UNIQUE
-                               {
-                                       elog(NOTICE,"UNIQUE clause ignored; not yet implemented",NULL);
-                                       $$ = TRUE;
-                               }
-                       | NOTNULL                                                       { $$ = TRUE; }
-                       | UNIQUE
-                               {
-                                       elog(NOTICE,"UNIQUE clause ignored; not yet implemented",NULL);
-                                       $$ = FALSE;
-                               }
-                       | PRIMARY KEY
-                               {
-                                       elog(NOTICE,"PRIMARY KEY clause ignored; not yet implemented",NULL);
-                                       $$ = FALSE;
-                               }
-                       | REFERENCES ColId opt_column_list key_match key_actions
-                               {
-                                       elog(NOTICE,"FOREIGN KEY clause ignored; not yet implemented",NULL);
-                                       $$ = FALSE;
-                               }
-                       | /* EMPTY */                                           { $$ = FALSE; }
-               ;
-
 
 /*****************************************************************************
  *
@@ -786,141 +664,318 @@ copy_delimiter:  USING DELIMITERS Sconst { $$ = $3;}
  *****************************************************************************/
 
 CreateStmt:  CREATE TABLE relation_name '(' OptTableElementList ')'
-                               OptInherit OptConstraint OptArchiveType
+                               OptInherit OptArchiveType
                                {
                                        CreateStmt *n = makeNode(CreateStmt);
                                        n->relname = $3;
                                        n->tableElts = $5;
                                        n->inhRelnames = $7;
-                                       n->constraints = $8;
+                                       n->constraints = NIL;
                                        $$ = (Node *)n;
                                }
                ;
 
-OptTableElementList:  tableElementList                 { $$ = $1; }
-               | /* EMPTY */                                                   { $$ = NULL; }
+OptTableElementList:  OptTableElementList ',' OptTableElement
+                                                                                               { $$ = lappend($1, $3); }
+                       | OptTableElement                                       { $$ = lcons($1, NIL); }
+                       | /*EMPTY*/                                                     { $$ = NULL; }
                ;
 
-tableElementList :
-                 tableElementList ',' columnDef
-                               { $$ = lappend($1, $3); }
-               | columnDef
-                               { $$ = lcons($1, NIL); }
+OptTableElement:  columnDef                                            { $$ = $1; }
+                       | TableConstraint                                       { $$ = $1; }
                ;
 
-/*
- *     This was removed in 6.3, but we keep it so people can upgrade
- *     with old pg_dump scripts.
+columnDef:  ColId Typename ColQualList
+                               {
+                                       ColumnDef *n = makeNode(ColumnDef);
+                                       n->colname = $1;
+                                       n->typename = $2;
+                                       n->defval = NULL;
+                                       n->is_not_null = FALSE;
+                                       n->constraints = $3;
+                                       $$ = (Node *)n;
+                               }
+               ;
+
+/* ColQualList decodes column-specific qualifiers.
+ * Seem to need to specify the explicit combinations
+ *  to eliminate reduce/reduce conflicts.
+ * I think this is because there are no explicit delimiters
+ *  (like commas) between clauses.
+ * - thomas 1997-12-03
  */
-OptArchiveType:  ARCHIVE '=' NONE                                              { }
-               | /*EMPTY*/                                                                             { }
+ColQualList:  ColConstraint ColConstraint ColConstraint ColConstraint
+                               { $$ = lappend(lappend(lappend(lcons($1, NIL), $2), $3), $4); }
+                       | ColConstraint ColConstraint ColConstraint
+                               { $$ = lappend(lappend(lcons($1, NIL), $2), $3); }
+                       | ColConstraint ColConstraint           { $$ = lappend(lcons($1, NIL), $2); }
+                       | ColConstraint                                         { $$ = lcons($1, NIL); }
+                       | /*EMPTY*/                                                     { $$ = NULL; }
                ;
 
-OptInherit:  INHERITS '(' relation_name_list ')'               { $$ = $3; }
-               | /*EMPTY*/                                                                             { $$ = NIL; }
+ColConstraint:
+               CONSTRAINT name ColConstraintElem
+                               {
+                                               Constraint *n = (Constraint *)$3;
+                                               n->name = fmtId($2);
+                                               $$ = $3;
+                               }
+               | ColConstraintElem
+                               { $$ = $1; }
                ;
 
-OptConstraint: ConstraintList                                                  { $$ = $1; }
-               | /*EMPTY*/                                                                             { $$ = NULL; }
+ColConstraintElem:  CHECK '(' constraint_expr ')'
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_CHECK;
+                                       n->name = NULL;
+                                       n->def = FlattenStringList($3);
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | DEFAULT default_expr
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_DEFAULT;
+                                       n->name = NULL;
+                                       n->def = FlattenStringList($2);
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | NOT NULL_P
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_NOTNULL;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | NOTNULL
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_NOTNULL;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | UNIQUE
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_UNIQUE;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | PRIMARY KEY
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_PRIMARY;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = NULL;
+                                       $$ = (Node *)n;
+                               }
+                       | REFERENCES ColId opt_column_list key_match key_actions
+                               {
+                                       elog(NOTICE,"CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented",NULL);
+                                       $$ = NULL;
+                               }
                ;
 
-ConstraintList:
-                 ConstraintList ',' ConstraintElem
-                               { $$ = lappend($1, $3); }
-               | ConstraintElem
-                               { $$ = lcons($1, NIL); }
+default_expr:  AexprConst
+                               {       $$ = makeConstantList((A_Const *) $1); }
+                       | NULL_P
+                               {       $$ = lcons( makeString("NULL"), NIL); }
+                       | '-' default_expr %prec UMINUS
+                               {       $$ = lcons( makeString( "-"), $2); }
+                       | default_expr '+' default_expr
+                               {       $$ = nconc( $1, lcons( makeString( "+"), $3)); }
+                       | default_expr '-' default_expr
+                               {       $$ = nconc( $1, lcons( makeString( "-"), $3)); }
+                       | default_expr '/' default_expr
+                               {       $$ = nconc( $1, lcons( makeString( "/"), $3)); }
+                       | default_expr '*' default_expr
+                               {       $$ = nconc( $1, lcons( makeString( "*"), $3)); }
+                       | default_expr '=' default_expr
+                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+                       | default_expr '<' default_expr
+                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+                       | default_expr '>' default_expr
+                               {       elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+                       | ':' default_expr
+                               {       $$ = lcons( makeString( ":"), $2); }
+                       | ';' default_expr
+                               {       $$ = lcons( makeString( ";"), $2); }
+                       | '|' default_expr
+                               {       $$ = lcons( makeString( "|"), $2); }
+                       | default_expr TYPECAST Typename
+                               {
+                                       $3->name = fmtId($3->name);
+                                       $$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
+                               }
+                       | CAST default_expr AS Typename
+                               {
+                                       $4->name = fmtId($4->name);
+                                       $$ = nconc( lcons( makeString( "CAST"), $2), makeList( makeString("AS"), $4, -1));
+                               }
+                       | '(' default_expr ')'
+                               {       $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
+                       | name '(' default_expr ')'
+                               {
+                                       $$ = makeList( makeString($1), makeString("("), -1);
+                                       $$ = nconc( $$, $3);
+                                       $$ = lappend( $$, makeString(")"));
+                               }
+                       | name '(' ')'
+                               {
+                                       $$ = makeList( makeString($1), makeString("("), -1);
+                                       $$ = lappend( $$, makeString(")"));
+                               }
+                       | default_expr Op default_expr
+                               {
+                                       if (!strcmp("<=", $2) || !strcmp(">=", $2))
+                                               elog(WARN,"boolean expressions not supported in DEFAULT",NULL);
+                                       $$ = nconc( $1, lcons( makeString( $2), $3));
+                               }
+                       | Op default_expr
+                               {       $$ = lcons( makeString( $1), $2); }
+                       | default_expr Op
+                               {       $$ = lappend( $1, makeString( $2)); }
+                       /* XXX - thomas 1997-10-07 v6.2 function-specific code to be changed */
+                       | CURRENT_DATE
+                               {       $$ = lcons( makeString( "date( 'current'::datetime + '0 sec')"), NIL); }
+                       | CURRENT_TIME
+                               {       $$ = lcons( makeString( "'now'::time"), NIL); }
+                       | CURRENT_TIME '(' Iconst ')'
+                               {
+                                       if ($3 != 0)
+                                               elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
+                                       $$ = lcons( makeString( "'now'::time"), NIL);
+                               }
+                       | CURRENT_TIMESTAMP
+                               {       $$ = lcons( makeString( "now()"), NIL); }
+                       | CURRENT_TIMESTAMP '(' Iconst ')'
+                               {
+                                       if ($3 != 0)
+                                               elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
+                                       $$ = lcons( makeString( "now()"), NIL);
+                               }
+                       | CURRENT_USER
+                               {       $$ = lcons( makeString( "CURRENT_USER"), NIL); }
                ;
 
-ConstraintElem:
-               CONSTRAINT name ConstraintDef
+/* ConstraintElem specifies constraint syntax which is not embedded into
+ *  a column definition. ColConstraintElem specifies the embedded form.
+ * - thomas 1997-12-03
+ */
+TableConstraint:  CONSTRAINT name ConstraintElem
                                {
-                                               $3->name = fmtId($2);
+                                               Constraint *n = (Constraint *)$3;
+                                               n->name = fmtId($2);
                                                $$ = $3;
                                }
-               | ConstraintDef                 { $$ = $1; }
+               | ConstraintElem
+                               { $$ = $1; }
                ;
 
-ConstraintDef: CHECK constraint_elem
+ConstraintElem:  CHECK '(' constraint_expr ')'
                                {
-                                       ConstraintDef *constr = palloc (sizeof(ConstraintDef));
-                                       constr->type = CONSTR_CHECK;
-                                       constr->name = NULL;
-                                       constr->def = FlattenStringList($2);
-                                       $$ = constr;
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_CHECK;
+                                       n->name = NULL;
+                                       n->def = FlattenStringList($3);
+                                       $$ = (Node *)n;
                                }
                | UNIQUE '(' columnList ')'
-                               {       elog(NOTICE,"CREATE TABLE/UNIQUE clause ignored; not yet implemented",NULL); }
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_UNIQUE;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = $3;
+                                       $$ = (Node *)n;
+                               }
                | PRIMARY KEY '(' columnList ')'
-                               {       elog(NOTICE,"CREATE TABLE/PRIMARY KEY clause ignored; not yet implemented",NULL); }
+                               {
+                                       Constraint *n = makeNode(Constraint);
+                                       n->contype = CONSTR_PRIMARY;
+                                       n->name = NULL;
+                                       n->def = NULL;
+                                       n->keys = $4;
+                                       $$ = (Node *)n;
+                               }
                | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list key_match key_actions
                                {       elog(NOTICE,"CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented",NULL); }
                ;
 
-constraint_elem:  AexprConst
+constraint_expr:  AexprConst
                                {       $$ = makeConstantList((A_Const *) $1); }
-                       | Pnull
+                       | NULL_P
                                {       $$ = lcons( makeString("NULL"), NIL); }
                        | ColId
                                {
                                        $$ = lcons( makeString(fmtId($1)), NIL);
                                }
-                       | '-' constraint_elem %prec UMINUS
+                       | '-' constraint_expr %prec UMINUS
                                {       $$ = lcons( makeString( "-"), $2); }
-                       | constraint_elem '+' constraint_elem
+                       | constraint_expr '+' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "+"), $3)); }
-                       | constraint_elem '-' constraint_elem
+                       | constraint_expr '-' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "-"), $3)); }
-                       | constraint_elem '/' constraint_elem
+                       | constraint_expr '/' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "/"), $3)); }
-                       | constraint_elem '*' constraint_elem
+                       | constraint_expr '*' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "*"), $3)); }
-                       | constraint_elem '=' constraint_elem
+                       | constraint_expr '=' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "="), $3)); }
-                       | constraint_elem '<' constraint_elem
+                       | constraint_expr '<' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "<"), $3)); }
-                       | constraint_elem '>' constraint_elem
+                       | constraint_expr '>' constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( ">"), $3)); }
-                       | ':' constraint_elem
+                       | ':' constraint_expr
                                {       $$ = lcons( makeString( ":"), $2); }
-                       | ';' constraint_elem
+                       | ';' constraint_expr
                                {       $$ = lcons( makeString( ";"), $2); }
-                       | '|' constraint_elem
+                       | '|' constraint_expr
                                {       $$ = lcons( makeString( "|"), $2); }
-                       | constraint_elem TYPECAST Typename
+                       | constraint_expr TYPECAST Typename
                                {
                                        $3->name = fmtId($3->name);
                                        $$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
                                }
-                       | CAST constraint_elem AS Typename
+                       | CAST constraint_expr AS Typename
                                {
                                        $4->name = fmtId($4->name);
                                        $$ = nconc( lcons( makeString( "CAST"), $2), makeList( makeString("AS"), $4, -1));
                                }
-                       | '(' constraint_elem ')'
+                       | '(' constraint_expr ')'
                                {       $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
-                       | name '(' constraint_elem ')'
+                       | name '(' constraint_expr ')'
                                {
                                        $$ = makeList( makeString($1), makeString("("), -1);
                                        $$ = nconc( $$, $3);
                                        $$ = lappend( $$, makeString(")"));
                                }
-                       | constraint_elem Op constraint_elem
+                       | constraint_expr Op constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( $2), $3)); }
-                       | constraint_elem AND constraint_elem
+                       | constraint_expr AND constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "AND"), $3)); }
-                       | constraint_elem OR constraint_elem
+                       | constraint_expr OR constraint_expr
                                {       $$ = nconc( $1, lcons( makeString( "OR"), $3)); }
-                       | Op constraint_elem
+                       | Op constraint_expr
                                {       $$ = lcons( makeString( $1), $2); }
-                       | constraint_elem Op
+                       | constraint_expr Op
                                {       $$ = lappend( $1, makeString( $2)); }
-                       | constraint_elem IS TRUE_P
+                       | constraint_expr IS TRUE_P
                                {       $$ = lappend( $1, makeString( "IS TRUE")); }
-                       | constraint_elem IS FALSE_P
+                       | constraint_expr IS FALSE_P
                                {       $$ = lappend( $1, makeString( "IS FALSE")); }
-                       | constraint_elem IS NOT TRUE_P
+                       | constraint_expr IS NOT TRUE_P
                                {       $$ = lappend( $1, makeString( "IS NOT TRUE")); }
-                       | constraint_elem IS NOT FALSE_P
+                       | constraint_expr IS NOT FALSE_P
                                {       $$ = lappend( $1, makeString( "IS NOT FALSE")); }
                ;
 
@@ -944,6 +999,18 @@ key_reference:  NO ACTION                          { $$ = NULL; }
                | SET NULL_P                                    { $$ = NULL; }
                ;
 
+OptInherit:  INHERITS '(' relation_name_list ')'               { $$ = $3; }
+               | /*EMPTY*/                                                                             { $$ = NIL; }
+               ;
+
+/*
+ *     "ARCHIVE" keyword was removed in 6.3, but we keep it for now
+ *  so people can upgrade with old pg_dump scripts. - momjian 1997-11-20(?)
+ */
+OptArchiveType:  ARCHIVE '=' NONE                                              { }
+               | /*EMPTY*/                                                                             { }
+               ;
+
 
 /*****************************************************************************
  *
@@ -1133,7 +1200,7 @@ def_rest:  def_name definition
                ;
 
 def_type:  OPERATOR                                                    { $$ = OPERATOR; }
-               | Type                                                          { $$ = TYPE_P; }
+               | TYPE_P                                                        { $$ = TYPE_P; }
                | AGGREGATE                                                     { $$ = AGGREGATE; }
                ;
 
@@ -1537,7 +1604,7 @@ RemoveStmt:  DROP remove_type name
                                }
                ;
 
-remove_type:  Type                                                             {  $$ = TYPE_P; }
+remove_type:  TYPE_P                                                   {  $$ = TYPE_P; }
                | INDEX                                                                 {  $$ = INDEX; }
                | RULE                                                                  {  $$ = RULE; }
                | VIEW                                                                  {  $$ = VIEW; }
@@ -2694,7 +2761,7 @@ opt_interval:  datetime                                                   { $$ = lcons($1, NIL); }
 
 a_expr_or_null:  a_expr
                                { $$ = $1;}
-               | Pnull
+               | NULL_P
                                {
                                        A_Const *n = makeNode(A_Const);
                                        n->val.type = T_Null;
@@ -2845,7 +2912,7 @@ a_expr:  attr opt_indirection
                                        t->setof = FALSE;
 
                                        if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIME(p) precision must be zero",NULL);
+                                               elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
 
                                        $$ = (Node *)n;
                                }
@@ -2880,7 +2947,7 @@ a_expr:  attr opt_indirection
                                        t->setof = FALSE;
 
                                        if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIMESTAMP(p) precision must be zero",NULL);
+                                               elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
 
                                        $$ = (Node *)n;
                                }
@@ -3566,9 +3633,6 @@ SpecialRuleRelation:  CURRENT
                                }
                ;
 
-Type:  TYPE_P;
-Pnull: NULL_P;
-
 %%
 
 static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)