From c6dd1e63a951ba4b529ed292f88fba28de70df78 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 11 Aug 1998 18:33:37 +0000
Subject: [PATCH] This one cleans the cursor problems ecpg had so far. It is
 now able to understand cursors with variables.

Michael
---
 src/interfaces/ecpg/ChangeLog         |   7 +
 src/interfaces/ecpg/TODO              |   4 +-
 src/interfaces/ecpg/include/ecpglib.h |   3 -
 src/interfaces/ecpg/lib/Makefile.in   |   2 +-
 src/interfaces/ecpg/lib/ecpglib.c     | 426 ++++++++++++++------------
 src/interfaces/ecpg/preproc/ecpg.c    |  19 ++
 src/interfaces/ecpg/preproc/extern.h  |  18 ++
 src/interfaces/ecpg/preproc/preproc.y |  73 ++++-
 src/interfaces/ecpg/test/Makefile     |   2 +-
 src/interfaces/ecpg/test/test2.pgc    |  10 +-
 10 files changed, 333 insertions(+), 231 deletions(-)

diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 1907471a731..6ac03ff234f 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -270,3 +270,10 @@ Mon Aug  3 17:23:18 CEST 1998
 	- Fixed cursor handling
 	- Set version to 2.3.5
 	- Set library version to 2.4
+
+Fri Aug  7 12:38:50 CEST 1998
+
+	- Fixed cursor handling once again
+	- Added support for variables in cursor
+	- Set version to 2.3.6
+	- Set library version to 2.5
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 5811cb767de..908ec619270 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -1,9 +1,7 @@
-What happens to a cursor declaration with variables?
-
 The complete structure definition has to be listed inside the declare
 section of the structure variable for ecpg to be able to understand it.
 
-Variable type bool has to be checked. I never used it so far.
+Variable type bool has to be tested. I never used it so far.
 
 The error message for "no data" in an exec sql insert select from statement
 has to be 100.
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index a81ca7e8b9c..83f2e6efb86 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -13,9 +13,6 @@ bool		ECPGdisconnect(int, const char *);
 
 void		ECPGlog(const char *format,...);
 
-bool		ECPGdeclare(int, const char *, char *);
-bool		ECPGopen(int, const char *);
-
 #ifdef LIBPQ_FE_H
 bool		ECPGsetdb(PGconn *);
 
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index 8fd6b772030..e236487d6aa 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global
 PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
 
 SO_MAJOR_VERSION=2
-SO_MINOR_VERSION=4
+SO_MINOR_VERSION=5
 
 PORTNAME=@PORTNAME@
 
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 86021d6ee46..0d3d4fa0e6a 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -33,6 +33,29 @@ static struct connection
 	struct connection *next;
 } *all_connections = NULL, *actual_connection = NULL;
 
+struct variable
+{
+	enum ECPGttype type;
+	void *value;
+	long varcharsize;
+	long arrsize;
+	long offset;
+	enum ECPGttype ind_type;
+	void *ind_value;
+	long ind_varcharsize;
+	long ind_arrsize;
+	long ind_offset;
+	struct variable *next;
+};
+
+struct statement
+{
+	int lineno;
+	char *command;
+	struct variable *inlist;
+	struct variable *outlist;
+};
+
 static int	simple_debug = 0;
 static FILE *debugstream = NULL;
 static int	committed = true;
@@ -116,27 +139,87 @@ ECPGfinish(struct connection *act)
 		ECPGlog("ECPGfinish: called an extra time.\n");
 }
 
-bool
-ECPGdo(int lineno, char *query,...)
+/* create a list of variables */
+static bool
+create_statement(int lineno, struct statement **stmt, char *query, va_list ap)
+{
+	struct variable **list = &((*stmt)->inlist);
+	enum ECPGttype	type;
+	
+	*stmt = calloc(sizeof(struct statement), 1);
+	
+	if (!*stmt)
+	{
+	       ECPGfinish(actual_connection);
+	       ECPGlog("out of memory\n");
+	       register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+	       return false;
+	}
+	
+	(*stmt)->command = query;
+	(*stmt)->lineno = lineno;
+	
+	list = &((*stmt)->inlist);
+
+	type = va_arg(ap, enum ECPGttype);
+	
+	while (type != ECPGt_EORT)
+   	{  
+   	   if (type == ECPGt_EOIT)
+   	   {
+   	   	list = &((*stmt)->outlist);
+   	   }
+   	   else
+   	   {
+		struct variable *var, *ptr;
+						
+		var = malloc(sizeof(struct variable));
+		if (!var)
+		{
+			ECPGfinish(actual_connection);
+			ECPGlog("out of memory\n");
+		        register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+			return false;
+		}
+	   	
+	   	var->type = type;
+	   	var->value = va_arg(ap, void *);
+		var->varcharsize = va_arg(ap, long);
+		var->arrsize = va_arg(ap, long);
+		var->offset = va_arg(ap, long);
+		var->ind_type = va_arg(ap, enum ECPGttype);
+		var->ind_value = va_arg(ap, void *);
+		var->ind_varcharsize = va_arg(ap, long);
+		var->ind_arrsize = va_arg(ap, long);
+		var->ind_offset = va_arg(ap, long);
+		var->next = NULL;
+		
+		for (ptr = *list; ptr && ptr->next; ptr=ptr->next);
+		
+		if (ptr == NULL)
+			*list = var;
+		else
+			ptr->next = var;
+	   }
+	   
+	   type = va_arg(ap, enum ECPGttype);
+	}
+	
+	return(true);
+}
+
+static bool
+ECPGexecute(struct statement *stmt)
 {
-	va_list		ap;
 	bool		status = false;
 	char	   *copiedquery;
 	PGresult   *results;
 	PGnotify   *notify;
-	enum ECPGttype type;
-	void	   *value = NULL, *ind_value;
-	long		varcharsize, ind_varcharsize;
-	long		arrsize, ind_arrsize;
-	long		offset, ind_offset;
-	enum ECPGttype ind_type;
+	struct variable *var;
 
 	memset((char *) &sqlca, 0, sizeof (sqlca));
-	va_start(ap, query);
 
-	copiedquery = strdup(query);
-
-	type = va_arg(ap, enum ECPGttype);
+	copiedquery = strdup(stmt->command);
 
 	/*
 	 * Now, if the type is one of the fill in types then we take the
@@ -144,7 +227,8 @@ ECPGdo(int lineno, char *query,...)
 	 * Then if there are any more fill in types we fill in at the next and
 	 * so on.
 	 */
-	while (type != ECPGt_EOIT)
+	var = stmt->inlist;
+	while (var)
 	{
 		char	   *newcopy;
 		char	   *mallocedval = NULL;
@@ -158,34 +242,24 @@ ECPGdo(int lineno, char *query,...)
 		 * think).
 		 */
 
-		value = va_arg(ap, void *);
-		varcharsize = va_arg(ap, long);
-		arrsize = va_arg(ap, long);
-		offset = va_arg(ap, long);
-		ind_type = va_arg(ap, enum ECPGttype);
-		ind_value = va_arg(ap, void *);
-		ind_varcharsize = va_arg(ap, long);
-		ind_arrsize = va_arg(ap, long);
-		ind_offset = va_arg(ap, long);
-
 		buff[0] = '\0';
 		
 		/* check for null value and set input buffer accordingly */
-		switch (ind_type)
+		switch (var->ind_type)
 		{
 			case ECPGt_short:
 			case ECPGt_unsigned_short:
-				if (*(short *) ind_value < 0)
+				if (*(short *) var->ind_value < 0)
 					strcpy(buff, "null");
 				break;
 			case ECPGt_int:
 			case ECPGt_unsigned_int:
-				if (*(int *) ind_value < 0)
+				if (*(int *) var->ind_value < 0)
 					strcpy(buff, "null");
 				break;
 			case ECPGt_long:
 			case ECPGt_unsigned_long:
-				if (*(long *) ind_value < 0L)
+				if (*(long *) var->ind_value < 0L)
 					strcpy(buff, "null");
 				break;
 			default:
@@ -194,42 +268,42 @@ ECPGdo(int lineno, char *query,...)
 		
 		if (*buff == '\0')
 		{
-		   switch (type)
+		   switch (var->type)
 		   {
 			case ECPGt_short:
 			case ECPGt_int:
-				sprintf(buff, "%d", *(int *) value);
+				sprintf(buff, "%d", *(int *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_unsigned_short:
 			case ECPGt_unsigned_int:
-				sprintf(buff, "%d", *(unsigned int *) value);
+				sprintf(buff, "%d", *(unsigned int *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_long:
-				sprintf(buff, "%ld", *(long *) value);
+				sprintf(buff, "%ld", *(long *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_unsigned_long:
-				sprintf(buff, "%ld", *(unsigned long *) value);
+				sprintf(buff, "%ld", *(unsigned long *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_float:
-				sprintf(buff, "%.14g", *(float *) value);
+				sprintf(buff, "%.14g", *(float *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_double:
-				sprintf(buff, "%.14g", *(double *) value);
+				sprintf(buff, "%.14g", *(double *) var->value);
 				tobeinserted = buff;
 				break;
 
 			case ECPGt_bool:
-				sprintf(buff, "'%c'", (*(char *) value ? 't' : 'f'));
+				sprintf(buff, "'%c'", (*(char *) var->value ? 't' : 'f'));
 				tobeinserted = buff;
 				break;
 
@@ -237,7 +311,7 @@ ECPGdo(int lineno, char *query,...)
 			case ECPGt_unsigned_char:
 				{
 					/* set slen to string length if type is char * */
-					int			slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize;
+					int			slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
 					char * tmp;
 
 					newcopy = (char *) malloc(slen + 1);
@@ -245,11 +319,11 @@ ECPGdo(int lineno, char *query,...)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 						
-					strncpy(newcopy, (char *) value, slen);
+					strncpy(newcopy, (char *) var->value, slen);
 					newcopy[slen] = '\0';
 
 					mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
@@ -257,7 +331,7 @@ ECPGdo(int lineno, char *query,...)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 						
@@ -267,7 +341,7 @@ ECPGdo(int lineno, char *query,...)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 						
@@ -282,28 +356,28 @@ ECPGdo(int lineno, char *query,...)
 
 			case ECPGt_varchar:
 				{
-					struct ECPGgeneric_varchar *var =
-					(struct ECPGgeneric_varchar *) value;
+					struct ECPGgeneric_varchar *variable =
+					(struct ECPGgeneric_varchar *) (var->value);
 					char *tmp;
 
-					newcopy = (char *) malloc(var->len + 1);
+					newcopy = (char *) malloc(variable->len + 1);
 					if (!newcopy)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 						
-					strncpy(newcopy, var->arr, var->len);
-					newcopy[var->len] = '\0';
+					strncpy(newcopy, variable->arr, variable->len);
+					newcopy[variable->len] = '\0';
 
 					mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
 					if (!mallocedval)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 					
@@ -313,7 +387,7 @@ ECPGdo(int lineno, char *query,...)
 					{
 						ECPGfinish(actual_connection);
 						ECPGlog("out of memory\n");
-				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+				                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 						return false;
 					}
 					                                                
@@ -329,7 +403,7 @@ ECPGdo(int lineno, char *query,...)
 			default:
 				/* Not implemented yet */
 				register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
-							   ECPGtype_name(type), lineno);
+							   ECPGtype_name(var->type), stmt->lineno);
 				return false;
 				break;
 		   }
@@ -348,7 +422,7 @@ ECPGdo(int lineno, char *query,...)
 		{
 			ECPGfinish(actual_connection);
 			ECPGlog("out of memory\n");
-	                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+	                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
 			return false;
 		}
 		 	
@@ -360,7 +434,7 @@ ECPGdo(int lineno, char *query,...)
 			 * We have an argument but we dont have the matched up string
 			 * in the string
 			 */
-			register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno);
+			register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", stmt->lineno);
 			return false;
 		}
 		else
@@ -379,7 +453,7 @@ ECPGdo(int lineno, char *query,...)
 
 		/*
 		 * Now everything is safely copied to the newcopy. Lets free the
-		 * oldcopy and let the copiedquery get the value from the newcopy.
+		 * oldcopy and let the copiedquery get the var->value from the newcopy.
 		 */
 		if (mallocedval != NULL)
 		{
@@ -390,13 +464,13 @@ ECPGdo(int lineno, char *query,...)
 		free(copiedquery);
 		copiedquery = newcopy;
 
-		type = va_arg(ap, enum ECPGttype);
+		var = var->next;
 	}
 
 	/* Check if there are unmatched things left. */
 	if (strstr(copiedquery, ";;") != NULL)
 	{
-		register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno);
+		register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
 		return false;
 	}
 
@@ -406,27 +480,28 @@ ECPGdo(int lineno, char *query,...)
 	{
 		if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
 		{
-			register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno);
+			register_error(ECPG_TRANS, "Error starting transaction line %d.", stmt->lineno);
 			return false;
 		}
 		PQclear(results);
 		committed = 0;
 	}
 
-	ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery);
+	ECPGlog("ECPGexecute line %d: QUERY: %s\n", stmt->lineno, copiedquery);
 	results = PQexec(actual_connection->connection, copiedquery);
 	free(copiedquery);
 
 	if (results == NULL)
 	{
-		ECPGlog("ECPGdo line %d: error: %s", lineno,
+		ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
 				PQerrorMessage(actual_connection->connection));
 		register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
-					   PQerrorMessage(actual_connection->connection), lineno);
+					   PQerrorMessage(actual_connection->connection), stmt->lineno);
 	}
 	else
 	{
 		sqlca.sqlerrd[2] = 0;
+		var = stmt->outlist;
 		switch (PQresultStatus(results))
 		{
 				int			nfields, ntuples, act_tuple, act_field;
@@ -445,9 +520,9 @@ ECPGdo(int lineno, char *query,...)
 				
 				if (ntuples < 1)
 				{
-					ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n",
-							lineno, ntuples);
-					register_error(ECPG_NOT_FOUND, "Data not found line %d.", lineno);
+					ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
+							stmt->lineno, ntuples);
+					register_error(ECPG_NOT_FOUND, "Data not found line %d.", stmt->lineno);
 					status = false;
 					break;
 				}
@@ -457,23 +532,19 @@ ECPGdo(int lineno, char *query,...)
                                      char	   *pval;
                                      char	   *scan_length;
                                              
-                                     type = va_arg(ap, enum ECPGttype);
-                                     value = va_arg(ap, void *);
-                                     varcharsize = va_arg(ap, long);
-                                     arrsize = va_arg(ap, long);
-                                     offset = va_arg(ap, long);
-                                     ind_type = va_arg(ap, enum ECPGttype);
-                                     ind_value = va_arg(ap, void *);
-                                     ind_varcharsize = va_arg(ap, long);
-                                     ind_arrsize = va_arg(ap, long);
-                                     ind_offset = va_arg(ap, long);
-
+                                     if (var == NULL)
+                                     {
+                                             ECPGlog("ECPGexecute line %d: Too few arguments.\n", stmt->lineno);
+                                             register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
+                                             return(false);
+                                     }
+                                     
                                      /* if we don't have enough space, we cannot read all tuples */
-                                     if ((arrsize > 0 && ntuples > arrsize) || (ind_arrsize > 0 && ntuples > ind_arrsize))
+                                     if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
                                      {
-                                             ECPGlog("ECPGdo line %d: Incorrect number of matches: %d don't fit into array of %d\n",
-                                                             lineno, ntuples, arrsize);
-                                             register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", lineno);
+                                             ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
+                                                             stmt->lineno, ntuples, var->arrsize);
+                                             register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", stmt->lineno);
                                              status = false;
                                              break;
                                      }
@@ -481,31 +552,31 @@ ECPGdo(int lineno, char *query,...)
                                      {
                                          pval = PQgetvalue(results, act_tuple, act_field);
 
-                                         ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
+                                         ECPGlog("ECPGexecute line %d: RESULT: %s\n", stmt->lineno, pval ? pval : "");
 
-                                         /* Now the pval is a pointer to the value. */
-                                         /* We will have to decode the value */
+                                         /* Now the pval is a pointer to the var->value. */
+                                         /* We will have to decode the var->value */
                                      
-                                         /* check for null value and set indicator accordingly */
-                                         switch (ind_type)
+                                         /* check for null var->value and set indicator accordingly */
+                                         switch (var->ind_type)
                                          {
                                                  case ECPGt_short:
                                                  case ECPGt_unsigned_short:
-                                                         ((short *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
+                                                         ((short *) var->ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
                                                          break;
                                                  case ECPGt_int:
                                                  case ECPGt_unsigned_int:
-                                                         ((int *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
+                                                         ((int *) var->ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
                                                          break;
                                                  case ECPGt_long:
                                                  case ECPGt_unsigned_long:
-                                                         ((long *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
+                                                         ((long *) var->ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
                                                          break;
                                                  default:
                                                          break;
                                          }
                                                                                  
-                                         switch (type)
+                                         switch (var->type)
                                          {
                                                          long		res;
                                                          unsigned long ures;
@@ -520,7 +591,7 @@ ECPGdo(int lineno, char *query,...)
                                                                  if (*scan_length != '\0')		/* Garbage left */
                                                                  {
                                                                          register_error(ECPG_INT_FORMAT, "Not correctly formatted int type: %s line %d.",
-                                                                                                    pval, lineno);
+                                                                                                    pval, stmt->lineno);
                                                                          status = false;
                                                                          res = 0L;
                                                                  }
@@ -529,16 +600,16 @@ ECPGdo(int lineno, char *query,...)
                                                                  res = 0L;
     
                                                          /* Again?! Yes */
-                                                         switch (type)
+                                                         switch (var->type)
                                                          {
                                                                  case ECPGt_short:
-                                                                         ((short *) value)[act_tuple] = (short) res;
+                                                                         ((short *) var->value)[act_tuple] = (short) res;
                                                                          break;
                                                                  case ECPGt_int:
-                                                                         ((int *) value)[act_tuple] = (int) res;
+                                                                         ((int *) var->value)[act_tuple] = (int) res;
                                                                          break;
                                                                  case ECPGt_long:
-                                                                         ((long *) value)[act_tuple] = res;
+                                                                         ((long *) var->value)[act_tuple] = res;
                                                                          break;
                                                                  default:
                                                                          /* Cannot happen */
@@ -555,7 +626,7 @@ ECPGdo(int lineno, char *query,...)
                                                                  if (*scan_length != '\0')		/* Garbage left */
                                                                  {
                                                                          register_error(ECPG_UINT_FORMAT, "Not correctly formatted unsigned type: %s line %d.",
-                                                                                                    pval, lineno);
+                                                                                                    pval, stmt->lineno);
                                                                          status = false;
                                                                          ures = 0L;
                                                                  }
@@ -564,16 +635,16 @@ ECPGdo(int lineno, char *query,...)
                                                                  ures = 0L;
     
                                                          /* Again?! Yes */
-                                                         switch (type)
+                                                         switch (var->type)
                                                          {
                                                                  case ECPGt_unsigned_short:
-                                                                         ((unsigned short *) value)[act_tuple] = (unsigned short) ures;
+                                                                         ((unsigned short *) var->value)[act_tuple] = (unsigned short) ures;
                                                                          break;
                                                                  case ECPGt_unsigned_int:
-                                                                         ((unsigned int *) value)[act_tuple] = (unsigned int) ures;
+                                                                         ((unsigned int *) var->value)[act_tuple] = (unsigned int) ures;
                                                                          break;
                                                                  case ECPGt_unsigned_long:
-                                                                         ((unsigned long *) value)[act_tuple] = ures;
+                                                                         ((unsigned long *) var->value)[act_tuple] = ures;
                                                                          break;
                                                                  default:
                                                                          /* Cannot happen */
@@ -590,7 +661,7 @@ ECPGdo(int lineno, char *query,...)
                                                                  if (*scan_length != '\0')		/* Garbage left */
                                                                  {
                                                                          register_error(ECPG_FLOAT_FORMAT, "Not correctly formatted floating point type: %s line %d.",
-                                                                                                    pval, lineno);
+                                                                                                    pval, stmt->lineno);
                                                                          status = false;
                                                                          dres = 0.0;
                                                                  }
@@ -599,13 +670,13 @@ ECPGdo(int lineno, char *query,...)
                                                                  dres = 0.0;
     
                                                          /* Again?! Yes */
-                                                         switch (type)
+                                                         switch (var->type)
                                                          {
                                                                  case ECPGt_float:
-                                                                         ((float *) value)[act_tuple] = dres;
+                                                                         ((float *) var->value)[act_tuple] = dres;
                                                                          break;
                                                                  case ECPGt_double:
-                                                                         ((double *) value)[act_tuple] = dres;
+                                                                         ((double *) var->value)[act_tuple] = dres;
                                                                          break;
                                                                  default:
                                                                          /* Cannot happen */
@@ -618,50 +689,50 @@ ECPGdo(int lineno, char *query,...)
                                                          {
                                                                  if (pval[0] == 'f' && pval[1] == '\0')
                                                                  {
-                                                                         ((char *) value)[act_tuple] = false;
+                                                                         ((char *) var->value)[act_tuple] = false;
                                                                          break;
                                                                  }
                                                                  else if (pval[0] == 't' && pval[1] == '\0')
                                                                  {
-                                                                         ((char *) value)[act_tuple] = true;
+                                                                         ((char *) var->value)[act_tuple] = true;
                                                                          break;
                                                                  }
                                                          }
     
                                                          register_error(ECPG_CONVERT_BOOL, "Unable to convert %s to bool on line %d.",
                                                                                     (pval ? pval : "NULL"),
-                                                                                    lineno);
+                                                                                    stmt->lineno);
                                                          status = false;
                                                          break;
     
                                                  case ECPGt_char:
                                                  case ECPGt_unsigned_char:
                                                          {
-                                                                 if (varcharsize == 0)
+                                                                 if (var->varcharsize == 0)
                                                                  {
                                                                          /* char* */
-                                                                         strncpy(((char **) value)[act_tuple], pval, strlen(pval));
-                                                                         (((char **) value)[act_tuple])[strlen(pval)] = '\0';
+                                                                         strncpy(((char **) var->value)[act_tuple], pval, strlen(pval));
+                                                                         (((char **) var->value)[act_tuple])[strlen(pval)] = '\0';
                                                                  }
                                                                  else
                                                                  {
-                                                                         strncpy((char *) (value + offset * act_tuple), pval, varcharsize);
-                                                                         if (varcharsize < strlen(pval))
+                                                                         strncpy((char *) (var->value + var->offset * act_tuple), pval, var->varcharsize);
+                                                                         if (var->varcharsize < strlen(pval))
                                                                          {
                                                                                  /* truncation */
-                                                                                 switch (ind_type)
+                                                                                 switch (var->ind_type)
                                                                                  {
                                                                                          case ECPGt_short:
                                                                                          case ECPGt_unsigned_short:
-                                                                                                 ((short *) ind_value)[act_tuple] = varcharsize;
+                                                                                                 ((short *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                                  break;
                                                                                          case ECPGt_int:
                                                                                          case ECPGt_unsigned_int:
-                                                                                                 ((int *) ind_value)[act_tuple] = varcharsize;
+                                                                                                 ((int *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                                  break;
                                                                                          case ECPGt_long:
                                                                                          case ECPGt_unsigned_long:
-                                                                                                 ((long *) ind_value)[act_tuple] = varcharsize;
+                                                                                                 ((long *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                                  break;
                                                                                          default:
                                                                                                  break;
@@ -674,62 +745,55 @@ ECPGdo(int lineno, char *query,...)
     
                                                  case ECPGt_varchar:
                                                          {
-                                                                 struct ECPGgeneric_varchar *var =
-								 (struct ECPGgeneric_varchar *) (value + offset * act_tuple);
+                                                                 struct ECPGgeneric_varchar *variable =
+								 (struct ECPGgeneric_varchar *) (var->value + var->offset * act_tuple);
     
-								 if (varcharsize == 0)
-								   strncpy(var->arr, pval, strlen(pval));
+								 if (var->varcharsize == 0)
+								   strncpy(variable->arr, pval, strlen(pval));
 								 else
-								   strncpy(var->arr, pval, varcharsize);
+								   strncpy(variable->arr, pval, var->varcharsize);
 
-                                                                 var->len = strlen(pval);
-                                                                 if (varcharsize > 0 && var->len > varcharsize)
+                                                                 variable->len = strlen(pval);
+                                                                 if (var->varcharsize > 0 && variable->len > var->varcharsize)
                                                                  {
                                                                          /* truncation */
-                                                                         switch (ind_type)
+                                                                         switch (var->ind_type)
                                                                          {
                                                                                  case ECPGt_short:
                                                                                  case ECPGt_unsigned_short:
-                                                                                         ((short *) ind_value)[act_tuple] = varcharsize;
+                                                                                         ((short *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                          break;
                                                                                  case ECPGt_int:
                                                                                  case ECPGt_unsigned_int:
-                                                                                         ((int *) ind_value)[act_tuple] = varcharsize;
+                                                                                         ((int *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                          break;
                                                                                  case ECPGt_long:
                                                                                  case ECPGt_unsigned_long:
-                                                                                         ((long *) ind_value)[act_tuple] = varcharsize;
+                                                                                         ((long *) var->ind_value)[act_tuple] = var->varcharsize;
                                                                                          break;
                                                                                  default:
                                                                                          break;
                                                                          }
                                                                          sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
     
-                                                                         var->len = varcharsize;
+                                                                         variable->len = var->varcharsize;
                                                                  }
                                                          }
                                                          break;
     
-                                                 case ECPGt_EORT:
-                                                         ECPGlog("ECPGdo line %d: Too few arguments.\n", lineno);
-                                                         register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno);
-                                                         status = false;
-                                                         break;
-    
                                                  default:
                                                          register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
-                                                                                    ECPGtype_name(type), lineno);
+                                                                                    ECPGtype_name(var->type), stmt->lineno);
                                                          status = false;
                                                          break;
                                          }
                                      }
+				     var = var->next;
 				}
 
-				type = va_arg(ap, enum ECPGttype);
-
-				if (status && type != ECPGt_EORT)
+				if (status && var != NULL)
 				{
-					register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno);
+					register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", stmt->lineno);
 					status = false;
 				}
 
@@ -737,35 +801,34 @@ ECPGdo(int lineno, char *query,...)
 				break;
 			case PGRES_EMPTY_QUERY:
 				/* do nothing */
-				register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
+				register_error(ECPG_EMPTY, "Empty query line %d.", stmt->lineno);
 				break;
 			case PGRES_COMMAND_OK:
 				status = true;
 				sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
-				ECPGlog("TEST: %s\n", PQcmdTuples(results));
-				ECPGlog("ECPGdo line %d Ok: %s\n", lineno, PQcmdStatus(results));
+				ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, PQcmdStatus(results));
 				break;
 			case PGRES_NONFATAL_ERROR:
 			case PGRES_FATAL_ERROR:
 			case PGRES_BAD_RESPONSE:
-				ECPGlog("ECPGdo line %d: Error: %s",
-						lineno, PQerrorMessage(actual_connection->connection));
+				ECPGlog("ECPGexecute line %d: Error: %s",
+						stmt->lineno, PQerrorMessage(actual_connection->connection));
 				register_error(ECPG_PGSQL, "Error: %s line %d.",
-							   PQerrorMessage(actual_connection->connection), lineno);
+							   PQerrorMessage(actual_connection->connection), stmt->lineno);
 				status = false;
 				break;
 			case PGRES_COPY_OUT:
-				ECPGlog("ECPGdo line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
+				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
 				PQendcopy(results->conn);
 				break;
 			case PGRES_COPY_IN:
-				ECPGlog("ECPGdo line %d: Got PGRES_COPY_IN ... tossing.\n", lineno);
+				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
 				PQendcopy(results->conn);
 				break;
 			default:
-				ECPGlog("ECPGdo line %d: Got something else, postgres error.\n",
-						lineno);
-				register_error(ECPG_PGSQL, "Postgres error line %d.", lineno);
+				ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
+						stmt->lineno);
+				register_error(ECPG_PGSQL, "Postgres error line %d.", stmt->lineno);
 				status = false;
 				break;
 		}
@@ -775,8 +838,8 @@ ECPGdo(int lineno, char *query,...)
 	notify = PQnotifies(actual_connection->connection);
 	if (notify)
 	{
-		ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
-				lineno, notify->relname, notify->be_pid);
+		ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+				stmt->lineno, notify->relname, notify->be_pid);
 		free(notify);
 	}
 
@@ -784,6 +847,20 @@ ECPGdo(int lineno, char *query,...)
 	return status;
 }
 
+bool
+ECPGdo(int lineno, char *query, ...)
+{
+	va_list			args;
+	struct statement	*stmt;
+	                                                                                                                                                     
+	va_start(args, query);
+	if (create_statement(lineno, &stmt, query, args) == false)
+		return(false);
+	va_end(args);
+	
+	return(ECPGexecute(stmt));
+}
+
 
 bool
 ECPGtrans(int lineno, const char * transaction)
@@ -940,56 +1017,3 @@ sqlprint(void)
 	sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
 	printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
 }
-
-/* keep a list of cursors */
-struct cursor *cur = NULL;
-
-bool ECPGdeclare(int lineno, const char *name, char *command)
-{
-	struct cursor *ptr;
-	
-	for (ptr = cur; ptr != NULL; ptr = ptr->next)
-	{
-		if (strcmp(name, ptr->name) == 0)
-		{
-		        /* re-definition */
-           		free(ptr->command);
-                        ptr->command = command;
-                        break;
-                }
-        }
-                        
-        if (ptr == NULL)
-        {
-        	struct cursor *this = (struct cursor *) malloc(sizeof(struct cursor));
-
-		if (!this)
-		{
-		        ECPGlog("out of memory\n");
-		        register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
-                	return false;
-                }
-        	/* initial definition */
-	        this->next = cur;
-	        this->name = name;
-	        this->command = command;
-        	cur = this;
-	}
-	
-	return(true);
-}
-
-bool ECPGopen(int lineno, const char *name)
-{
-	struct cursor *ptr;
-
-        for (ptr = cur; ptr != NULL; ptr=ptr->next)
-        {
-               if (strcmp(ptr->name, name) == 0)
-                    return(ECPGdo(lineno, ptr->command, ECPGt_EOIT, ECPGt_EORT));
-        }
-
-	ECPGlog("trying to open undeclared cursor %s\n", name);
-	register_error(ECPG_UNDECLARED_CURSOR, "trying to open undeclared cursor %s in line %d", name, lineno);        
-        return(false);
-}
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index f12b799850c..1fe777845b7 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -23,6 +23,7 @@ extern char *optarg;
 
 struct _include_path *include_paths;
 static int no_auto_trans = 0;
+struct cursor *cur = NULL;
 
 static void
 usage(char *progname)
@@ -138,6 +139,24 @@ main(int argc, char *const argv[])
 			{
 				struct cursor *ptr;
 				
+				/* remove old cursor definitions if any are still there */
+				for (ptr = cur; ptr != NULL; ptr=ptr->next)
+				{
+					struct arguments *l1, *l2;
+					
+					free(ptr->command);
+					free(ptr->name);
+					for (l1 = argsinsert; l1; l1 = l2)
+					{
+						l2 = l1->next;
+						free(l1);
+					}
+					for (l1 = argsresult; l1; l1 = l2)
+					{
+						l2 = l1->next;
+						free(l1);
+					}
+				}
 				/* initialize lex */
 				lex_init();
 				
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index d2eec0c0978..43a15394af3 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -16,6 +16,15 @@ struct _include_path {  char * path;
 
 extern struct _include_path *include_paths;
 
+struct cursor { char *name;
+                char *command;
+                struct arguments * argsinsert;
+                struct arguments * argsresult;
+                struct cursor *next;
+              };
+                                           
+extern struct cursor *cur;
+
 /* This is a linked list of the variable names and types. */
 struct variable
 {
@@ -28,6 +37,15 @@ struct variable
 extern struct ECPGtype ecpg_no_indicator;
 extern struct variable no_indicator;
 
+struct arguments {
+    struct variable * variable;
+    struct variable * indicator;
+    struct arguments * next;
+};
+
+extern struct arguments * argsinsert;
+extern struct arguments * argsresult;
+
 /* functions */
 
 extern void lex_init(void);
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 290440a39f5..4d6960e406b 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -245,14 +245,9 @@ remove_variables(int brace_level)
  * These are of two kinds: input and output.
  * I will make two lists for them.
  */
-struct arguments {
-    struct variable * variable;
-    struct variable * indicator;
-    struct arguments * next;
-};
 
-static struct arguments * argsinsert = NULL;
-static struct arguments * argsresult = NULL;
+struct arguments * argsinsert = NULL;
+struct arguments * argsresult = NULL;
 
 static void
 reset_variables(void)
@@ -279,7 +274,7 @@ add_variable(struct arguments ** list, struct variable * var, struct variable *
    deletes the list as we go on.
  */
 static void
-dump_variables(struct arguments * list)
+dump_variables(struct arguments * list, int mode)
 {
     if (list == NULL)
     {
@@ -290,7 +285,7 @@ dump_variables(struct arguments * list)
        end of the list:
      */
 
-    dump_variables(list->next);
+    dump_variables(list->next, mode);
 
     /* Then the current element and its indicator */
     ECPGdump_a_type(yyout, list->variable->name, list->variable->type,
@@ -298,7 +293,8 @@ dump_variables(struct arguments * list)
 	(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL);
 
     /* Then release the list element. */
-    free(list);
+    if (mode != 0)
+    	free(list);
 }
 
 static void
@@ -494,9 +490,9 @@ output_statement(char * stmt, int mode)
 	fputs("\", ", yyout);
 
 	/* dump variables to C file*/
-	dump_variables(argsinsert);
+	dump_variables(argsinsert, 1);
 	fputs("ECPGt_EOIT, ", yyout);
-	dump_variables(argsresult);
+	dump_variables(argsresult, 1);
 	fputs("ECPGt_EORT);", yyout);
 	whenever_action(mode);
 	free(stmt);
@@ -737,10 +733,9 @@ stmt:  AddAttrStmt			{ output_statement($1, 0); }
 		| RenameStmt		{ output_statement($1, 0); }
 		| RevokeStmt		{ output_statement($1, 0); }
                 | OptimizableStmt	{
-						if (strncmp($1, "ECPGdeclare" , sizeof("ECPGdeclare")-1) == 0)
+						if (strncmp($1, "/* " , sizeof("/* ")-1) == 0)
 						{
 							fputs($1, yyout);
-							whenever_action(0);
 							free($1);
 						}
 						else
@@ -775,7 +770,27 @@ stmt:  AddAttrStmt			{ output_statement($1, 0); }
 						whenever_action(0);
 						free($1);
 					}
-		| ECPGOpen		{	fprintf(yyout, "ECPGopen(__LINE__, %s);", $1);
+		| ECPGOpen		{	
+						struct cursor *ptr;
+						 
+						for (ptr = cur; ptr != NULL; ptr=ptr->next)
+						{
+					               if (strcmp(ptr->name, $1) == 0)
+						       		break;
+						}
+						
+						if (ptr == NULL)
+						{
+							sprintf(errortext, "trying to open undeclared cursor %s\n", $1);
+							yyerror(errortext);
+						}
+                  
+						fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
+						/* dump variables to C file*/
+						dump_variables(ptr->argsinsert, 0);
+						fputs("ECPGt_EOIT, ", yyout);
+						dump_variables(ptr->argsresult, 0);
+						fputs("ECPGt_EORT);", yyout);
 						whenever_action(0);
 						free($1);
 					}
@@ -2359,7 +2374,31 @@ CursorStmt:  DECLARE name opt_binary CURSOR FOR
 			 group_clause having_clause
 			 union_clause sort_clause
 				{
-					$$ = make5_str(make1_str("ECPGdeclare(__LINE__, \""), $2, make1_str("\", \""), cat4_str(cat5_str(cat5_str(make1_str("declare"), strdup($2), $3, make1_str("cursor for select"), $7), $8, $9, $10, $11), $12, $13, $14), make1_str("\");"));
+					struct cursor *ptr, *this;
+	
+					for (ptr = cur; ptr != NULL; ptr = ptr->next)
+					{
+						if (strcmp($2, ptr->name) == 0)
+						{
+						        /* re-definition is a bug*/
+							sprintf(errortext, "cursor %s already defined", $2);
+							yyerror(errortext);
+				                }
+        				}
+                        
+        				this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+			        	/* initial definition */
+				        this->next = cur;
+				        this->name = $2;
+				        this->command = cat4_str(cat5_str(cat5_str(make1_str("declare"), strdup($2), $3, make1_str("cursor for select"), $7), $8, $9, $10, $11), $12, $13, $14);
+					this->argsinsert = argsinsert;
+					this->argsresult = argsresult;
+					argsinsert = argsresult = NULL;
+											
+			        	cur = this;
+					
+					$$ = cat3_str(make1_str("/*"), strdup(this->command), make1_str("*/"));
 				}
 		;
 
@@ -4221,7 +4260,7 @@ execstring: cvariable |
  * open is an open cursor, at the moment this has to be removed
  */
 ECPGOpen: SQL_OPEN name open_opts {
-		$$ = make3_str(make1_str("\""), $2, make1_str("\""));
+		$$ = $2;
 };
 
 open_opts: /* empty */		{ $$ = make1_str(""); }
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 8a7f1f69df4..4e19502fca9 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -1,6 +1,6 @@
 all: test1 test2 perftest
 
-LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
+LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt
 
 test1: test1.c
 test1.c: test1.pgc
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index 1506dd7bfa9..89d938730b8 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -19,6 +19,10 @@ exec sql begin declare section;
 	long ind_married;
 	char married[9];
 exec sql end declare section;
+
+exec sql declare cur cursor for
+       select name, born, age, married from meskes;
+
 	char msg[128], command[128];
 	FILE *dbgs;
 
@@ -26,7 +30,7 @@ exec sql end declare section;
                 ECPGdebug(1, dbgs);
 
 	strcpy(msg, "connect");
-	exec sql connect to tcp:postgresql://localhost:5432/mm;
+	exec sql connect to tcp:postgresql://localhost:5432/mm; 
 
 	strcpy(msg, "create");
 	exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
@@ -41,10 +45,6 @@ exec sql end declare section;
 	strcpy(msg, "commit");
 	exec sql commit;
 
-	strcpy(msg, "declare");
-	exec sql declare cur cursor for
-                select name, born, age, married from meskes;
-
 	strcpy(msg, "open");
 	exec sql open cur;
 
-- 
GitLab