diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 0e6b37ae833b7ecdccebb6d8f7026ba9a78cd580..c4d47d976bcbeb87f06a773a1bd7fb1fcb04143d 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -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.
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 84edb5a2b55674b3416c48511f7349ed73e28a96..f75a7b364922fc20e7029134d4d2086a2109bf2a 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -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
diff --git a/src/interfaces/ecpg/include/ecpgerrno.h b/src/interfaces/ecpg/include/ecpgerrno.h
index 85b891688d64baabdaf46c895c97c9ff0aaad972..37443badcd2add18ede253f490b3b8b710d1d1cf 100644
--- a/src/interfaces/ecpg/include/ecpgerrno.h
+++ b/src/interfaces/ecpg/include/ecpgerrno.h
@@ -13,32 +13,34 @@
 #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 */
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index fc416bd4fb3e9fc7b6e784c113b8088be861cdab..1e527ce369eaec80c40a475019466e1e83343472 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -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;
diff --git a/src/interfaces/ecpg/include/sql3types.h b/src/interfaces/ecpg/include/sql3types.h
index c844975b4ad948cb79a40f969e069dc3ad4702e5..34224c7577e18fed033b045d5a467a8cf8ef6636 100644
--- a/src/interfaces/ecpg/include/sql3types.h
+++ b/src/interfaces/ecpg/include/sql3types.h
@@ -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 */
diff --git a/src/interfaces/ecpg/lib/data.c b/src/interfaces/ecpg/lib/data.c
index 5b30eb1ca4bb69c3f0150a4b1e1da95b7d062921..af3c78ce591d4d57e38c655c2570a49210df19e5 100644
--- a/src/interfaces/ecpg/lib/data.c
+++ b/src/interfaces/ecpg/lib/data.c
@@ -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);
 }
diff --git a/src/interfaces/ecpg/lib/descriptor.c b/src/interfaces/ecpg/lib/descriptor.c
index 1f0c5536f799b10edaf75cdc39bb451789ed7626..a27915ce5c129ad076e4bbddb63ef052b03b403d 100644
--- a/src/interfaces/ecpg/lib/descriptor.c
+++ b/src/interfaces/ecpg/lib/descriptor.c
@@ -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;
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 2891eefe084ea795a954b7844863a5da192a28f9..c3c262bea4cdd79d240c2dee78ebf2cf7fed4da5 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -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
diff --git a/src/interfaces/ecpg/lib/error.c b/src/interfaces/ecpg/lib/error.c
index aa63fe94397b986e3e49a6079287628163bc7ea2..54e48a55271aa8e44b8b6fa43a5efb38c325ec68 100644
--- a/src/interfaces/ecpg/lib/error.c
+++ b/src/interfaces/ecpg/lib/error.c
@@ -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),
diff --git a/src/interfaces/ecpg/lib/typename.c b/src/interfaces/ecpg/lib/typename.c
index af87b160aa9e1108a645ae77656b7d3a3c9825f0..1999ab82d7519ed124402c8948259f3c00131a51 100644
--- a/src/interfaces/ecpg/lib/typename.c
+++ b/src/interfaces/ecpg/lib/typename.c
@@ -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;
+	}
+}
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index ed5e27db3a3709698cf9ef963f660bd593fb7b06..c1fe45c4a4440e62e00c01ee20934d8651519417 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -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"); }