From e30c2d67ef1c58d148bdc1b3a7faeed7b17d8b28 Mon Sep 17 00:00:00 2001
From: Michael Meskes <meskes@postgresql.org>
Date: Mon, 22 Nov 1999 12:48:48 +0000
Subject: [PATCH] *** empty log message ***

---
 src/interfaces/ecpg/ChangeLog         |   15 +
 src/interfaces/ecpg/TODO              |    5 +
 src/interfaces/ecpg/lib/Makefile.in   |    4 +-
 src/interfaces/ecpg/lib/ecpglib.c     |   18 +-
 src/interfaces/ecpg/preproc/Makefile  |    2 +-
 src/interfaces/ecpg/preproc/preproc.y | 1036 +++++++------------------
 src/interfaces/ecpg/test/test4.pgc    |   26 +-
 7 files changed, 347 insertions(+), 759 deletions(-)

diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index b80b1de652d..adbe47ed4b8 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -705,3 +705,18 @@ Mon Nov  1 11:22:06 CET 1999
 	- Print SQL error message to STDERR instead of STDOUT.
 	- Added a fourth test source.
 	- Set library version to 3.0.5.
+
+Wed Nov 10 18:33:14 CET 1999
+
+	- Synced preproc.y with gram.y.
+
+Thu Nov 11 07:49:44 CET 1999
+
+	- Fixed bug in SET AUTOCOMMIT.
+
+Mon Nov 22 18:26:34 CET 1999
+
+	- Synced preproc.y with gram.y.
+	- Clean up parser.
+	- Set library version to 3.0.6.
+        - Set ecpg version to 2.6.10.
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 9e9f94b1570..307953e32a4 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -7,6 +7,9 @@ has to be 100.
 sqlwarn[6] should be 'W' if the PRECISION or SCALE value specified in a SET
 DESCRIPTOR statement will be ignored.
 
+If a NOTICE message is given by the backend it should not be printed to
+stderr. Instead it should be listed as a warning.
+
 it would be nice to be able to use :var[:index] as cvariable
 
 support for dynamic SQL with unknown number of variables with DESCRIPTORS
@@ -18,6 +21,8 @@ indicator-error?
 
 Add a semantic check level, e.g. check if a table really exists.
 
+How can on insert arrays from c variables?
+
 Missing statements:
  - exec sql ifdef
  - exec sql allocate
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index fe75bfc13f4..6a6955f7d87 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -6,13 +6,13 @@
 # Copyright (c) 1994, Regents of the University of California
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.50 1999/11/02 12:11:53 meskes Exp $
+#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.51 1999/11/22 12:48:46 meskes Exp $
 #
 #-------------------------------------------------------------------------
 
 NAME= ecpg
 SO_MAJOR_VERSION= 3
-SO_MINOR_VERSION= 0.5
+SO_MINOR_VERSION= 0.6
 
 SRCDIR= @top_srcdir@
 include $(SRCDIR)/Makefile.global
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 6e711b4fcb2..9112ebb55b8 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -84,14 +84,14 @@ struct statement
 	struct variable *outlist;
 };
 
-struct prepared_statement
+static struct prepared_statement
 {
 	char	   *name;
 	struct statement *stmt;
 	struct prepared_statement *next;
 }		   *prep_stmts = NULL;
 
-struct auto_mem
+static struct auto_mem
 {
 	void	   *pointer;
 	struct auto_mem *next;
@@ -656,7 +656,7 @@ ECPGexecute(struct statement * stmt)
 	}
 	else
 	{
-		sqlca.sqlerrd[2] = 0;
+/*		sqlca.sqlerrd[2] = 0;*/
 		var = stmt->outlist;
 		switch (PQresultStatus(results))
 		{
@@ -741,7 +741,7 @@ ECPGexecute(struct statement * stmt)
 
 					for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
 					{
-						pval = PQgetvalue(results, act_tuple, act_field);
+						pval = (char *)PQgetvalue(results, act_tuple, act_field);
 
 						ECPGlog("ECPGexecute line %d: RESULT: %s\n", stmt->lineno, pval ? pval : "");
 
@@ -1112,6 +1112,7 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction)
 		}
 		PQclear(res);
 	}
+	
 	if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0)
 	{
 		struct prepared_statement *this;
@@ -1140,7 +1141,9 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
 	if (!ecpg_init(con, connection_name, lineno))
 		return(false);
 
-	if (con->autocommit == true && strncmp(mode, "OFF", strlen("OFF")) == 0)
+	ECPGlog("ECPGsetcommit line %d action = %s connection = %s\n", lineno, mode, con->name);
+	
+	if (con->autocommit == true && strncmp(mode, "off", strlen("off")) == 0)
 	{
 		if (con->committed)
 		{
@@ -1154,7 +1157,7 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
 		}
 		con->autocommit = false;
 	}
-	else if (con->autocommit == false && strncmp(mode, "ON", strlen("ON")) == 0)
+	else if (con->autocommit == false && strncmp(mode, "on", strlen("on")) == 0)
 	{
 		if (!con->committed)
 		{
@@ -1213,8 +1216,6 @@ ECPGconnect(int lineno, const char *dbname, const char *user, const char *passwd
 
 	ECPGlog("ECPGconnect: opening database %s %s%s\n", dbname ? dbname : "<DEFAULT>", user ? "for user " : "", user ? user : "");
 
-	sqlca.sqlcode = 0;
-
 	this->connection = PQsetdbLogin(NULL, NULL, NULL, NULL, dbname, user, passwd);
 
 	if (PQstatus(this->connection) == CONNECTION_BAD)
@@ -1238,6 +1239,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
 
 	if (strcmp(connection_name, "ALL") == 0)
 	{
+		memcpy((char *) &sqlca, (char *) &sqlca_init, sizeof(sqlca));
 		for (con = all_connections; con;)
 		{
 			struct connection *f = con;
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index bbf33db0bb9..45851e0d456 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -3,7 +3,7 @@ include $(SRCDIR)/Makefile.global
 
 MAJOR_VERSION=2
 MINOR_VERSION=6
-PATCHLEVEL=9
+PATCHLEVEL=10
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
 	-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 49bc9d7867b..eb7e79fac85 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -14,6 +14,7 @@
 #endif
 
 #define STRUCT_DEPTH 128
+#define EMPTY make1_str("")
 
 /*
  * Variables containing simple states.
@@ -21,7 +22,7 @@
 int	struct_level = 0;
 char	errortext[128];
 static char	*connection = NULL;
-static int      QueryIsRule = 0, ForUpdateNotAllowed = 0;
+static int      QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
 static struct this_type actual_type[STRUCT_DEPTH];
 static char     *actual_storage[STRUCT_DEPTH];
 
@@ -784,7 +785,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %type  <str>    target_list target_el update_target_list
 %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
+%type  <str>    file_name AexprConst ParamNo TypeId com_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
@@ -794,10 +795,10 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %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_union opt_unique sort_clause sortby_list
+%type  <str>	opt_table opt_all opt_unique sort_clause sortby_list
 %type  <str>	sortby OptUseOp opt_inh_star relation_name_list name_list
 %type  <str>	group_clause having_clause from_clause 
-%type  <str>	table_list join_outer where_clause relation_expr row_op sub_type
+%type  <str>	table_list join_outer where_clause relation_expr sub_type
 %type  <str>	opt_column_list insert_rest InsertStmt OptimizableStmt
 %type  <str>    columnList DeleteStmt LockStmt UpdateStmt CursorStmt
 %type  <str>    NotifyStmt columnElem copy_dirn UnlistenStmt
@@ -809,7 +810,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %type  <str>    index_opt_unique IndexStmt set_opt func_return def_rest
 %type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
 %type  <str>    def_elem def_list definition def_name def_type DefineStmt
-%type  <str>    opt_instead event event_object RuleActionList,
+%type  <str>    opt_instead event event_object RuleActionList opt_using
 %type  <str>	RuleActionStmtOrEmpty RuleActionMulti join_list func_as
 %type  <str>    RuleStmt opt_column opt_name oper_argtypes
 %type  <str>    MathOp RemoveFuncStmt aggr_argtype for_update_clause
@@ -838,8 +839,8 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %type  <str>    constraints_set_list constraints_set_namelist comment_fn
 %type  <str>	constraints_set_mode comment_type comment_cl comment_ag
 
-%type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen opt_using
-%type  <str>	indicator ECPGExecute ecpg_expr ECPGPrepare
+%type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen
+%type  <str>	indicator ECPGExecute ECPGPrepare ecpg_using
 %type  <str>    storage_clause opt_initializer c_anything blockstart
 %type  <str>    blockend variable_list variable c_thing c_term
 %type  <str>	opt_pointer cvariable ECPGDisconnect dis_name
@@ -1086,7 +1087,7 @@ DropUserStmt:  DROP USER UserId
 		;
 
 user_passwd_clause:  WITH PASSWORD UserId	{ $$ = cat2_str(make1_str("with password") , $3); }
-			| /*EMPTY*/		{ $$ = make1_str(""); }
+			| /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 user_createdb_clause:  CREATEDB
@@ -1097,7 +1098,7 @@ user_createdb_clause:  CREATEDB
 				{
 					$$ = make1_str("nocreatedb");
 				}
-			| /*EMPTY*/		{ $$ = make1_str(""); }
+			| /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 user_createuser_clause:  CREATEUSER
@@ -1122,11 +1123,11 @@ user_group_list:  user_group_list ',' UserId
 		;
 
 user_group_clause:  IN GROUP user_group_list	{ $$ = cat2_str(make1_str("in group"), $3); }
-			| /*EMPTY*/		{ $$ = make1_str(""); }
+			| /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 user_valid_clause:  VALID UNTIL Sconst			{ $$ = cat2_str(make1_str("valid until"), $3); }
-			| /*EMPTY*/			{ $$ = make1_str(""); }
+			| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 /*****************************************************************************
@@ -1322,21 +1323,22 @@ copy_file_name:  Sconst					{ $$ = $1; }
 		;
 
 opt_binary:  BINARY					{ $$ = make1_str("binary"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_with_copy:	WITH OIDS				{ $$ = make1_str("with oids"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 /*
  * the default copy delimiter is tab but the user can configure it
  */
-copy_delimiter:  USING DELIMITERS Sconst		{ $$ = cat2_str(make1_str("using delimiters"), $3); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+copy_delimiter:  opt_using DELIMITERS Sconst		{ $$ = cat3_str($1, make1_str("delimiters"), $3); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
-
+opt_using:	USING		{ $$ = make1_str("using"); }
+		| /* EMPTY */	{ $$ = EMPTY; }
 
 /*****************************************************************************
  *
@@ -1358,7 +1360,7 @@ OptTemp:  OptTempType                           { $$ = $1; }
 
 OptTempType:	  TEMP		{ $$ = make1_str("temp"); }
 		| TEMPORARY	{ $$ = make1_str("temporary"); }
-		| /* EMPTY */	{ $$ = make1_str(""); }
+		| /* EMPTY */	{ $$ = EMPTY; }
 		;
 
 OptTempScope:  GLOBAL
@@ -1378,7 +1380,7 @@ OptTableElementList:  OptTableElementList ',' OptTableElement
 				{
 					$$ = $1;
 				}
-			| /*EMPTY*/	{ $$ = make1_str(""); }
+			| /*EMPTY*/	{ $$ = EMPTY; }
 		;
 
 OptTableElement:  columnDef		{ $$ = $1; }
@@ -1396,7 +1398,7 @@ columnDef:  ColId Typename ColQualifier
 		;
 
 ColQualifier:  ColQualList	{ $$ = $1; }
-			| /*EMPTY*/	{ $$ = make1_str(""); }
+			| /*EMPTY*/	{ $$ = EMPTY; }
 		;
 
 ColQualList:  ColQualList ColConstraint	{ $$ = cat2_str($1,$2); }
@@ -1409,7 +1411,7 @@ ColPrimaryKey:  PRIMARY KEY
                 }
               | /*EMPTY*/
 		{
-			$$ = make1_str("");
+			$$ = EMPTY;
 		}
                 ;
 
@@ -1422,15 +1424,18 @@ ColConstraint:
 				{ $$ = $1; }
 		;
 
-/* DEFAULT NULL is already the default for Postgres.
+/*
+ * DEFAULT NULL is already the default for Postgres.
  * Bue define it here and carry it forward into the system
  * to make it explicit.
  * - thomas 1998-09-13
+ *
  * WITH NULL and NULL are not SQL92-standard syntax elements,
  * so leave them out. Use DEFAULT NULL to explicitly indicate
  * that a column may have that value. WITH NULL leads to
  * shift/reduce conflicts with WITH TIME ZONE anyway.
  * - thomas 1999-01-08
+ *
  * 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).
@@ -1462,7 +1467,7 @@ ColConstraintElem:  CHECK '(' a_expr ')'
 			| REFERENCES ColId opt_column_list key_match key_actions
 				{
 					fprintf(stderr, "CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented");
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 		;
 
@@ -1499,12 +1504,12 @@ ConstraintElem:  CHECK '(' a_expr ')'
 
 key_match:  MATCH FULL					{ $$ = make1_str("match full"); }
 		| MATCH PARTIAL					{ $$ = make1_str("match partial"); }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 key_actions:  key_action key_action		{ $$ = cat2_str($1, $2); }
 		| key_action					{ $$ = $1; }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 key_action:  ON DELETE key_reference	{ $$ = cat2_str(make1_str("on delete"), $3); }
@@ -1518,17 +1523,25 @@ key_reference:  NO ACTION	{ $$ = make1_str("no action"); }
 		;
 
 OptInherit:  INHERITS '(' relation_name_list ')' { $$ = make3_str(make1_str("inherits ("), $3, make1_str(")")); }
-		| /*EMPTY*/ { $$ = make1_str(""); }
+		| /*EMPTY*/ { $$ = EMPTY; }
 		;
 
-CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SubSelect
+/*
+ * Note: CREATE TABLE ... AS SELECT ... is just another spelling for
+ * SELECT ... INTO.
+ */
+
+CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
 		{
+			if (FoundInto == 1)
+				yyerror("CREATE TABLE/AS SELECT may not specify INTO");
+
 			$$ = cat5_str(cat3_str(make1_str("create"), $2, make1_str("table")), $4, $5, make1_str("as"), $7); 
 		}
 		;
 
 OptCreateAs:  '(' CreateAsList ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); }
-			| /*EMPTY*/ { $$ = make1_str(""); }	
+			| /*EMPTY*/ { $$ = EMPTY; }	
 		;
 
 CreateAsList:  CreateAsList ',' CreateAsElement	{ $$ = cat3_str($1, make1_str(","), $3); }
@@ -1553,7 +1566,7 @@ CreateSeqStmt:  CREATE SEQUENCE relation_name OptSeqList
 
 OptSeqList:  OptSeqList OptSeqElem
 				{ $$ = cat2_str($1, $2); }
-			|	{ $$ = make1_str(""); }
+			|	{ $$ = EMPTY; }
 		;
 
 OptSeqElem:  CACHE IntegerOnly
@@ -1622,7 +1635,7 @@ CreatePLangStmt:  CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst
 		;
 
 PLangTrusted:		TRUSTED { $$ = make1_str("trusted"); }
-			|	{ $$ = make1_str(""); }
+			|	{ $$ = EMPTY; }
 
 DropPLangStmt:  DROP PROCEDURAL LANGUAGE Sconst
 			{
@@ -1684,7 +1697,7 @@ TriggerForSpec:  FOR TriggerForOpt TriggerForType
 		;
 
 TriggerForOpt:  EACH					{ $$ = make1_str("each"); }
-			| /*EMPTY*/			{ $$ = make1_str(""); }
+			| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 TriggerForType:  ROW					{ $$ = make1_str("row"); }
@@ -1696,7 +1709,7 @@ TriggerFuncArgs:  TriggerFuncArg
 			| TriggerFuncArgs ',' TriggerFuncArg
 				{ $$ = cat3_str($1, make1_str(","), $3); }
 			| /*EMPTY*/
-				{ $$ = make1_str(""); }
+				{ $$ = EMPTY; }
 		;
 
 TriggerFuncArg:  Iconst
@@ -1713,7 +1726,7 @@ TriggerFuncArg:  Iconst
 
 OptConstrFromTable:                     /* Empty */
                                 {
-                                        $$ = make1_str("");
+                                        $$ = EMPTY;
                                 }
                 | FROM relation_name
                                 {
@@ -1723,7 +1736,7 @@ OptConstrFromTable:                     /* Empty */
 
 OptConstrTrigDeferrable:        /* Empty */
                                 {
-                                        $$ = make1_str("");
+                                        $$ = EMPTY;
                                 }
                 | DEFERRABLE
                                 {
@@ -1737,7 +1750,7 @@ OptConstrTrigDeferrable:        /* Empty */
 
 OptConstrTrigInitdeferred:      /* Empty */
                                 {
-                                        $$ = make1_str("");
+                                        $$ = EMPTY;
                                 }
                 | INITIALLY DEFERRED
                                 {
@@ -1783,8 +1796,7 @@ def_type:  OPERATOR		{ $$ = make1_str("operator"); }
 def_name:  PROCEDURE		{ $$ = make1_str("procedure"); }
 		| JOIN		{ $$ = make1_str("join"); }
 		| ColId		{ $$ = $1; }
-		| MathOp	{ $$ = $1; }
-		| Op		{ $$ = $1; }
+		| all_Op	{ $$ = $1; }
 		;
 
 definition:  '(' def_list ')'				{ $$ = make3_str(make1_str("("), $2, make1_str(")")); }
@@ -1876,7 +1888,7 @@ opt_direction:	FORWARD		{ $$ = make1_str("forward"); }
 					fprintf(stderr, "FETCH/ABSOLUTE not supported, using RELATIVE");
 					$$ = make1_str("absolute");
 				}
-		| /*EMPTY*/	{ $$ = make1_str(""); /* default */ }
+		| /*EMPTY*/	{ $$ = EMPTY; /* default */ }
 		;
 
 fetch_how_many:   Iconst        { $$ = $1; }
@@ -1884,13 +1896,13 @@ fetch_how_many:   Iconst        { $$ = $1; }
 		| ALL		{ $$ = make1_str("all"); }
 		| NEXT		{ $$ = make1_str("next"); }
 		| PRIOR		{ $$ = make1_str("prior"); }
-		| /*EMPTY*/	{ $$ = make1_str(""); /*default*/ }
+		| /*EMPTY*/	{ $$ = EMPTY; /*default*/ }
 		;
 
 opt_portal_name:  IN name		{ $$ = cat2_str(make1_str("in"), $2); }
 		| FROM name		{ $$ = cat2_str(make1_str("from"), $2); }
 /*		| name			{ $$ = cat2_str(make1_str("in"), $1); */
-		| /*EMPTY*/		{ $$ = make1_str(""); }
+		| /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 /*****************************************************************************
@@ -2070,11 +2082,11 @@ IndexStmt:	CREATE index_opt_unique INDEX index_name ON relation_name
 		;
 
 index_opt_unique:  UNIQUE	{ $$ = make1_str("unique"); }
-		| /*EMPTY*/	{ $$ = make1_str(""); }
+		| /*EMPTY*/	{ $$ = EMPTY; }
 		;
 
 access_method_clause:  USING access_method	{ $$ = cat2_str(make1_str("using"), $2); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 index_params:  index_list			{ $$ = $1; }
@@ -2099,7 +2111,7 @@ index_elem:  attr_name opt_type opt_class
 
 opt_type:  ':' Typename		{ $$ = cat2_str(make1_str(":"), $2); }
 		| FOR Typename	{ $$ = cat2_str(make1_str("for"), $2); }
-		| /*EMPTY*/	{ $$ = make1_str(""); }
+		| /*EMPTY*/	{ $$ = EMPTY; }
 		;
 
 /* opt_class "WITH class" conflicts with preceeding opt_type
@@ -2110,7 +2122,7 @@ opt_type:  ':' Typename		{ $$ = cat2_str(make1_str(":"), $2); }
  */
 opt_class:  class				{ $$ = $1; }
 		| USING class			{ $$ = cat2_str(make1_str("using"), $2); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 /*****************************************************************************
@@ -2163,7 +2175,7 @@ ProcedureStmt:	CREATE FUNCTION func_name func_args
 				}
 
 opt_with:  WITH definition			{ $$ = cat2_str(make1_str("with"), $2); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 func_args:  '(' func_args_list ')'		{ $$ = make3_str(make1_str("("), $2, make1_str(")")); }
@@ -2185,7 +2197,7 @@ func_return:  set_opt TypeId
 		;
 
 set_opt:  SETOF					{ $$ = make1_str("setof"); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 
@@ -2243,20 +2255,6 @@ RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
 				}
 		;
 
-all_Op:  Op | MathOp;
-
-MathOp:	'+'				{ $$ = make1_str("+"); }
-		| '-'			{ $$ = make1_str("-"); }
-		| '*'			{ $$ = make1_str("*"); }
-		| '%'			{ $$ = make1_str("%"); }
-                | '^'                   { $$ = make1_str("^"); }
-                | '|'                   { $$ = make1_str("|"); }
-		| '/'			{ $$ = make1_str("/"); }
-		| '<'			{ $$ = make1_str("<"); }
-		| '>'			{ $$ = make1_str(">"); }
-		| '='			{ $$ = make1_str("="); }
-		;
-
 oper_argtypes:	name
 				{
 				   yyerror("parser: argument type missing (use NONE for unary operators)");
@@ -2286,11 +2284,11 @@ RenameStmt:  ALTER TABLE relation_name opt_inh_star
 		;
 
 opt_name:  name							{ $$ = $1; }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 opt_column:  COLUMN					{ $$ = make1_str("colmunn"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 
@@ -2332,7 +2330,7 @@ RuleActionStmt:        InsertStmt
 		| NotifyStmt
                 ;
 RuleActionStmtOrEmpty: RuleActionStmt	{ $$ = $1; }
-               |       /*EMPTY*/        { $$ = make1_str(""); }
+               |       /*EMPTY*/        { $$ = EMPTY; }
                ;
 
 event_object:  relation_name '.' attr_name
@@ -2353,7 +2351,7 @@ event:	SELECT					{ $$ = make1_str("select"); }
 		 ;
 
 opt_instead:  INSTEAD					{ $$ = make1_str("instead"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 
@@ -2462,7 +2460,7 @@ CreatedbStmt:  CREATE DATABASE database_name WITH opt_database1 opt_database2
 		;
 
 opt_database1:  LOCATION '=' location	{ $$ = cat2_str(make1_str("location ="), $3); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 opt_database2:  ENCODING '=' encoding   { $$ = cat2_str(make1_str("encoding ="), $3); }
@@ -2471,12 +2469,12 @@ opt_database2:  ENCODING '=' encoding   { $$ = cat2_str(make1_str("encoding ="),
 
 location:  Sconst				{ $$ = $1; }
 		| DEFAULT			{ $$ = make1_str("default"); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 encoding:  Sconst		{ $$ = $1; }
 		| DEFAULT	{ $$ = make1_str("default"); }
-		| /*EMPTY*/	{ $$ = make1_str(""); }
+		| /*EMPTY*/	{ $$ = EMPTY; }
                ;
 
 /*****************************************************************************
@@ -2527,15 +2525,15 @@ VacuumStmt:  VACUUM opt_verbose opt_analyze
 		;
 
 opt_verbose:  VERBOSE					{ $$ = make1_str("verbose"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_analyze:  ANALYZE					{ $$ = make1_str("analyse"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_va_list:  '(' va_list ')'				{ $$ = make3_str(make1_str("("), $2, make1_str(")")); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 va_list:  name
@@ -2620,7 +2618,7 @@ insert_rest:  VALUES '(' target_list ')'
 		;
 
 opt_column_list:  '(' columnList ')'			{ $$ = make3_str(make1_str("("), $2, make1_str(")")); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 columnList:
@@ -2658,7 +2656,7 @@ LockStmt:  LOCK_P opt_table relation_name opt_lock
 		;
 
 opt_lock:  IN lock_type MODE            { $$ = cat3_str(make1_str("in"), $2, make1_str("mode")); }
-                | /*EMPTY*/             { $$ = make1_str("");}
+                | /*EMPTY*/             { $$ = EMPTY;}
                 ;
 
 lock_type:  SHARE ROW EXCLUSIVE 	{ $$ = make1_str("share row exclusive"); }
@@ -2727,11 +2725,11 @@ CursorStmt:  DECLARE name opt_cursor CURSOR FOR
 				}
 		;
 
-opt_cursor:  BINARY             { $$ = make1_str("binary"); }
-               | INSENSITIVE	{ $$ = make1_str("insensitive"); }
-               | SCROLL         { $$ = make1_str("scroll"); }
+opt_cursor:  BINARY             	{ $$ = make1_str("binary"); }
+               | INSENSITIVE		{ $$ = make1_str("insensitive"); }
+               | SCROLL        		{ $$ = make1_str("scroll"); }
                | INSENSITIVE SCROLL	{ $$ = make1_str("insensitive scroll"); }
-               | /*EMPTY*/      { $$ = make1_str(""); }
+               | /*EMPTY*/      	{ $$ = EMPTY; }
                ;
 
 /*****************************************************************************
@@ -2765,23 +2763,24 @@ SelectStmt:      select_clause sort_clause for_update_clause opt_select_limit
  */
 select_clause: '(' select_clause ')'
                         {
-                               $$ = make3_str(make1_str("("), $2, make1_str(")")); 
+                                $$ = make3_str(make1_str("("), $2, make1_str(")")); 
                         }
                 | SubSelect
                         {
-                               $$ = $1; 
+				FoundInto = 0;
+                                $$ = $1; 
                         }
                 | select_clause EXCEPT select_clause
 			{
 				$$ = cat3_str($1, make1_str("except"), $3);
 				ForUpdateNotAllowed = 1;
 			}
-		| select_clause UNION opt_union select_clause
+		| select_clause UNION opt_all select_clause
 			{
 				$$ = cat4_str($1, make1_str("union"), $3, $4);
 				ForUpdateNotAllowed = 1;
 			}
-		| select_clause INTERSECT opt_union select_clause
+		| select_clause INTERSECT opt_all select_clause
 			{
 				$$ = cat3_str($1, make1_str("intersect"), $3);
 				ForUpdateNotAllowed = 1;
@@ -2798,27 +2797,29 @@ SubSelect:     SELECT opt_unique target_list
 				}
 		;
 
-result:  INTO OptTemp opt_table relation_name		{ $$= cat4_str(make1_str("into"), $2, $3, $4); }
-		| INTO into_list			{ $$ = make1_str(""); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+result:  INTO OptTemp opt_table relation_name		{ FoundInto = 1;
+							  $$= cat4_str(make1_str("into"), $2, $3, $4);
+							}
+		| INTO into_list			{ $$ = EMPTY; }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_table:  TABLE					{ $$ = make1_str("table"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
-opt_union:  ALL						{ $$ = make1_str("all"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+opt_all:  ALL						{ $$ = make1_str("all"); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_unique:  DISTINCT					{ $$ = make1_str("distinct"); }
 		| DISTINCT ON ColId			{ $$ = cat2_str(make1_str("distinct on"), $3); }
 		| ALL					{ $$ = make1_str("all"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 sort_clause:  ORDER BY sortby_list			{ $$ = cat2_str(make1_str("order by"), $3); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 sortby_list:  sortby					{ $$ = $1; }
@@ -2831,12 +2832,10 @@ sortby: a_expr OptUseOp
                                 }
 		;
 
-OptUseOp:  USING Op				{ $$ = cat2_str(make1_str("using"), $2); }
-		| USING '<'			{ $$ = make1_str("using <"); }
-		| USING '>'			{ $$ = make1_str("using >"); }
+OptUseOp:  USING all_Op				{ $$ = cat2_str(make1_str("using"), $2); }
 		| ASC				{ $$ = make1_str("asc"); }
 		| DESC				{ $$ = make1_str("desc"); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 opt_select_limit:      LIMIT select_limit_value ',' select_offset_value
@@ -2850,7 +2849,7 @@ opt_select_limit:      LIMIT select_limit_value ',' select_offset_value
                | OFFSET select_offset_value
                        { $$ = cat2_str(make1_str("offset"), $2); }
                | /* EMPTY */
-                       { $$ = make1_str(""); }
+                       { $$ = EMPTY; }
                ;
 
 select_limit_value:	Iconst	{ $$ = $1; }
@@ -2870,7 +2869,7 @@ select_offset_value:  	Iconst	{ $$ = $1; }
  *	cases for these.
  */
 opt_inh_star:  '*'					{ $$ = make1_str("*"); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 relation_name_list:  name_list { $$ = $1; };
@@ -2882,14 +2881,14 @@ name_list:  name
 		;
 
 group_clause:  GROUP BY expr_list			{ $$ = cat2_str(make1_str("group by"), $3); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 having_clause:  HAVING a_expr
 				{
 					$$ = cat2_str(make1_str("having"), $2);
 				}
-		| /*EMPTY*/		{ $$ = make1_str(""); }
+		| /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 for_update_clause:  FOR UPDATE update_list
@@ -2902,7 +2901,7 @@ for_update_clause:  FOR UPDATE update_list
 		}
 		| /* EMPTY */
                 {
-                        $$ = make1_str("");
+                        $$ = EMPTY;
                 }
                 ;
 update_list:  OF va_list
@@ -2911,7 +2910,7 @@ update_list:  OF va_list
 	      }
               | /* EMPTY */
               {
-                        $$ = make1_str("");
+                        $$ = EMPTY;
               }
               ;
 
@@ -2929,7 +2928,7 @@ from_clause:  FROM from_expr
 		}
 		| /* EMPTY */
 		{
-			$$ = make1_str("");
+			$$ = EMPTY;
 		}
 
 
@@ -3033,12 +3032,12 @@ join_type:  FULL join_outer
 				}
                 | /* EMPTY */
                                 {
-                                        $$ = make1_str("");
+                                        $$ = EMPTY;
 				}
 
 
 join_outer:  OUTER_P				{ $$ = make1_str("outer"); }
-		| /*EMPTY*/			{ $$ = make1_str("");  /* no qualifiers */ }
+		| /*EMPTY*/			{ $$ = EMPTY;  /* no qualifiers */ }
 		;
 
 /* JOIN qualification clauses
@@ -3064,7 +3063,7 @@ using_expr:  ColId
 		;
 
 where_clause:  WHERE a_expr			{ $$ = cat2_str(make1_str("where"), $2); }
-		| /*EMPTY*/				{ $$ = make1_str("");  /* no qualifiers */ }
+		| /*EMPTY*/				{ $$ = EMPTY;  /* no qualifiers */ }
 		;
 
 relation_expr:	relation_name
@@ -3097,7 +3096,7 @@ opt_array_bounds:  '[' ']' opt_array_bounds
 			{
                             $$.index1 = -1;
                             $$.index2 = -1;
-                            $$.str= make1_str("");
+                            $$.str= EMPTY;
                         }
 		;
 
@@ -3222,7 +3221,7 @@ opt_float:  '(' Iconst ')'
 				}
 		| /*EMPTY*/
 				{
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 		;
 
@@ -3248,7 +3247,7 @@ opt_numeric:  '(' Iconst ',' Iconst ')'
 				}
 		| /*EMPTY*/
 				{
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 		;
 
@@ -3274,7 +3273,7 @@ opt_decimal:  '(' Iconst ',' Iconst ')'
 				}
 		| /*EMPTY*/
 				{
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 		;
 
@@ -3317,15 +3316,15 @@ character:  CHARACTER opt_varying opt_charset opt_collate
 		;
 
 opt_varying:  VARYING			{ $$ = make1_str("varying"); }
-		| /*EMPTY*/			{ $$ = make1_str(""); }
+		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
 opt_charset:  CHARACTER SET ColId	{ $$ = cat2_str(make1_str("character set"), $3); }
-		| /*EMPTY*/				{ $$ = make1_str(""); }
+		| /*EMPTY*/				{ $$ = EMPTY; }
 		;
 
 opt_collate:  COLLATE ColId		{ $$ = cat2_str(make1_str("collate"), $2); }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 Datetime:  datetime
@@ -3355,7 +3354,7 @@ datetime:  YEAR_P								{ $$ = make1_str("year"); }
 		;
 
 opt_timezone:  WITH TIME ZONE				{ $$ = make1_str("with time zone"); }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 opt_interval:  datetime					{ $$ = $1; }
@@ -3366,13 +3365,13 @@ opt_interval:  datetime					{ $$ = $1; }
 		| HOUR_P TO MINUTE_P			{ $$ = make1_str("hour to minute"); }
 		| MINUTE_P TO SECOND_P			{ $$ = make1_str("minute to second"); }
 		| HOUR_P TO SECOND_P			{ $$ = make1_str("hour to second"); }
-		| /*EMPTY*/					{ $$ = make1_str(""); }
+		| /*EMPTY*/					{ $$ = EMPTY; }
 		;
 
 
 /*****************************************************************************
  *
- *	expression grammar, still needs some cleanup
+ *	expression grammar
  *
  *****************************************************************************/
 
@@ -3387,11 +3386,6 @@ a_expr_or_null:  a_expr
 /* Expressions using row descriptors
  * Define row_descriptor to allow yacc to break the reduce/reduce conflict
  *  with singleton expressions.
- * Eliminated lots of code by defining row_op and sub_type clauses.
- * However, can not consolidate EXPR_LINK case with others subselects
- *  due to shift/reduce conflict with the non-subselect clause (the parser
- *  would have to look ahead more than one token to resolve the conflict).
- * - thomas 1998-05-09
  */
 row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
 				{
@@ -3401,15 +3395,15 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
 				{
 					$$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")"));
 				}
-		| '(' row_descriptor ')' row_op sub_type  '(' SubSelect ')'
+		| '(' row_descriptor ')' all_Op sub_type  '(' SubSelect ')'
 				{
 					$$ = make4_str(make5_str(make1_str("("), $2, make1_str(")"), $4, $5), make1_str("("), $7, make1_str(")"));
 				}
-		| '(' row_descriptor ')' row_op '(' SubSelect ')'
+		| '(' row_descriptor ')' all_Op '(' SubSelect ')'
 				{
 					$$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")"));
 				}
-		| '(' row_descriptor ')' row_op '(' row_descriptor ')'
+		| '(' row_descriptor ')' all_Op '(' row_descriptor ')'
 				{
 					$$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("("), $6, make1_str(")")));
 				}
@@ -3421,19 +3415,6 @@ row_descriptor:  row_list ',' a_expr
 				}
 		;
 
-row_op:  Op			{ $$ = $1; }
-	| '<'                   { $$ = "<"; }
-        | '='                   { $$ = "="; }
-        | '>'                   { $$ = ">"; }
-        | '+'                   { $$ = "+"; }
-        | '-'                   { $$ = "-"; }
-        | '*'                   { $$ = "*"; }
-        | '%'                   { $$ = "%"; }
-        | '/'                   { $$ = "/"; }
-        | '^'                   { $$ = "^"; }
-        | '|'                   { $$ = "|"; }
-              ;
-
 sub_type:  ANY                  { $$ = make1_str("ANY"); }
          | ALL                  { $$ = make1_str("ALL"); }
               ;
@@ -3449,27 +3430,49 @@ row_list:  row_list ',' a_expr
 				}
 		;
 
+all_Op:  Op | MathOp;
+
+MathOp:	'+'				{ $$ = make1_str("+"); }
+		| '-'			{ $$ = make1_str("-"); }
+		| '*'			{ $$ = make1_str("*"); }
+		| '%'			{ $$ = make1_str("%"); }
+                | '^'                   { $$ = make1_str("^"); }
+                | '|'                   { $$ = make1_str("|"); }
+		| '/'			{ $$ = make1_str("/"); }
+		| '<'			{ $$ = make1_str("<"); }
+		| '>'			{ $$ = make1_str(">"); }
+		| '='			{ $$ = make1_str("="); }
+		;
+
 /* General expressions
  * This is the heart of the expression syntax.
- * Note that the BETWEEN clause looks similar to a boolean expression
- *  and so we must define b_expr which is almost the same as a_expr
- *  but without the boolean expressions.
- * All operations/expressions are allowed in a BETWEEN clause
- *  if surrounded by parens.
+ *
+ * We have two expression types: a_expr is the unrestricted kind, and
+ * b_expr is a subset that must be used in some places to avoid shift/reduce
+ * conflicts.  For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr"
+ * because that use of AND conflicts with AND as a boolean operator.  So,
+ * b_expr is used in BETWEEN and we remove boolean keywords from b_expr.
+ *
+ * Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
+ * always be used by surrounding it with parens.
+ *
+ * com_expr is all the productions that are common to a_expr and b_expr;
+ * it's factored out just to eliminate redundant coding.
  */
 
-a_expr:  attr
-				{
-					$$ = $1;
-				}
-		| row_expr
-				{	$$ = $1;  }
-		| AexprConst
-				{	$$ = $1;  }
-		| ColId opt_indirection
-				{
-					$$ = cat2_str($1, $2);
-				}
+a_expr:  com_expr
+				{	$$ = $1; }
+		| a_expr TYPECAST Typename
+				{	$$ = cat3_str($1, make1_str("::"), $3); }
+		/*
+                 * These operators must be called out explicitly in order to make use
+                 * of yacc/bison's automatic operator-precedence handling.  All other
+                 * operator names are handled by the generic productions using "Op",
+                 * below; and all those operators will have the same precedence.
+                 *
+                 * If you add more explicitly-known operators, be sure to add them
+                 * also to b_expr and to the MathOp list above.
+                 */
 		| '-' a_expr %prec UMINUS
 				{	$$ = cat2_str(make1_str("-"), $2); }
 		| '%' a_expr
@@ -3509,107 +3512,27 @@ a_expr:  attr
 				{	$$ = cat3_str($1, make1_str(">"), $3); }
 		| a_expr '=' NULL_P
                                 {       $$ = cat2_str($1, make1_str("= NULL")); }
+		/* We allow this for standards-broken SQL products, like MS stuff */
 		| NULL_P '=' a_expr
                                 {       $$ = cat2_str(make1_str("= NULL"), $3); }
 		| a_expr '=' a_expr
 				{	$$ = cat3_str($1, make1_str("="), $3); }
-		| a_expr TYPECAST Typename
-				{
-					$$ = cat3_str($1, make1_str("::"), $3);
-				}
-		| CAST '(' a_expr AS Typename ')'
-				{
-					$$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")")));
-				}
-		| '(' a_expr_or_null ')'
-				{	$$ = make3_str(make1_str("("), $2, make1_str(")")); }
 		| a_expr Op a_expr
-				{	$$ = cat3_str($1, $2, $3);	}
-		| a_expr LIKE a_expr
-				{	$$ = cat3_str($1, make1_str("like"), $3); }
-		| a_expr NOT LIKE a_expr
-				{	$$ = cat3_str($1, make1_str("not like"), $4); }
+				{	$$ = cat3_str($1, make1_str("="), $3); }
 		| Op a_expr
 				{	$$ = cat2_str($1, $2); }
 		| a_expr Op
 				{	$$ = cat2_str($1, $2); }
-		| func_name '(' '*' ')'
-				{
-					$$ = cat2_str($1, make1_str("(*)")); 
-				}
-		| func_name '(' ')'
-				{
-					$$ = cat2_str($1, make1_str("()")); 
-				}
-		| func_name '(' expr_list ')'
-				{
-					$$ = make4_str($1, make1_str("("), $3, make1_str(")")); 
-				}
-		| CURRENT_DATE
-				{
-					$$ = make1_str("current_date");
-				}
-		| CURRENT_TIME
-				{
-					$$ = make1_str("current_time");
-				}
-		| CURRENT_TIME '(' Iconst ')'
-				{
-					if (atol($3) != 0)
-						fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
-					$$ = make1_str("current_time");
-				}
-		| CURRENT_TIMESTAMP
-				{
-					$$ = make1_str("current_timestamp");
-				}
-		| CURRENT_TIMESTAMP '(' Iconst ')'
-				{
-					if (atol($3) != 0)
-						fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
-					$$ = make1_str("current_timestamp");
-				}
-		| CURRENT_USER
-				{
-					$$ = make1_str("current_user");
-				}
-		| USER
-				{
-  		     		        $$ = make1_str("user");
-			     	}
-		| EXISTS '(' SubSelect ')'
-				{
-					$$ = make3_str(make1_str("exists("), $3, make1_str(")"));
-				}
-		| EXTRACT '(' extract_list ')'
-				{
-					$$ = make3_str(make1_str("extract("), $3, make1_str(")"));
-				}
-		| POSITION '(' position_list ')'
-				{
-					$$ = make3_str(make1_str("position("), $3, make1_str(")"));
-				}
-		| SUBSTRING '(' substr_list ')'
-				{
-					$$ = make3_str(make1_str("substring("), $3, make1_str(")"));
-				}
-		/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
-		| TRIM '(' BOTH trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(both"), $4, make1_str(")"));
-				}
-		| TRIM '(' LEADING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(leading"), $4, make1_str(")"));
-				}
-		| TRIM '(' TRAILING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")"));
-				}
-		| TRIM '(' trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
-				}
+		| a_expr AND a_expr
+				{	$$ = cat3_str($1, make1_str("and"), $3); }
+		| a_expr OR a_expr
+				{	$$ = cat3_str($1, make1_str("or"), $3); }
+		| NOT a_expr
+				{	$$ = cat2_str(make1_str("not"), $2); }
+		| a_expr LIKE a_expr
+				{	$$ = cat3_str($1, make1_str("like"), $3); }
+		| a_expr NOT LIKE a_expr
+				{	$$ = cat3_str($1, make1_str("not like"), $4); }
 		| a_expr ISNULL
 				{	$$ = cat2_str($1, make1_str("isnull")); }
 		| a_expr IS NULL_P
@@ -3624,21 +3547,13 @@ a_expr:  attr
 		 * - thomas 1997-12-22
 		 */
 		| a_expr IS TRUE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is true")); }
-				}
 		| a_expr IS NOT FALSE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is not false")); }
-				}
 		| a_expr IS FALSE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is false")); }
-				}
 		| a_expr IS NOT TRUE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is not true")); }
-				}
 		| a_expr BETWEEN b_expr AND b_expr
 				{
 					$$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); 
@@ -3655,164 +3570,31 @@ a_expr:  attr
 				{
 					$$ = make4_str($1, make1_str(" not in ("), $5, make1_str(")")); 
 				}
-		| a_expr Op '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("("), $4, make1_str(")"))); 
-				}
-		| a_expr '+' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+("), $4, make1_str(")")); 
-				}
-		| a_expr '-' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("-("), $4, make1_str(")")); 
-				}
-		| a_expr '*' '(' SubSelect ')'
+		| a_expr all_Op sub_type '(' SubSelect ')'
 				{
-					$$ = make4_str($1, make1_str("*("), $4, make1_str(")")); 
+					$$ = cat4_str($1, $2, $3, make3_str(make1_str("("), $5, make1_str(")"))); 
 				}
-		| a_expr '/' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/("), $4, make1_str(")")); 
-				}
-		| a_expr '%' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("%("), $4, make1_str(")")); 
-				}
-		| a_expr '^' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("^("), $4, make1_str(")")); 
-				}
-		| a_expr '|' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("|("), $4, make1_str(")")); 
-				}
-		| a_expr '<' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("<("), $4, make1_str(")")); 
-				}
-		| a_expr '>' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str(">("), $4, make1_str(")")); 
-				}
-		| a_expr '=' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("=("), $4, make1_str(")")); 
-				}
-		| a_expr Op ANY '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("any("), $5, make1_str(")"))); 
-				}
-		| a_expr '+' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+ any("), $5, make1_str(")")); 
-				}
-		| a_expr '-' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("- any("), $5, make1_str(")")); 
-				}
-		| a_expr '*' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("* any("), $5, make1_str(")")); 
-				}
-		| a_expr '/' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/ any("), $5, make1_str(")")); 
-				}
-		| a_expr '%' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("% any("), $5, make1_str(")")); 
-				}
-		| a_expr '^' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("^ any("), $5, make1_str(")")); 
-				}
-		| a_expr '|' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("| any("), $5, make1_str(")")); 
-				}
-		| a_expr '<' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("< any("), $5, make1_str(")")); 
-				}
-		| a_expr '>' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("> any("), $5, make1_str(")")); 
-				}
-		| a_expr '=' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("= any("), $5, make1_str(")")); 
-				}
-		| a_expr Op ALL '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("all ("), $5, make1_str(")"))); 
-				}
-		| a_expr '+' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+ all("), $5, make1_str(")")); 
-				}
-		| a_expr '-' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("- all("), $5, make1_str(")")); 
-				}
-		| a_expr '*' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("* all("), $5, make1_str(")")); 
-				}
-		| a_expr '/' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/ all("), $5, make1_str(")")); 
-				}
-		| a_expr '%' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("% all("), $5, make1_str(")")); 
-				}
-		| a_expr '^' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("^ all("), $5, make1_str(")")); 
-				}
-		| a_expr '|' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("| all("), $5, make1_str(")")); 
-				}
-		| a_expr '<' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("< all("), $5, make1_str(")")); 
-				}
-		| a_expr '>' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("> all("), $5, make1_str(")")); 
-				}
-		| a_expr '=' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("= all("), $5, make1_str(")")); 
-				}
-		| a_expr AND a_expr
-				{	$$ = cat3_str($1, make1_str("and"), $3); }
-		| a_expr OR a_expr
-				{	$$ = cat3_str($1, make1_str("or"), $3); }
-		| NOT a_expr
-				{	$$ = cat2_str(make1_str("not"), $2); }
-		| case_expr
+		| row_expr
 				{       $$ = $1; }
 		| cinputvariable
 			        { $$ = make1_str("?"); }
 		;
 
 /* Restricted expressions
+ *
  * b_expr is a subset of the complete expression syntax
- *  defined by a_expr. b_expr is used in BETWEEN clauses
- *  to eliminate parser ambiguities stemming from the AND keyword.
+ *
+ * Presently, AND, NOT, IS, IN, and NULL are the a_expr keywords that would
+ * cause trouble in the places where b_expr is used.  For simplicity, we
+ * just eliminate all the boolean-keyword-operator productions from b_expr.
  */
-b_expr:  attr
+b_expr:  com_expr
 				{
-					$$ = $1
+					$$ = $1;
 				}
-		| AexprConst
-				{	$$ = $1;  }
-		| ColId opt_indirection
+		| b_expr TYPECAST Typename
 				{
-					$$ = cat2_str($1, $2);
+					$$ = cat3_str($1, make1_str("::"), $3);
 				}
 		| '-' b_expr %prec UMINUS
 				{	$$ = cat2_str(make1_str("-"), $2); }
@@ -3820,13 +3602,13 @@ b_expr:  attr
 				{       $$ = cat2_str(make1_str("%"), $2); }
 		| '^' b_expr
 				{       $$ = cat2_str(make1_str("^"), $2); }
-/* not possible in embedded sql		| ':' b_expr
-				{	$$ = cat2_str(make1_str(":"), $2); }
+		| '|' b_expr
+				{       $$ = cat2_str(make1_str("|"), $2); }
+/* not possible in embedded sql		| ':' b_expr	
+				{       $$ = cat2_str(make1_str(":"), $2); }
 */
 		| ';' b_expr
-				{	$$ = cat2_str(make1_str(";"), $2); }
-		| '|' b_expr
-				{	$$ = cat2_str(make1_str("|"), $2); }
+				{       $$ = cat2_str(make1_str(";"), $2); }
 		| b_expr '%'
 				{       $$ = cat2_str($1, make1_str("%")); }
 		| b_expr '^'
@@ -3847,48 +3629,60 @@ b_expr:  attr
 				{	$$ = cat3_str($1, make1_str("^"), $3); }
 		| b_expr '|' b_expr
 				{	$$ = cat3_str($1, make1_str("|"), $3); }
-		| b_expr TYPECAST Typename
-				{
-					$$ = cat3_str($1, make1_str("::"), $3);
-				}
-		| CAST '(' b_expr AS Typename ')'
-				{
-					$$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")")));
-				}
-		| '(' a_expr ')'
-				{	$$ = make3_str(make1_str("("), $2, make1_str(")")); }
+		| b_expr '<' b_expr
+				{	$$ = cat3_str($1, make1_str("<"), $3); }
+		| b_expr '>' b_expr
+				{	$$ = cat3_str($1, make1_str(">"), $3); }
+		| b_expr '=' b_expr
+				{	$$ = cat3_str($1, make1_str("="), $3); }
 		| b_expr Op b_expr
-				{	$$ = cat3_str($1, $2, $3);	}
+				{	$$ = cat3_str($1, make1_str("="), $3); }
 		| Op b_expr
 				{	$$ = cat2_str($1, $2); }
 		| b_expr Op
 				{	$$ = cat2_str($1, $2); }
+		| civariableonly
+			        { 	$$ = $1; }
+		;
+
+/*
+ * Productions that can be used in both a_expr and b_expr.
+ *
+ * Note: productions that refer recursively to a_expr or b_expr mostly
+ * cannot appear here.  However, it's OK to refer to a_exprs that occur
+ * inside parentheses, such as function arguments; that cannot introduce
+ * ambiguity to the b_expr syntax.
+ */
+com_expr:  attr
+				{	$$ = $1;  }
+		| ColId opt_indirection
+				{	$$ = cat2_str($1, $2);	}
+		| AexprConst
+				{	$$ = $1;  }
+		| '(' a_expr_or_null ')'
+				{	$$ = make3_str(make1_str("("), $2, make1_str(")")); }
+		| CAST '(' a_expr AS Typename ')'
+				{ 	$$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")"))); }
+		| case_expr
+				{       $$ = $1; }
 		| func_name '(' ')'
-				{
-					$$ = cat2_str($1, make1_str("()")); 
-				}
+				{	$$ = cat2_str($1, make1_str("()"));  }
 		| func_name '(' expr_list ')'
-				{
-					$$ = make4_str($1, make1_str("("), $3, make1_str(")")); 
-				}
+				{	$$ = make4_str($1, make1_str("("), $3, make1_str(")"));  }
+		| func_name '(' '*' ')'
+				{	$$ = cat2_str($1, make1_str("(*)")); }
 		| CURRENT_DATE
-				{
-					$$ = make1_str("current_date");
-				}
+				{	$$ = make1_str("current_date"); }
 		| CURRENT_TIME
-				{
-					$$ = make1_str("current_time");
-				}
+				{	$$ = make1_str("current_time"); }
 		| CURRENT_TIME '(' Iconst ')'
 				{
-					if ($3 != 0)
+					if (atol($3) != 0)
 						fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
 					$$ = make1_str("current_time");
 				}
 		| CURRENT_TIMESTAMP
-				{
-					$$ = make1_str("current_timestamp");
-				}
+				{	$$ = make1_str("current_timestamp"); }
 		| CURRENT_TIMESTAMP '(' Iconst ')'
 				{
 					if (atol($3) != 0)
@@ -3896,52 +3690,43 @@ b_expr:  attr
 					$$ = make1_str("current_timestamp");
 				}
 		| CURRENT_USER
-				{
-					$$ = make1_str("current_user");
-				}
+				{	$$ = make1_str("current_user"); }
 		| USER
-				{
-					$$ = make1_str("user");
-				}
+				{       $$ = make1_str("user"); }
+		| EXTRACT '(' extract_list ')'
+				{	$$ = make3_str(make1_str("extract("), $3, make1_str(")")); }
 		| POSITION '(' position_list ')'
-				{
-					$$ = make3_str(make1_str("position ("), $3, make1_str(")"));
-				}
+				{	$$ = make3_str(make1_str("position("), $3, make1_str(")")); }
 		| SUBSTRING '(' substr_list ')'
-				{
-					$$ = make3_str(make1_str("substring ("), $3, make1_str(")"));
-				}
+				{	$$ = make3_str(make1_str("substring("), $3, make1_str(")")); }
 		/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
 		| TRIM '(' BOTH trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(both"), $4, make1_str(")"));
-				}
+				{	$$ = make3_str(make1_str("trim(both"), $4, make1_str(")")); }
 		| TRIM '(' LEADING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(leading"), $4, make1_str(")"));
-				}
+				{	$$ = make3_str(make1_str("trim(leading"), $4, make1_str(")")); }
 		| TRIM '(' TRAILING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")"));
-				}
+				{	$$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")")); }
 		| TRIM '(' trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
-				}
-		| civariableonly
-			        { 	$$ = $1; }
+				{	$$ = make3_str(make1_str("trim("), $3, make1_str(")")); }
+		| '(' SubSelect ')'
+				{	$$ = make3_str(make1_str("("), $2, make1_str(")")); }
+		| EXISTS '(' SubSelect ')'
+				{	$$ = make3_str(make1_str("exists("), $3, make1_str(")")); }
 		;
-
-opt_indirection:  '[' ecpg_expr ']' opt_indirection
+/* 
+ * This used to use ecpg_expr, but since there is no shift/reduce conflict
+ * anymore, we can remove ecpg_expr. - MM
+ */
+opt_indirection:  '[' a_expr ']' opt_indirection
 				{
 					$$ = cat4_str(make1_str("["), $2, make1_str("]"), $4);
 				}
-		| '[' ecpg_expr ':' ecpg_expr ']' opt_indirection
+		| '[' a_expr ':' a_expr ']' opt_indirection
 				{
 					$$ = cat2_str(cat5_str(make1_str("["), $2, make1_str(":"), $4, make1_str("]")), $6);
 				}
 		| /* EMPTY */
-				{	$$ = make1_str(""); }
+				{	$$ = EMPTY; }
 		;
 
 expr_list:  a_expr_or_null
@@ -3957,7 +3742,7 @@ extract_list:  extract_arg FROM a_expr
 					$$ = cat3_str($1, make1_str("from"), $3);
 				}
 		| /* EMPTY */
-				{	$$ = make1_str(""); }
+				{	$$ = EMPTY; }
 		| cinputvariable
 			        { $$ = make1_str("?"); }
 		;
@@ -3971,7 +3756,7 @@ extract_arg:  datetime		{ $$ = $1; }
 position_list:  b_expr IN b_expr
 				{	$$ = cat3_str($1, make1_str("in"), $3); }
 		| /* EMPTY */
-				{	$$ = make1_str(""); }
+				{	$$ = EMPTY; }
 		;
 
 substr_list:  expr_list substr_from substr_for
@@ -3979,21 +3764,21 @@ substr_list:  expr_list substr_from substr_for
 					$$ = cat3_str($1, $2, $3);
 				}
 		| /* EMPTY */
-				{	$$ = make1_str(""); }
+				{	$$ = EMPTY; }
 		;
 
 substr_from:  FROM expr_list
 				{	$$ = cat2_str(make1_str("from"), $2); }
 		| /* EMPTY */
 				{
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 		;
 
 substr_for:  FOR expr_list
 				{	$$ = cat2_str(make1_str("for"), $2); }
 		| /* EMPTY */
-				{	$$ = make1_str(""); }
+				{	$$ = EMPTY; }
 		;
 
 trim_list:  a_expr FROM expr_list
@@ -4060,14 +3845,14 @@ when_clause:  WHEN a_expr THEN a_expr_or_null
                ;
 
 case_default:  ELSE a_expr_or_null	{ $$ = cat2_str(make1_str("else"), $2); }
-               | /*EMPTY*/        	{ $$ = make1_str(""); }
+               | /*EMPTY*/        	{ $$ = EMPTY; }
                ;
 
 case_arg:  a_expr              {
                                        $$ = $1;
                                }
                | /*EMPTY*/
-                               {       $$ = make1_str(""); }
+                               {       $$ = EMPTY; }
                ;
 
 attr:  relation_name '.' attrs opt_indirection
@@ -4526,13 +4311,13 @@ server: Op server_name
 	        }
 
 opt_server: server { $$ = $1; }
-        | /* empty */ { $$ = make1_str(""); }
+        | /* empty */ { $$ = EMPTY; }
 
 server_name: ColId   { $$ = $1; }
         | ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); }
 
 opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); }
-        | /* empty */ { $$ = make1_str(""); }
+        | /* empty */ { $$ = EMPTY; }
 
 opt_connection_name: AS connection_target { $$ = $2; }
         | /* empty */ { $$ = make1_str("NULL"); }
@@ -4602,7 +4387,7 @@ opt_options: Op ColId
 			
 			$$ = make2_str(make1_str("?"), $2);
 		}
-	| /* empty */ { $$ = make1_str(""); }
+	| /* empty */ { $$ = EMPTY; }
 
 /*
  * Declare a prepared cursor. The syntax is different from the standard
@@ -4674,7 +4459,7 @@ sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {}
 
 variable_declarations: /* empty */
 	{
-		$$ = make1_str("");
+		$$ = EMPTY;
 	}
 	| declaration variable_declarations
 	{
@@ -4702,7 +4487,7 @@ storage_clause : S_EXTERN	{ $$ = make1_str("extern"); }
        | S_CONST		{ $$ = make1_str("const"); }
        | S_REGISTER		{ $$ = make1_str("register"); }
        | S_AUTO			{ $$ = make1_str("auto"); }
-       | /* empty */		{ $$ = make1_str(""); }
+       | /* empty */		{ $$ = EMPTY; }
 
 type: simple_type
 		{
@@ -4714,7 +4499,7 @@ type: simple_type
 	| varchar_type
 		{
 			$$.type_enum = ECPGt_varchar;
-			$$.type_str = make1_str("");
+			$$.type_str = EMPTY;
 			$$.type_dimension = -1;
   			$$.type_index = -1;
 		}
@@ -4744,7 +4529,7 @@ type: simple_type
 			/* this is for typedef'ed types */
 			struct typedefs *this = get_typedef($1);
 
-			$$.type_str = (this->type->type_enum == ECPGt_varchar) ? make1_str("") : mm_strdup(this->name);
+			$$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name);
                         $$.type_enum = this->type->type_enum;
 			$$.type_dimension = this->type->type_dimension;
   			$$.type_index = this->type->type_index;
@@ -4788,7 +4573,7 @@ s_union : S_UNION opt_symbol
 	    $$ = cat2_str(make1_str("union"), $2);
 	}
 
-opt_symbol: /* empty */ 	{ $$ = make1_str(""); }
+opt_symbol: /* empty */ 	{ $$ = EMPTY; }
 	| symbol		{ $$ = $1; }
 
 simple_type: S_SHORT		{ $$ = ECPGt_short; }
@@ -4889,10 +4674,10 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer
 			free($2);
 		}
 
-opt_initializer: /* empty */		{ $$ = make1_str(""); }
+opt_initializer: /* empty */		{ $$ = EMPTY; }
 	| '=' c_term			{ $$ = make2_str(make1_str("="), $2); }
 
-opt_pointer: /* empty */	{ $$ = make1_str(""); }
+opt_pointer: /* empty */	{ $$ = EMPTY; }
 	| '*'			{ $$ = make1_str("*"); }
 
 /*
@@ -4944,7 +4729,7 @@ ECPGExecute : EXECUTE IMMEDIATE execstring
 		sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
 
 		add_variable(&argsinsert, thisquery, &no_indicator); 
-	} opt_using
+	} ecpg_using
 	{
 		$$ = make1_str("?");
 	}
@@ -4961,14 +4746,14 @@ ECPGFree:	SQL_FREE ident	{ $$ = $2; }
 /*
  * open is an open cursor, at the moment this has to be removed
  */
-ECPGOpen: SQL_OPEN name opt_using {
+ECPGOpen: SQL_OPEN name ecpg_using {
 		$$ = $2;
 };
 
-opt_using: /* empty */		{ $$ = make1_str(""); }
+ecpg_using: /* empty */		{ $$ = EMPTY; }
 	| USING variablelist	{
 					/* yyerror ("open cursor with variables not implemented yet"); */
-					$$ = make1_str("");
+					$$ = EMPTY;
 				}
 
 variablelist: cinputvariable | cinputvariable ',' variablelist
@@ -5012,7 +4797,7 @@ ECPGSetAutocommit:  SET SQL_AUTOCOMMIT to_equal on_off
 on_off:	ON		{ $$ = make1_str("on"); }
 	| SQL_OFF	{ $$ = make1_str("off"); }
 
-to_equal:	TO | "=";
+to_equal:	TO | '=';
 
 /* 
  * set the actual connection, this needs a differnet handling as the other
@@ -5102,12 +4887,12 @@ opt_type_array_bounds:  '[' ']' opt_type_array_bounds
 			{
                             $$.index1 = -1;
                             $$.index2 = -1;
-                            $$.str= make1_str("");
+                            $$.str= EMPTY;
                         }
 		;
 
 opt_reference: SQL_REFERENCE { $$ = make1_str("reference"); }
-	| /* empty */ 	     { $$ = make1_str(""); }
+	| /* empty */ 	     { $$ = EMPTY; }
 
 ctype: CHAR
 	{
@@ -5234,7 +5019,7 @@ opt_signed: SQL_SIGNED | /* empty */
 
 sql_variable_declarations: /* empty */
 	{
-		$$ = make1_str("");
+		$$ = EMPTY;
 	}
 	| sql_declaration sql_variable_declarations
 	{
@@ -5446,28 +5231,22 @@ action : SQL_CONTINUE {
 }
 
 /* some other stuff for ecpg */
-ecpg_expr:  attr 
-				{
-					$$ = $1;
-				}
-		| row_expr
-				{	$$ = $1;  }
-		| AexprConst
-				{	$$ = $1;  }
-		| ColId opt_indirection
-				{
-					$$ = cat2_str($1, $2);
-				}
+/*
+ * no longer used
+ecpg_expr:  com_expr 
+				{	$$ = $1; }
+		| a_expr TYPECAST Typename
+				{	$$ = cat3_str($1, make1_str("::"), $3); }
 		| '-' ecpg_expr %prec UMINUS
 				{	$$ = cat2_str(make1_str("-"), $2); }
 		| '%' ecpg_expr
 				{       $$ = cat2_str(make1_str("%"), $2); }
 		| '^' ecpg_expr
 				{       $$ = cat2_str(make1_str("^"), $2); }
-		| ';' ecpg_expr
-				{	$$ = cat2_str(make1_str(";"), $2); }
 		| '|' ecpg_expr
-				{	$$ = cat2_str(make1_str("|"), $2); }
+				{       $$ = cat2_str(make1_str("|"), $2); }
+		| ';' a_expr
+				{       $$ = cat2_str(make1_str(";"), $2); }
 		| a_expr '%'
 				{       $$ = cat2_str($1, make1_str("%")); }
 		| a_expr '^'
@@ -5493,108 +5272,27 @@ ecpg_expr:  attr
 		| a_expr '>' ecpg_expr
 				{	$$ = cat3_str($1, make1_str(">"), $3); }
 		| a_expr '=' NULL_P
-				{       $$ = cat2_str($1, make1_str("= NULL")); }
-		| NULL_P '=' a_expr
-				{       $$ = cat2_str(make1_str("= NULL"), $3); }
+                                {       $$ = cat2_str($1, make1_str("= NULL")); }
+		| NULL_P '=' ecpg_expr
+                                {       $$ = cat2_str(make1_str("= NULL"), $3); }
 		| a_expr '=' ecpg_expr
 				{	$$ = cat3_str($1, make1_str("="), $3); }
-		| a_expr TYPECAST Typename
-				{
-					$$ = cat3_str($1, make1_str("::"), $3);
-				}
-		| CAST '(' a_expr AS Typename ')'
-				{
-					$$ = cat3_str(make2_str(make1_str("cast("), $3), make1_str("as"), make2_str($5, make1_str(")")));
-				}
-		| '(' a_expr_or_null ')'
-				{	$$ = make3_str(make1_str("("), $2, make1_str(")")); }
 		| a_expr Op ecpg_expr
-				{	$$ = cat3_str($1, $2, $3);	}
-		| a_expr LIKE ecpg_expr
-				{	$$ = cat3_str($1, make1_str("like"), $3); }
-		| a_expr NOT LIKE ecpg_expr
-				{	$$ = cat3_str($1, make1_str("not like"), $4); }
+				{	$$ = cat3_str($1, make1_str("="), $3); }
 		| Op ecpg_expr
 				{	$$ = cat2_str($1, $2); }
 		| a_expr Op
 				{	$$ = cat2_str($1, $2); }
-		| func_name '(' '*' ')'
-				{
-					$$ = cat2_str($1, make1_str("(*)")); 
-				}
-		| func_name '(' ')'
-				{
-					$$ = cat2_str($1, make1_str("()")); 
-				}
-		| func_name '(' expr_list ')'
-				{
-					$$ = make4_str($1, make1_str("("), $3, make1_str(")")); 
-				}
-		| CURRENT_DATE
-				{
-					$$ = make1_str("current_date");
-				}
-		| CURRENT_TIME
-				{
-					$$ = make1_str("current_time");
-				}
-		| CURRENT_TIME '(' Iconst ')'
-				{
-					if (atol($3) != 0)
-						fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
-					$$ = make1_str("current_time");
-				}
-		| CURRENT_TIMESTAMP
-				{
-					$$ = make1_str("current_timestamp");
-				}
-		| CURRENT_TIMESTAMP '(' Iconst ')'
-				{
-					if (atol($3) != 0)
-						fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
-					$$ = make1_str("current_timestamp");
-				}
-		| CURRENT_USER
-				{
-					$$ = make1_str("current_user");
-				}
-		| USER
-				{
-  		     		        $$ = make1_str("user");
-			     	}
-		| EXISTS '(' SubSelect ')'
-				{
-					$$ = make3_str(make1_str("exists("), $3, make1_str(")"));
-				}
-		| EXTRACT '(' extract_list ')'
-				{
-					$$ = make3_str(make1_str("extract("), $3, make1_str(")"));
-				}
-		| POSITION '(' position_list ')'
-				{
-					$$ = make3_str(make1_str("position("), $3, make1_str(")"));
-				}
-		| SUBSTRING '(' substr_list ')'
-				{
-					$$ = make3_str(make1_str("substring("), $3, make1_str(")"));
-				}
-		/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
-		| TRIM '(' BOTH trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(both"), $4, make1_str(")"));
-				}
-		| TRIM '(' LEADING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(leading"), $4, make1_str(")"));
-				}
-		| TRIM '(' TRAILING trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim(trailing"), $4, make1_str(")"));
-				}
-		| TRIM '(' trim_list ')'
-				{
-					$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
-				}
+		| a_expr AND ecpg_expr
+				{	$$ = cat3_str($1, make1_str("and"), $3); }
+		| a_expr OR ecpg_expr
+				{	$$ = cat3_str($1, make1_str("or"), $3); }
+		| NOT ecpg_expr
+				{	$$ = cat2_str(make1_str("not"), $2); }
+		| a_expr LIKE ecpg_expr
+				{	$$ = cat3_str($1, make1_str("like"), $3); }
+		| a_expr NOT LIKE ecpg_expr
+				{	$$ = cat3_str($1, make1_str("not like"), $4); }
 		| a_expr ISNULL
 				{	$$ = cat2_str($1, make1_str("isnull")); }
 		| a_expr IS NULL_P
@@ -5603,27 +5301,14 @@ ecpg_expr:  attr
 				{	$$ = cat2_str($1, make1_str("notnull")); }
 		| a_expr IS NOT NULL_P
 				{	$$ = cat2_str($1, make1_str("is not null")); }
-		/* IS TRUE, IS FALSE, etc used to be function calls
-		 *  but let's make them expressions to allow the optimizer
-		 *  a chance to eliminate them if a_expr is a constant string.
-		 * - thomas 1997-12-22
-		 */
 		| a_expr IS TRUE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is true")); }
-				}
 		| a_expr IS NOT FALSE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is not false")); }
-				}
 		| a_expr IS FALSE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is false")); }
-				}
 		| a_expr IS NOT TRUE_P
-				{
 				{	$$ = cat2_str($1, make1_str("is not true")); }
-				}
 		| a_expr BETWEEN b_expr AND b_expr
 				{
 					$$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); 
@@ -5640,155 +5325,22 @@ ecpg_expr:  attr
 				{
 					$$ = make4_str($1, make1_str(" not in ("), $5, make1_str(")")); 
 				}
-		| a_expr Op '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("("), $4, make1_str(")"))); 
-				}
-		| a_expr '+' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+("), $4, make1_str(")")); 
-				}
-		| a_expr '-' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("-("), $4, make1_str(")")); 
-				}
-		| a_expr '*' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("*("), $4, make1_str(")")); 
-				}
-		| a_expr '/' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/("), $4, make1_str(")")); 
-				}
-		| a_expr '%' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("%("), $4, make1_str(")")); 
-				}
-		| a_expr '^' '(' SubSelect ')'
+		| a_expr all_Op sub_type '(' SubSelect ')'
 				{
-					$$ = make4_str($1, make1_str("^("), $4, make1_str(")")); 
+					$$ = cat4_str($1, $2, $3, make3_str(make1_str("("), $5, make1_str(")"))); 
 				}
-		| a_expr '|' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("|("), $4, make1_str(")")); 
-				}
-		| a_expr '<' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("<("), $4, make1_str(")")); 
-				}
-		| a_expr '>' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str(">("), $4, make1_str(")")); 
-				}
-		| a_expr '=' '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("=("), $4, make1_str(")")); 
-				}
-		| a_expr Op ANY '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("any ("), $5, make1_str(")"))); 
-				}
-		| a_expr '+' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+ any("), $5, make1_str(")")); 
-				}
-		| a_expr '-' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("- any("), $5, make1_str(")")); 
-				}
-		| a_expr '*' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("* any("), $5, make1_str(")")); 
-				}
-		| a_expr '/' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/ any("), $5, make1_str(")")); 
-				}
-		| a_expr '%' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("% any("), $5, make1_str(")")); 
-				}
-		| a_expr '^' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("^ any("), $5, make1_str(")")); 
-				}
-		| a_expr '|' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("| any("), $5, make1_str(")")); 
-				}
-		| a_expr '<' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("< any("), $5, make1_str(")")); 
-				}
-		| a_expr '>' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("> any("), $5, make1_str(")")); 
-				}
-		| a_expr '=' ANY '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("= any("), $5, make1_str(")")); 
-				}
-		| a_expr Op ALL '(' SubSelect ')'
-				{
-					$$ = cat3_str($1, $2, make3_str(make1_str("all ("), $5, make1_str(")"))); 
-				}
-		| a_expr '+' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("+ all("), $5, make1_str(")")); 
-				}
-		| a_expr '-' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("- all("), $5, make1_str(")")); 
-				}
-		| a_expr '*' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("* all("), $5, make1_str(")")); 
-				}
-		| a_expr '/' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("/ all("), $5, make1_str(")")); 
-				}
-		| a_expr '%' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("% all("), $5, make1_str(")")); 
-				}
-		| a_expr '^' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("^ all("), $5, make1_str(")")); 
-				}
-		| a_expr '|' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("| all("), $5, make1_str(")")); 
-				}
-		| a_expr '<' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("< all("), $5, make1_str(")")); 
-				}
-		| a_expr '>' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("> all("), $5, make1_str(")")); 
-				}
-		| a_expr '=' ALL '(' SubSelect ')'
-				{
-					$$ = make4_str($1, make1_str("=all("), $5, make1_str(")")); 
-				}
-		| a_expr AND ecpg_expr
-				{	$$ = cat3_str($1, make1_str("and"), $3); }
-		| a_expr OR ecpg_expr
-				{	$$ = cat3_str($1, make1_str("or"), $3); }
-		| NOT ecpg_expr
-				{	$$ = cat2_str(make1_str("not"), $2); }
-		| case_expr
+		| row_expr
 				{       $$ = $1; }
 		| civariableonly
 			        { 	$$ = $1; }
 		;
+*/
 
 into_list : coutputvariable | into_list ',' coutputvariable;
 
 ecpgstart: SQL_START { reset_variables();}
 
-c_args: /* empty */		{ $$ = make1_str(""); }
+c_args: /* empty */		{ $$ = EMPTY; }
 	| c_list		{ $$ = $1; }
 
 coutputvariable : cvariable indicator {
diff --git a/src/interfaces/ecpg/test/test4.pgc b/src/interfaces/ecpg/test/test4.pgc
index 191a74789ea..c61d5f0c7f9 100644
--- a/src/interfaces/ecpg/test/test4.pgc
+++ b/src/interfaces/ecpg/test/test4.pgc
@@ -6,7 +6,8 @@ int
 main ()
 {
 EXEC SQL BEGIN DECLARE SECTION;
-	int a = 1;
+	int i = 1;
+	int a[10] = {9,8,7,6,5,4,3,2,1,0};
 	double f;
 EXEC SQL END DECLARE SECTION;
 	FILE *dbgs;
@@ -16,23 +17,31 @@ EXEC SQL END DECLARE SECTION;
 
         EXEC SQL CONNECT TO mm;
 
-	EXEC SQL CREATE TABLE test (f decimal(8,2), a int);
+	EXEC SQL SET AUTOCOMMIT = ON;
 
-	EXEC SQL INSERT INTO test(f,a) VALUES(17000.00,1);
+ 	EXEC SQL BEGIN WORK;
+
+	EXEC SQL CREATE TABLE test (f decimal(8,2), i int, a int[10]);
+
+	EXEC SQL INSERT INTO test(f,i,a) VALUES(17000.00,1,'{0,1,2,3,4,5,6,7,8,9}');
+
+/*	EXEC SQL INSERT INTO test(f,i,a) VALUES(140787.0,2,:a);*/
 
 	EXEC SQL COMMIT;
 
+	EXEC SQL BEGIN WORK; 
+
 	EXEC SQL SELECT f::float
          INTO :f
          FROM test
-         WHERE a = :a;
+         WHERE i = :i;
 
 	printf("Found f::float=%f\n", f);
 
 	EXEC SQL SELECT f
          INTO :f
          FROM test
-         WHERE a = :a;
+         WHERE i = :i;
 
 	printf("Found f=%f\n", f);
 
@@ -41,4 +50,9 @@ EXEC SQL END DECLARE SECTION;
 	EXEC SQL COMMIT;
 
 	EXEC SQL DISCONNECT;
-}	
+
+	if (dbgs != NULL)
+                fclose(dbgs);
+
+	return (0);
+}
-- 
GitLab