]> granicus.if.org Git - postgresql/commitdiff
*** empty log message ***
authorMichael Meskes <meskes@postgresql.org>
Wed, 1 Mar 2000 12:49:43 +0000 (12:49 +0000)
committerMichael Meskes <meskes@postgresql.org>
Wed, 1 Mar 2000 12:49:43 +0000 (12:49 +0000)
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/TODO
src/interfaces/ecpg/include/ecpgerrno.h
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/sql3types.h
src/interfaces/ecpg/lib/data.c
src/interfaces/ecpg/lib/descriptor.c
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/lib/error.c
src/interfaces/ecpg/lib/typename.c
src/interfaces/ecpg/preproc/preproc.y

index 0e6b37ae833b7ecdccebb6d8f7026ba9a78cd580..c4d47d976bcbeb87f06a773a1bd7fb1fcb04143d 100644 (file)
@@ -832,5 +832,10 @@ Wed Feb 23 17:08:28 CET 2000
 Fri Feb 25 16:13:11 CET 2000
 
        - Fixed some bugs I created when I cleaned up, thanks Christof.
+
+Wed Mar  1 10:49:03 CET 2000
+
+       - Synced preproc.y with gram.y.
+       - Added output of arrays.
        - Set library version to 3.1.0.
        - Set ecpg version to 2.7.0.
index 84edb5a2b55674b3416c48511f7349ed73e28a96..f75a7b364922fc20e7029134d4d2086a2109bf2a 100644 (file)
@@ -16,8 +16,6 @@ the parser.
 it would be nice to be able to use :var[:index] or :var[<integer>] as
 cvariable for an array var
 
-How can one insert arrays from c variables?
-
 What happens to the output variable during read if there was an
 indicator-error? 
 
@@ -26,10 +24,7 @@ Add a semantic check level, e.g. check if a table really exists.
 It would be nice if there was a alternative library using SPI functions
 instead of libpq so we can write backend functions using ecpg.
 
-make ECPGnumeric_lvalue more accurate by using something like ECPGdump_a_*
-
 remove space_or_nl and line_end from pgc.l
 
 Missing statements:
- - exec sql ifdef
  - SQLSTATE
index 85b891688d64baabdaf46c895c97c9ff0aaad972..37443badcd2add18ede253f490b3b8b710d1d1cf 100644 (file)
 #define ECPG_OUT_OF_MEMORY     -ENOMEM
 
 /* first we have a set of ecpg messages, they start at 200 */
-#define ECPG_UNSUPPORTED       -200
-#define ECPG_TOO_MANY_ARGUMENTS -201
-#define ECPG_TOO_FEW_ARGUMENTS -202
-#define ECPG_TOO_MANY_MATCHES  -203
-#define ECPG_INT_FORMAT                -204
-#define ECPG_UINT_FORMAT       -205
-#define ECPG_FLOAT_FORMAT      -206
-#define ECPG_CONVERT_BOOL      -207
-#define ECPG_EMPTY             -208
-#define ECPG_MISSING_INDICATOR -209
-
-#define ECPG_NO_CONN           -220
-#define ECPG_NOT_CONN          -221
-
-#define ECPG_INVALID_STMT      -230
+#define ECPG_UNSUPPORTED               -200
+#define ECPG_TOO_MANY_ARGUMENTS        -201
+#define ECPG_TOO_FEW_ARGUMENTS         -202
+#define ECPG_TOO_MANY_MATCHES          -203
+#define ECPG_INT_FORMAT                        -204
+#define ECPG_UINT_FORMAT               -205
+#define ECPG_FLOAT_FORMAT              -206
+#define ECPG_CONVERT_BOOL              -207
+#define ECPG_EMPTY                     -208
+#define ECPG_MISSING_INDICATOR         -209
+#define ECPG_NO_ARRAY                  -210
+#define ECPG_DATA_NOT_ARRAY            -211
+
+#define ECPG_NO_CONN                   -220
+#define ECPG_NOT_CONN                  -221
+
+#define ECPG_INVALID_STMT              -230
 
 /* dynamic SQL related */
-#define ECPG_UNKNOWN_DESCRIPTOR        -240
+#define ECPG_UNKNOWN_DESCRIPTOR                -240
 #define ECPG_INVALID_DESCRIPTOR_INDEX  -241
 #define ECPG_UNKNOWN_DESCRIPTOR_ITEM   -242
-#define ECPG_VAR_NOT_NUMERIC   -243
-#define ECPG_VAR_NOT_CHAR      -244
+#define ECPG_VAR_NOT_NUMERIC           -243
+#define ECPG_VAR_NOT_CHAR              -244
 
 /* finally the backend error messages, they start at 400 */
-#define ECPG_PGSQL             -400
-#define ECPG_TRANS             -401
-#define ECPG_CONNECT           -402
+#define ECPG_PGSQL                     -400
+#define ECPG_TRANS                     -401
+#define ECPG_CONNECT                   -402
 
 #endif  /* !_ECPG_ERROR_H */
index fc416bd4fb3e9fc7b6e784c113b8088be861cdab..1e527ce369eaec80c40a475019466e1e83343472 100644 (file)
@@ -30,12 +30,12 @@ extern              "C"
 
 /* Here are some methods used by the lib. */
 /* Returns a pointer to a string containing a simple type name. */
-       const char *ECPGtype_name(enum ECPGttype);
        bool get_data(PGresult *, int, int, int, enum ECPGttype type,
-                       enum ECPGttype, void *, void *, long, long);
+                       enum ECPGttype, void *, void *, long, long, bool);
        char *ecpg_alloc(long, int);
        char *ecpg_strdup(const char *, int);
        const char *ECPGtype_name(enum ECPGttype);
+       unsigned int ECPGDynamicType(Oid);
        
 /* and some vars */
        extern struct auto_mem *auto_allocs;
index c844975b4ad948cb79a40f969e069dc3ad4702e5..34224c7577e18fed033b045d5a467a8cf8ef6636 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
  *
- * $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.1 2000/02/16 16:18:03 meskes Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.2 2000/03/01 12:49:41 meskes Exp $
  */
 
 /* chapter 13.1 table 2: Codes used for SQL data types in Dynamic SQL */
index 5b30eb1ca4bb69c3f0150a4b1e1da95b7d062921..af3c78ce591d4d57e38c655c2570a49210df19e5 100644 (file)
@@ -8,13 +8,26 @@
 bool
 get_data(PGresult *results, int act_tuple, int act_field, int lineno,
         enum ECPGttype type, enum ECPGttype ind_type,
-        void *var, void *ind, long varcharsize, long offset)
+        void *var, void *ind, long varcharsize, long offset,
+        bool isarray)
 {
        char *pval = (char *)PQgetvalue(results, act_tuple, act_field);
 
        ECPGlog("get_data line %d: RESULT: %s\n", lineno, pval ? pval : "");
 
        /* Now the pval is a pointer to the value. */
+       /* let's check is it really is an array if it should be */
+       if (isarray)
+       {
+               if (*pval !=  '{')
+               {
+                       ECPGlog("get_data data entry does not look like an array in line %d\n", lineno);
+                       ECPGraise(lineno, ECPG_DATA_NOT_ARRAY, NULL);
+                       return(false);
+               }
+               else ++pval;
+       }
+
        /* We will have to decode the value */
 
        /*
@@ -48,8 +61,10 @@ get_data(PGresult *results, int act_tuple, int act_field, int lineno,
                        break;
        }
        
-       switch (type)
-       {
+       do
+       {       
+          switch (type)
+          {
                long            res;
                unsigned long   ures;
                double          dres;
@@ -61,7 +76,8 @@ get_data(PGresult *results, int act_tuple, int act_field, int lineno,
                        if (pval)
                        {
                                res = strtol(pval, &scan_length, 10);
-                               if (*scan_length != '\0')       /* Garbage left */
+                               if ((isarray && *scan_length != ',' && *scan_length != '}')
+                                       || (!isarray && *scan_length != '\0'))  /* Garbage left */
                                {
                                        ECPGraise(lineno, ECPG_INT_FORMAT, pval);
                                        return (false);
@@ -94,7 +110,8 @@ get_data(PGresult *results, int act_tuple, int act_field, int lineno,
                        if (pval)
                        {
                                ures = strtoul(pval, &scan_length, 10);
-                               if (*scan_length != '\0')       /* Garbage left */
+                               if ((isarray && *scan_length != ',' && *scan_length != '}')
+                                       || (!isarray && *scan_length != '\0'))  /* Garbage left */
                                {
                                        ECPGraise(lineno, ECPG_UINT_FORMAT, pval);
                                        return (false);
@@ -127,7 +144,8 @@ get_data(PGresult *results, int act_tuple, int act_field, int lineno,
                        if (pval)
                        {
                                dres = strtod(pval, &scan_length);
-                               if (*scan_length != '\0')       /* Garbage left */
+                               if ((isarray && *scan_length != ',' && *scan_length != '}')
+                                       || (!isarray && *scan_length != '\0'))  /* Garbage left */
                                {
                                        ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval);
                                        return (false);
@@ -246,7 +264,23 @@ get_data(PGresult *results, int act_tuple, int act_field, int lineno,
                        ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(type));
                        return (false);
                        break;
-       }
-       
+          }
+          if (isarray)
+          {
+               bool string = false;
+               
+               /* set array to next entry */
+               ++act_tuple;
+               
+               /* set pval to the next entry */
+               for (; string || (*pval != ',' && *pval != '}'); ++pval)
+                       if (*pval == '"')
+                               string = string ? false : true;
+               
+               if (*pval == ',')
+                       ++pval;
+          }
+       } while (isarray && *pval != '}');
+
        return (true);
 }
index 1f0c5536f799b10edaf75cdc39bb451789ed7626..a27915ce5c129ad076e4bbddb63ef052b03b403d 100644 (file)
@@ -25,28 +25,6 @@ static PGresult
        return NULL;
 } 
 
-static unsigned int
-ECPGDynamicType(Oid type)
-{
-       switch(type)
-       {
-               case 16:        return SQL3_BOOLEAN;    /* bool */
-               case 21:        return SQL3_SMALLINT;   /* int2 */
-               case 23:        return SQL3_INTEGER;    /* int4 */
-               case 25:        return SQL3_CHARACTER;  /* text */
-               case 700:       return SQL3_REAL;               /* float4 */
-               case 701:       return SQL3_DOUBLE_PRECISION;   /* float8 */
-               case 1042:      return SQL3_CHARACTER;  /* bpchar */
-               case 1043:      return SQL3_CHARACTER_VARYING;  /* varchar */
-               case 1082:      return SQL3_DATE_TIME_TIMESTAMP;        /* date */
-               case 1083:      return SQL3_DATE_TIME_TIMESTAMP;        /* time */
-               case 1184:      return SQL3_DATE_TIME_TIMESTAMP;        /* datetime */
-               case 1296:      return SQL3_DATE_TIME_TIMESTAMP;        /* timestamp */
-               case 1700:      return SQL3_NUMERIC;    /* numeric */
-               default:        return -type;
-       }
-}
-
 static unsigned int
 ECPGDynamicType_DDT(Oid type)
 {
@@ -61,7 +39,6 @@ ECPGDynamicType_DDT(Oid type)
        }
 }
 
-
 bool
 ECPGget_desc_header(int lineno, char * desc_name, int *count)
 {
@@ -266,7 +243,7 @@ ECPGget_desc(int lineno, char *desc_name, int index, ...)
                                ECPGlog("ECPGget_desc: TYPE = %d\n", ECPGDynamicType_DDT(PQftype(ECPGresult, index)));
                                break;
                        case ECPGd_data:
-                               if (!get_data(ECPGresult, 0, index, lineno, vartype, ECPGt_NO_INDICATOR, var, NULL, varcharsize, offset))
+                               if (!get_data(ECPGresult, 0, index, lineno, vartype, ECPGt_NO_INDICATOR, var, NULL, varcharsize, offset, false))
                                        return (false);                         
                                        
                                break;
index 2891eefe084ea795a954b7844863a5da192a28f9..c3c262bea4cdd79d240c2dee78ebf2cf7fed4da5 100644 (file)
@@ -24,6 +24,7 @@
 #include <ecpgtype.h>
 #include <ecpglib.h>
 #include <sqlca.h>
+#include <sql3types.h>
 
 /* variables visible to the programs */
 static struct sqlca sqlca_init =
@@ -689,23 +690,46 @@ ECPGexecute(struct statement * stmt)
                                        isarray = 0;
                                        if (PQresultStatus(query) == PGRES_TUPLES_OK) {
                                                isarray = atol((char *)PQgetvalue(query, 0, 0));
+                                               if (ECPGDynamicType(PQftype(results, act_field)) == SQL3_CHARACTER ||
+                                                   (PQftype(results, act_field)) == SQL3_CHARACTER_VARYING)
+                                               {
+                                                       /* arrays of character strings are not yet implemented */
+                                                       isarray = false;
+                                               }
                                                ECPGlog("ECPGexecute line %d: TYPE database: %d C: %d array: %s\n", stmt->lineno, PQftype(results, act_field), var->type, isarray ? "yes" : "no");
                                        }
                                        PQclear(query);
 
-                                       /*
-                                        * if we don't have enough space, we cannot read all
-                                        * tuples
-                                        */
-                                       if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
+                                       if (!isarray)
                                        {
-                                               ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
+                                               /*
+                                                * if we don't have enough space, we cannot read all
+                                                * tuples
+                                                */
+                                               if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
+                                               {
+                                                       ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
                                                                stmt->lineno, ntuples, var->arrsize);
-                                               ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL);
-                                               status = false;
-                                               break;
+                                                       ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL);
+                                                       status = false;
+                                                       break;
+                                               }
                                        }
-
+                                       else
+                                       {
+                                               /*
+                                                * since we read an array, the variable has to be
+                                                * an array too
+                                                */
+                                               if (var->arrsize == 0)
+                                               {
+                                                       ECPGlog("ECPGexecute line %d: variable is not an array\n");
+                                                       ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL);
+                                                       status = false;
+                                                       break;
+                                               } 
+                                       }
+                                       
                                        /*
                                         * allocate memory for NULL pointers
                                         */
@@ -745,7 +769,7 @@ ECPGexecute(struct statement * stmt)
                                        {
                                                if (!get_data(results, act_tuple, act_field, stmt->lineno,
                                                         var->type, var->ind_type, var->value,
-                                                        var->ind_value, var->varcharsize, var->offset))
+                                                        var->ind_value, var->varcharsize, var->offset, isarray))
                                                         status = false;
                                        }
                                        var = var->next;
@@ -1067,13 +1091,9 @@ ECPGlog(const char *format,...)
  *
  * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
  *
- * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/ecpglib.c,v 1.60 2000/02/23 19:25:43 meskes Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/ecpglib.c,v 1.61 2000/03/01 12:49:42 meskes Exp $
  */
 
-/* I borrowed the include files from ecpglib.c, maybe we don't need all of them */
-
-#include <sql3types.h>
-
 PGconn *ECPG_internal_get_connection(char *name);
 
 extern struct descriptor
index aa63fe94397b986e3e49a6079287628163bc7ea2..54e48a55271aa8e44b8b6fa43a5efb38c325ec68 100644 (file)
@@ -67,6 +67,16 @@ ECPGraise(int line, int code, const char *str)
                        snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
                                "NULL value without indicator in line %d.", line);
                        break;
+               
+               case ECPG_NO_ARRAY: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "variable is not an array in line %d.", line);
+                       break;
+                       
+               case ECPG_DATA_NOT_ARRAY: 
+                       snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+                               "data read from backend is not an array in line %d.", line);
+                       break;
                        
                case ECPG_NO_CONN: 
                        snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
index af87b160aa9e1108a645ae77656b7d3a3c9825f0..1999ab82d7519ed124402c8948259f3c00131a51 100644 (file)
@@ -1,5 +1,8 @@
 #include <stdlib.h>
 #include <ecpgtype.h>
+#include <ecpglib.h>
+#include <sql3types.h>
+
 /*
  * This function is used to generate the correct type names.
  */
@@ -39,3 +42,25 @@ ECPGtype_name(enum ECPGttype typ)
        }
        return NULL;
 }
+
+unsigned int
+ECPGDynamicType(Oid type)
+{
+       switch(type)
+       {
+               case 16:        return SQL3_BOOLEAN;    /* bool */
+               case 21:        return SQL3_SMALLINT;   /* int2 */
+               case 23:        return SQL3_INTEGER;    /* int4 */
+               case 25:        return SQL3_CHARACTER;  /* text */
+               case 700:       return SQL3_REAL;               /* float4 */
+               case 701:       return SQL3_DOUBLE_PRECISION;   /* float8 */
+               case 1042:      return SQL3_CHARACTER;  /* bpchar */
+               case 1043:      return SQL3_CHARACTER_VARYING;  /* varchar */
+               case 1082:      return SQL3_DATE_TIME_TIMESTAMP;        /* date */
+               case 1083:      return SQL3_DATE_TIME_TIMESTAMP;        /* time */
+               case 1184:      return SQL3_DATE_TIME_TIMESTAMP;        /* datetime */
+               case 1296:      return SQL3_DATE_TIME_TIMESTAMP;        /* timestamp */
+               case 1700:      return SQL3_NUMERIC;    /* numeric */
+               default:        return -type;
+       }
+}
index ed5e27db3a3709698cf9ef963f660bd593fb7b06..c1fe45c4a4440e62e00c01ee20934d8651519417 100644 (file)
@@ -275,7 +275,7 @@ make_name(void)
 
 %type  <str>   Iconst Fconst Sconst TransactionStmt CreateStmt UserId
 %type  <str>   CreateAsElement OptCreateAs CreateAsList CreateAsStmt
-%type  <str>   OptInherit key_reference comment_text
+%type  <str>   OptInherit key_reference comment_text ConstraintDeferrabilitySpec
 %type  <str>    key_match ColLabel SpecialRuleRelation ColId columnDef
 %type  <str>    ColConstraint ColConstraintElem NumericOnly FloatOnly
 %type  <str>    OptTableElementList OptTableElement TableConstraint
@@ -283,7 +283,7 @@ make_name(void)
 %type  <str>    target_list target_el update_target_list alias_clause
 %type  <str>    update_target_el opt_id relation_name database_name
 %type  <str>    access_method attr_name class index_name name func_name
-%type  <str>    file_name AexprConst ParamNo TypeId c_expr ColQualListWithNull
+%type  <str>    file_name AexprConst ParamNo TypeId c_expr
 %type  <str>   in_expr_nodes a_expr b_expr TruncateStmt CommentStmt
 %type  <str>   opt_indirection expr_list extract_list extract_arg
 %type  <str>   position_list substr_list substr_from alter_column_action
@@ -292,8 +292,8 @@ make_name(void)
 %type  <str>   opt_decimal Character character opt_varying opt_charset
 %type  <str>   opt_collate Datetime datetime opt_timezone opt_interval
 %type  <str>   numeric a_expr_or_null row_expr row_descriptor row_list
-%type  <str>   SelectStmt SubSelect result OptTemp OptTempType OptTempScope
-%type  <str>   opt_table opt_all sort_clause sortby_list ColQualifier
+%type  <str>   SelectStmt SubSelect result OptTemp ConstraintAttributeSpec
+%type  <str>   opt_table opt_all sort_clause sortby_list ConstraintAttr 
 %type  <str>   sortby OptUseOp opt_inh_star relation_name_list name_list
 %type  <str>   group_clause having_clause from_clause opt_distinct
 %type  <str>   join_outer where_clause relation_expr sub_type
@@ -329,18 +329,16 @@ make_name(void)
 %type  <str>   GrantStmt privileges operation_commalist operation
 %type  <str>   opt_cursor opt_lmode ConstraintsSetStmt comment_tg
 %type  <str>   case_expr when_clause_list case_default case_arg when_clause
-%type  <str>    select_clause opt_select_limit select_limit_value TimeClause
+%type  <str>    select_clause opt_select_limit select_limit_value ConstraintTimeSpec
 %type  <str>    select_offset_value using_expr join_expr ReindexStmt
 %type  <str>   using_list from_expr join_clause join_type
 %type  <str>   join_qual update_list join_clause join_clause_with_union
 %type  <str>   opt_level opt_lock lock_type users_in_new_group_clause
-%type  <str>    OptConstrFromTable comment_op ConstraintAttribute
+%type  <str>    OptConstrFromTable comment_op OptTempTableName
 %type  <str>    constraints_set_list constraints_set_namelist comment_fn
 %type  <str>   constraints_set_mode comment_type comment_cl comment_ag
 %type  <str>   CreateGroupStmt AlterGroupStmt DropGroupStmt key_delete
-%type  <str>   ColConstraintWithNull ColConstraintElemWithNull NotNull
-%type  <str>   join_expr_with_union DefaultClause DefaultExpr PrimaryKey
-%type  <str>   DeferrabilityClause opt_force key_update
+%type  <str>   join_expr_with_union opt_force key_update
 /***
 #ifdef ENABLE_ORACLE_JOIN_SYNTAX
 %type  <str>   oracle_list oracle_expr oracle_outer
@@ -991,24 +989,26 @@ CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
                                }
                ;
 
-OptTemp:  OptTempType                           { $$ = $1; }
-                | OptTempScope OptTempType     { $$ = cat2_str($1,$2); }
-                ;
+/*
+ * Redundancy here is needed to avoid shift/reduce conflicts,
+ * since TEMP is not a reserved word.  See also OptTempTableName.
+ */
 
-OptTempType:     TEMP          { $$ = make_str("temp"); }
-               | TEMPORARY     { $$ = make_str("temporary"); }
-               | /* EMPTY */   { $$ = EMPTY; }
+OptTemp:       TEMPORARY               { $$ = make_str("temporary"); }
+               | TEMP                  { $$ = make_str("temp"); }
+               | LOCAL TEMPORARY       { $$ = make_str("local temporary"); }
+               | LOCAL TEMP            { $$ = make_str("local temp"); }
+               | GLOBAL TEMPORARY      {
+                                         mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+                                         $$ = make_str("global temporary");
+                                       }
+               | GLOBAL TEMP           {
+                                         mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+                                         $$ = make_str("global temp");
+                                       }
+               | /*EMPTY*/             { $$ = EMPTY; }
                ;
 
-OptTempScope:  GLOBAL
-               {
-                    mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
-                    $$ = make_str("global");
-               }
-             | LOCAL { $$ = make_str("local"); }
-             ;
-
-
 OptTableElementList:  OptTableElementList ',' OptTableElement
                                {
                                        $$ = cat_str(3, $1, make_str(","), $3);
@@ -1024,7 +1024,7 @@ OptTableElement:  columnDef               { $$ = $1; }
                        | TableConstraint       { $$ = $1; }
                ;
 
-columnDef:  ColId Typename ColQualifier opt_collate
+columnDef:  ColId Typename ColQualList opt_collate
                                {
                                        if (strlen($4) > 0)
                                        {
@@ -1033,7 +1033,7 @@ columnDef:  ColId Typename ColQualifier opt_collate
                                        }
                                        $$ = cat_str(4, $1, $2, $3, $4);
                                }
-       | ColId SERIAL ColQualifier opt_collate
+       | ColId SERIAL ColQualList opt_collate
                {
                        if (strlen($4) > 0)
                        {
@@ -1044,55 +1044,18 @@ columnDef:  ColId Typename ColQualifier opt_collate
                }
                ;
 
-/*
- * ColQualifier encapsulates an entire column qualification,
- * including DEFAULT, constraints, and constraint attributes.
- * Note that the DefaultClause handles the empty case.
- */
-ColQualifier:  DefaultClause ColQualList                       { $$ = cat2_str($1, $2); }
-               | NotNull DefaultClause ColQualListWithNull     { $$ = cat_str(3, $1, $2, $3); }
-               | DefaultExpr NotNull ColQualListWithNull       { $$ = cat_str(3, $1, $2, $3); }
-                | DefaultExpr NotNull                          { $$ = cat2_str($1, $2); }
-                | NotNull DefaultClause                                { $$ = cat2_str($1, $2); }
-               | NULL_P DefaultClause ColQualListWithNull      { $$ = cat_str(3, make_str("null"), $2, $3); }
-                | NULL_P DefaultClause                         { $$ = cat2_str(make_str("null"), $2); }
-                | DefaultClause                                        { $$ = $1; }
-               ;
-
-/*
- * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
- * conflict on NOT (since NOT might start a subsequent NOT NULL constraint,
- * or be part of a_expr NOT LIKE or similar constructs).
- */
-DefaultClause:  DefaultExpr     { $$ = $1; }
-               | /*EMPTY*/     { $$ = EMPTY; }
-                ;
-
-DefaultExpr:  DEFAULT NULL_P           { $$ = make_str("default null"); }
-               | DEFAULT b_expr        { $$ = cat2_str(make_str("default"), $2); }
-               ;
-
 ColQualList:  ColQualList ColConstraint        { $$ = cat2_str($1,$2); }
-                       | ColConstraint { $$ = $1; }
+                       | /*EMPTY*/     { $$ = EMPTY; }
                ;
 
-ColQualListWithNull:  ColConstraintWithNull ColQualListWithNull
-                       { $$ = cat2_str($1, $2); }
-               |  ColConstraintWithNull
-                       { $$ = $1; }
-
 ColConstraint: CONSTRAINT name ColConstraintElem
                                {
                                        $$ = cat_str(3, make_str("constraint"), $2, $3);
                                }
                | ColConstraintElem
                                { $$ = $1; }
-               ;
-
-ColConstraintWithNull: CONSTRAINT name ColConstraintElemWithNull
-                       { $$ = cat_str(3, make_str("constraint"), $2, $3); }
-               | ColConstraintElemWithNull
-                       { $$ = $1; }
+               | ConstraintAttr
+                               { $$ = $1; }
                ;
 
 /* DEFAULT NULL is already the default for Postgres.
@@ -1106,40 +1069,56 @@ ColConstraintWithNull:  CONSTRAINT name ColConstraintElemWithNull
  * shift/reduce conflicts with WITH TIME ZONE anyway.
  * - thomas 1999-01-08
  */
-ColConstraintElem:  ColConstraintElemWithNull
-                                {
-                                        $$ = $1;
-                                }
-                        | UNIQUE
+ColConstraintElem:     NOT NULL_P
+                               {
+                                       $$ = make_str("not null");
+                               }
+                       | NULL_P
+                               {
+                                       $$ = make_str("null");
+                               }
+                       | UNIQUE
                                {
                                        $$ = make_str("unique");
                                }
-                       | PrimaryKey
+                       | PRIMARY KEY
                                {
-                                       $$ = $1;
+                                       $$ = make_str("primary key");
                                }
-                       ;
-
-
-ColConstraintElemWithNull:  CHECK '(' a_expr ')'
+                       | CHECK '(' a_expr ')'
                                {
-                                       $$ = cat_str(3, make_str("check("), $3, make_str(")"));
+                                       $$ = cat_str(3, make_str("check ("), $3, make_str(")"));
                                }
-                       | REFERENCES ColId opt_column_list
-                               key_match key_actions ConstraintAttribute
+                       | DEFAULT NULL_P
                                {
-                                       $$ = cat_str(6, make_str("references"), $2, $3, $4, $5, $6);
+                                       $$ = make_str("default null");
                                }
-                       | REFERENCES ColId opt_column_list
-                               key_match key_actions
+                       | DEFAULT b_expr
                                {
-                                       $$ = cat_str(5, make_str("references"), $2, $3, $4, $5);
+                                       $$ = cat2_str(make_str("default"), $2);
                                }
-               ;
-
-PrimaryKey:  PRIMARY KEY       { $$ = make_str("primary key"); }
+                       |  REFERENCES ColId opt_column_list key_match key_actions 
+                               {
+                                       $$ = cat_str(5, make_str("references"), $2, $3, $4, $5);  
+                               }
+                       ;
 
-NotNull:  NOT NULL_P           { $$ = make_str("not null"); }
+/*
+ * ConstraintAttr represents constraint attributes, which we parse as if
+ * they were independent constraint clauses, in order to avoid shift/reduce
+ * conflicts (since NOT might start either an independent NOT NULL clause
+ * or an attribute).  analyze.c is responsible for attaching the attribute
+ * information to the preceding "real" constraint node, and for complaining
+ * if attribute clauses appear in the wrong place or wrong combinations.
+ *
+ * See also ConstraintAttributeSpec, which can be used in places where
+ * there is no parsing conflict.
+ */
+ConstraintAttr: DEFERRABLE             { $$ = make_str("deferrable"); }
+               | NOT DEFERRABLE        { $$ = make_str("not deferrable"); }
+               | INITIALLY DEFERRED    { $$ = make_str("initially deferred"); }
+               | INITIALLY IMMEDIATE   { $$ = make_str("initially immediate"); }
+               ;
 
 /* ConstraintElem specifies constraint syntax which is not embedded into
  *  a column definition. ColConstraintElem specifies the embedded form.
@@ -1161,20 +1140,15 @@ ConstraintElem:  CHECK '(' a_expr ')'
                                {
                                        $$ = cat_str(3, make_str("unique("), $3, make_str(")"));
                                }
-               | PrimaryKey '(' columnList ')'
+               | PRIMARY KEY '(' columnList ')'
                                {
-                                       $$ = cat_str(3, make_str("primary key("), $3, make_str(")"));
+                                       $$ = cat_str(3, make_str("primary key("), $4, make_str(")"));
                                }
                | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
-                       key_match key_actions ConstraintAttribute
+                       key_match key_actions ConstraintAttributeSpec
                                {
                                        $$ = cat_str(8, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10, $11);
                                }
-               | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
-                       key_match key_actions
-                               {
-                                       $$ = cat_str(7, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10);
-                               }
                ;
 
 key_match:  MATCH FULL
@@ -1347,7 +1321,7 @@ CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
                                }
        |       CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
                                 relation_name OptConstrFromTable
-                               ConstraintAttribute
+                               ConstraintAttributeSpec
                                 FOR EACH ROW EXECUTE PROCEDURE
                                name '(' TriggerFuncArgs ')'
                                {
@@ -1422,18 +1396,18 @@ OptConstrFromTable:                     /* Empty */
                                 }
                 ;
 
-ConstraintAttribute: DeferrabilityClause
+ConstraintAttributeSpec: ConstraintDeferrabilitySpec
                 {      $$ = $1; }
-       | TimeClause
-               {       $$ = $1; }
-       | DeferrabilityClause TimeClause
-               {
+       | ConstraintDeferrabilitySpec ConstraintTimeSpec
+               {       
                        if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
                                mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
 
-                       $$ = cat2_str($1, $2);
+                       $$ = cat2_str($1, $2);
                }
-       | TimeClause DeferrabilityClause
+       | ConstraintTimeSpec
+               {       $$ = $1; }
+       | ConstraintTimeSpec ConstraintDeferrabilitySpec
                {
                        if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
                                mmerror(ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
@@ -1442,11 +1416,11 @@ ConstraintAttribute: DeferrabilityClause
                }
        ;
 
-DeferrabilityClause: NOT DEFERRABLE    { $$ = make_str("not deferrable"); }
+ConstraintDeferrabilitySpec: NOT DEFERRABLE    { $$ = make_str("not deferrable"); }
                        | DEFERRABLE    { $$ = make_str("deferrable"); }
                 ;
 
-TimeClause: INITIALLY IMMEDIATE                { $$ = make_str("initially immediate"); }
+ConstraintTimeSpec: INITIALLY IMMEDIATE                { $$ = make_str("initially immediate"); }
                 | INITIALLY DEFERRED   { $$ = make_str("initially deferrable"); }
                 ;
 
@@ -2545,13 +2519,57 @@ SubSelect:     SELECT opt_distinct target_list
                                }
                ;
 
-result:  INTO OptTemp opt_table relation_name          { FoundInto = 1;
-                                                         $$= cat_str(4, make_str("into"), $2, $3, $4);
-                                                       }
-               | INTO into_list                        { $$ = EMPTY; }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+result:  INTO OptTempTableName                 {
+                                               FoundInto = 1;
+                                               $$= cat2_str(make_str("into"), $2);
+                                       }
+               | INTO into_list        { $$ = EMPTY; }
+               | /*EMPTY*/             { $$ = EMPTY; }
                ;
 
+/*
+ * Redundancy here is needed to avoid shift/reduce conflicts,
+ * since TEMP is not a reserved word.  See also OptTemp.
+ *
+ * The result is a cons cell (not a true list!) containing
+ * a boolean and a table name.
+ */
+OptTempTableName:  TEMPORARY opt_table relation_name
+                       {
+                               $$ = cat_str(3, make_str("temporary"), $2, $3);
+                       }
+                       | TEMP opt_table relation_name
+                       {
+                               $$ = cat_str(3, make_str("temp"), $2, $3);
+                       }
+                       | LOCAL TEMPORARY opt_table relation_name
+                       {
+                               $$ = cat_str(3, make_str("local temporary"), $3, $4);
+                       }
+                       | LOCAL TEMP opt_table relation_name
+                       {
+                               $$ = cat_str(3, make_str("local temp"), $3, $4);
+                       }
+                       | GLOBAL TEMPORARY opt_table relation_name
+                        {
+                               mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+                               $$ = cat_str(3, make_str("global temporary"), $3, $4);
+                        }
+                       | GLOBAL TEMP opt_table relation_name
+                        {
+                               mmerror(ET_ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
+                               $$ = cat_str(3, make_str("global temp"), $3, $4);
+                        }
+                       | TABLE relation_name
+                       {
+                               $$ = cat2_str(make_str("table"), $2);
+                       }
+                       | relation_name
+                       {
+                               $$ = $1;
+                       }
+                ;
+
 opt_table:  TABLE                                      { $$ = make_str("table"); }
                | /*EMPTY*/                             { $$ = EMPTY; }
                ;
@@ -3839,7 +3857,6 @@ ColId:  ident                                     { $$ = $1; }
                | CREATEUSER                    { $$ = make_str("createuser"); }
                | CYCLE                         { $$ = make_str("cycle"); }
                | DATABASE                      { $$ = make_str("database"); }
-               | DEFERRABLE                    { $$ = make_str("deferrable"); }
                | DEFERRED                      { $$ = make_str("deferred"); }
                | DELIMITERS                    { $$ = make_str("delimiters"); }
                | DOUBLE                        { $$ = make_str("double"); }
@@ -3853,7 +3870,6 @@ ColId:  ident                                     { $$ = $1; }
                | INCREMENT                     { $$ = make_str("increment"); }
                | INDEX                         { $$ = make_str("index"); }
                | INHERITS                      { $$ = make_str("inherits"); }
-               | INITIALLY                     { $$ = make_str("initially"); }
                | INSENSITIVE                   { $$ = make_str("insensitive"); }
                | INSTEAD                       { $$ = make_str("instead"); }
                | INTERVAL                      { $$ = make_str("interval"); }
@@ -3900,6 +3916,8 @@ ColId:  ident                                     { $$ = $1; }
                | STDIN                         { $$ = make_str("stdin"); }
                | STDOUT                        { $$ = make_str("stdout"); }
                | SYSID                         { $$ = make_str("sysid"); }
+               | TEMP                          { $$ = make_str("temp"); }
+               | TEMPORARY                     { $$ = make_str("temporary"); }
                | TIME                          { $$ = make_str("time"); }
                | TIMESTAMP                     { $$ = make_str("timestamp"); }
                | TIMEZONE_HOUR                 { $$ = make_str("timezone_hour"); }
@@ -3977,6 +3995,7 @@ ColLabel:  ColId                  { $$ = $1; }
                | CURRENT_USER          { $$ = make_str("current_user"); }
                | DEC                   { $$ = make_str("dec"); }
                | DECIMAL               { $$ = make_str("decimal"); }
+               | DEFERRABLE            { $$ = make_str("deferrable"); }
                | DO                    { $$ = make_str("do"); }
                | ELSE                  { $$ = make_str("else"); }
                | END_TRANS             { $$ = make_str("end"); }
@@ -3987,6 +4006,7 @@ ColLabel:  ColId                  { $$ = $1; }
                | FOREIGN               { $$ = make_str("foreign"); }
                | GLOBAL                { $$ = make_str("global"); }
                | GROUP                 { $$ = make_str("group"); }
+               | INITIALLY             { $$ = make_str("initially"); }
                | LISTEN                { $$ = make_str("listen"); }
                | LOAD                  { $$ = make_str("load"); }
                | LOCK_P                { $$ = make_str("lock"); }