diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 52a01f8e9bae80711e90514aafe9cd9d9f1eb53b..196f7c99e5e7c8e87db5b12349c494e892666eb1 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -400,3 +400,60 @@ Tue Feb  2 07:40:52 CET 1999
 	- Brought preproc.y in sync again with gram.y.
 	- Set ecpg version to 2.4.9
 
+Wed Feb  3 18:28:46 CET 1999
+
+	- Started working on PREPARE statement.
+	- Fixed typo in preproc that cause CREATE statement to not work
+	  anymore.
+
+Thu Feb  4 19:43:39 CET 1999
+
+	- Some parts of the PREPARE statement work now.
+	- Added EXECUTE command
+	- Added DEALLOCATE PREPARE command
+
+Fri Feb  5 18:25:07 CET 1999
+
+	- PREPARE seems to be working okay now.
+	- Fixed some minor bugs.
+	- Renamed y.tab.* to preproc.*
+
+Mon Feb  8 07:57:29 CET 1999
+
+	- Synced preproc.y with gram.y again.
+	- Allow ':<name>' as positional variable in prepare statement also.
+	  You can still specify ';;' instead of course.
+	- Added TYPE statement.
+	- Set library version to 2.7.0
+
+Tue Feb  9 07:07:11 CET 1999
+
+	- Synced preproc.y with gram.y.
+
+Tue Feb  9 20:21:44 CET 1999
+
+	- Added FREE statement.
+
+Wed Feb 10 07:51:09 CET 1999
+
+	- Synced keyword.c.
+
+Sat Feb 13 10:44:43 CET 1999
+
+	- Added DECLARE STATEMENT for compatibility with Oracle. De facto
+	  this statement does nothing.
+	- Added VAR statement.
+
+Son Feb 14 11:36:04 CET 1999
+
+	- Added type 'enum' to TYPE and VAR statement. 
+	- Allow ecpg keywords as datatypes.
+
+Thu Feb 18 08:35:35 CET 1999
+
+	- Make sure indicator for array is array too.
+
+Fri Feb 19 18:38:45 CET 1999
+
+	- Finished type aliasing for structures.
+	- Set ecpg version to 2.5.0
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index cac4f67056adfcdcfbec224439953350e4bc27ba..82b8a5d8b85b070dbe2eb82a6de7d08fc1b04ce7 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -11,10 +11,10 @@ DESCRIPTOR statement will be ignored.
 
 it would be nice to be able to use :var[:index] as cvariable
 
+'at DB connection' is missing for several commands (is this standard?)
+
+support for unions
+
 Missing statements:
- - exec sql type
- - exec sql prepare
  - exec sql allocate
- - exqc sql free
  - SQLSTATE
- - exec sql whenever sqlwarning
diff --git a/src/interfaces/ecpg/include/ecpgerrno.h b/src/interfaces/ecpg/include/ecpgerrno.h
index 56cf8d5f570f06c72d0487aeab07f7c525268bca..5fa7e704715773cc3dd3759eaec3a465c55f5103 100644
--- a/src/interfaces/ecpg/include/ecpgerrno.h
+++ b/src/interfaces/ecpg/include/ecpgerrno.h
@@ -28,6 +28,8 @@
 #define ECPG_NO_CONN		-220
 #define ECPG_NOT_CONN		-221
 
+#define ECPG_INVALID_STMT	-230
+
 /* finally the backend error messages, they start at 400 */
 #define ECPG_PGSQL		-400
 #define ECPG_TRANS		-401
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index 730753efcdae65be721b920e2929cf8ff6bc41d7..4e1d6f9cde4b44d7c14b649f6aa5949a0fd3f7d6 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -11,7 +11,10 @@ extern		"C"
 	bool		ECPGdo(int, char *,...);
 	bool		ECPGtrans(int, const char *);
 	bool		ECPGdisconnect(int, const char *);
-
+	bool		ECPGprepare(int, char *, char *);
+	bool		ECPGdeallocate(int, char *);
+	char		*ECPGprepared_statement(char *);
+		
 	void		ECPGlog(const char *format,...);
 
 #ifdef LIBPQ_FE_H
diff --git a/src/interfaces/ecpg/include/ecpgtype.h b/src/interfaces/ecpg/include/ecpgtype.h
index 945ce0b98d0c5a1a2df618bea296d4d326f7cdbe..e92220481da0df7176ca975970582e73992b7254 100644
--- a/src/interfaces/ecpg/include/ecpgtype.h
+++ b/src/interfaces/ecpg/include/ecpgtype.h
@@ -45,7 +45,8 @@ extern		"C"
 		ECPGt_struct,
 		ECPGt_EOIT,				/* End of insert types. */
 		ECPGt_EORT,				/* End of result types. */
-		ECPGt_NO_INDICATOR		/* no indicator */
+		ECPGt_NO_INDICATOR,		/* no indicator */
+		ECPGt_char_variable
 	};
 
 #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index 9173f36c4eef70e43f1d1b0d33a581a955bf3033..195ded19680d0c6b13ddea6c442cab17564835e9 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.40 1999/01/21 20:01:32 scrappy Exp $
+#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.41 1999/02/20 07:00:53 scrappy Exp $
 #
 #-------------------------------------------------------------------------
 
 NAME= ecpg
 SO_MAJOR_VERSION= 2
-SO_MINOR_VERSION= 6.3
+SO_MINOR_VERSION= 7.0
 
 SRCDIR= @top_srcdir@
 include $(SRCDIR)/Makefile.global
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 62769941a7ce9c9b20ec7c17451888c6b1620fcc..01fe37298bbb586916cc3824498b4e9dd24f597e 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -75,12 +75,19 @@ struct variable
 
 struct statement
 {
-	int			lineno;
+	int	    lineno;
 	char	   *command;
 	struct variable *inlist;
 	struct variable *outlist;
 };
 
+struct prepared_statement
+{
+	char 				*name;
+	struct statement 		*stmt;
+	struct prepared_statement	*next;
+}	*prep_stmts = NULL;
+
 static int	simple_debug = 0;
 static FILE *debugstream = NULL;
 static int	committed = true;
@@ -196,6 +203,41 @@ quote_postgres(char *arg, int lineno)
 	return res;
 }
 
+/* This function returns a newly malloced string that has the \
+   in the strings inside the argument quoted with another \.
+ */
+static
+char *
+quote_strings(char *arg, int lineno)
+{
+	char	   *res = (char *) ecpg_alloc(2 * strlen(arg) + 1, lineno);
+	int			i,
+				ri;
+	bool 			string = false;
+
+	if (!res)
+		return (res);
+
+	for (i = 0, ri = 0; arg[i]; i++, ri++)
+	{
+		switch (arg[i])
+		{
+			case '\'':
+				string = string ? false : true;
+				break;
+			case '\\':
+				res[ri++] = '\\';
+			default:
+				;
+		}
+
+		res[ri] = arg[i];
+	}
+	res[ri] = '\0';
+
+	return res;
+}
+
 /* create a list of variables */
 static bool
 create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
@@ -236,6 +278,14 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
 			var->ind_arrsize = va_arg(ap, long);
 			var->ind_offset = va_arg(ap, long);
 			var->next = NULL;
+			
+			if (var->value == NULL)
+			{
+				ECPGlog("create_statement: invalid statement name\n");
+				register_error(ECPG_INVALID_STMT, "Invalid statement name in line %d", lineno);
+				free(var);
+				return false;
+			}
 
 			for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
 
@@ -251,6 +301,19 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
 	return (true);
 }
 
+static char *
+next_insert(char *text)
+{
+	char *ptr = text;
+	bool string = false;
+	
+	for (; ptr[1] != '\0' && (ptr[0] != ';' || ptr[1] != ';' || string); ptr++)
+		if (ptr[0] == '\'')
+			string = string ? false : true;
+			
+	return (ptr[1] == '\0') ? NULL : ptr;
+}
+
 static bool
 ECPGexecute(struct statement * stmt)
 {
@@ -379,7 +442,30 @@ ECPGexecute(struct statement * stmt)
 						tobeinserted = mallocedval;
 					}
 					break;
+				case ECPGt_char_variable:
+					{
+						/* set slen to string length if type is char * */
+						int			slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
+						char	   *tmp;
 
+						if (!(newcopy = ecpg_alloc(slen + 1, stmt->lineno)))
+							return false;
+
+						strncpy(newcopy, (char *) var->value, slen);
+						newcopy[slen] = '\0';
+						if (!(mallocedval = (char *) ecpg_alloc(2 * strlen(newcopy) + 1, stmt->lineno)))
+							return false;
+
+						tmp = quote_strings(newcopy, stmt->lineno);
+						if (!tmp)
+							return false;
+
+						strcat(mallocedval, tmp);
+						free(newcopy);
+
+						tobeinserted = mallocedval;
+					}
+					break;
 				case ECPGt_varchar:
 					{
 						struct ECPGgeneric_varchar *variable =
@@ -428,7 +514,7 @@ ECPGexecute(struct statement * stmt)
 			return false;
 
 		strcpy(newcopy, copiedquery);
-		if ((p = strstr(newcopy, ";;")) == NULL)
+		if ((p = next_insert(newcopy)) == NULL)
 		{
 
 			/*
@@ -449,7 +535,7 @@ ECPGexecute(struct statement * stmt)
 			strcat(newcopy,
 				   copiedquery
 				   + (p - newcopy)
-				   + 2 /* Length of ;; */ );
+				   + sizeof(";;") - 1 /* don't count the '\0' */);
 		}
 
 		/*
@@ -470,7 +556,7 @@ ECPGexecute(struct statement * stmt)
 	}
 
 	/* Check if there are unmatched things left. */
-	if (strstr(copiedquery, ";;") != NULL)
+	if (next_insert(copiedquery) != NULL)
 	{
 		register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
 		return false;
@@ -898,7 +984,21 @@ ECPGtrans(int lineno, const char *transaction)
 		PQclear(res);
 	}
 	if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0)
+	{
+		struct prepared_statement *this;
+			
 		committed = 1;
+
+		/* deallocate all prepared statements */
+		for (this = prep_stmts; this != NULL; this = this->next)
+		{
+			bool b = ECPGdeallocate(lineno, this->name);
+		
+			if (!b) 
+				return false;
+		}
+	}
+
 	return TRUE;
 }
 
@@ -1033,3 +1133,109 @@ sqlprint(void)
 	sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
 	printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
 }
+
+static void
+replace_variables(char *text)
+{
+	char *ptr = text;
+	bool string = false;
+	
+	for (; *ptr != '\0'; ptr++)
+	{
+		if (*ptr == '\'')
+			string = string ? false : true;
+			
+		if (!string && *ptr == ':')
+		{
+			ptr[0] = ptr[1] = ';';
+			for (ptr += 2; *ptr && *ptr != ' '; ptr++)
+				*ptr = ' ';
+		}
+	}
+}
+
+/* handle the EXEC SQL PREPARE statement */
+bool
+ECPGprepare(int lineno, char *name, char *variable)
+{
+	struct statement *stmt;
+	struct prepared_statement *this;
+
+	/* check if we already have prepared this statement */
+	for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);		
+	if (this)
+	{
+		bool b = ECPGdeallocate(lineno, name);
+		
+		if (!b) 
+			return false;
+	}
+	
+	this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
+	if (!this)
+		return false;
+		
+	stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
+	if (!stmt)
+	{
+		free(this);
+		return false;
+	}
+
+	/* create statement */
+	stmt->lineno = lineno;
+        stmt->command = ecpg_strdup(variable, lineno);
+        stmt->inlist = stmt->outlist = NULL;
+        
+        /* if we have C variables in our statment replace them with ';;' */
+        replace_variables(stmt->command);                	
+        
+	/* add prepared statement to our list */
+	this->name = ecpg_strdup(name, lineno);
+	this->stmt = stmt;
+
+	if (prep_stmts == NULL)
+		this->next = NULL;
+	else
+		this->next = prep_stmts;
+
+	prep_stmts = this;
+	return true;
+}
+
+/* handle the EXEC SQL DEALLOCATE PREPARE statement */
+bool
+ECPGdeallocate(int lineno, char *name)
+{
+	struct prepared_statement *this, *prev;
+
+	/* check if we really have prepared this statement */
+	for (this = prep_stmts, prev = NULL; this != NULL && strcmp(this->name, name) != 0; prev = this, this = this->next);		
+	if (this)
+	{
+		/* okay, free all the resources */
+		free(this->name);
+		free(this->stmt->command);
+		free(this->stmt);
+		if (prev != NULL)
+			prev->next = this->next;
+		else
+			prep_stmts = this->next;
+		
+		return true;
+	}
+	ECPGlog("deallocate_prepare: invalid statement name %s\n", name);
+	register_error(ECPG_INVALID_STMT, "Invalid statement name %s in line %d", name, lineno);
+	return false;
+}
+
+/* return the prepared statement */
+char *
+ECPGprepared_statement(char *name)
+{
+	struct prepared_statement *this;
+	
+	for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
+	return (this) ? this->stmt->command : NULL;
+}
+
diff --git a/src/interfaces/ecpg/lib/typename.c b/src/interfaces/ecpg/lib/typename.c
index 0ee2a39cc91d51217d078271b6a19f7e3fb4aec1..af87b160aa9e1108a645ae77656b7d3a3c9825f0 100644
--- a/src/interfaces/ecpg/lib/typename.c
+++ b/src/interfaces/ecpg/lib/typename.c
@@ -8,7 +8,7 @@ ECPGtype_name(enum ECPGttype typ)
 {
 	switch (typ)
 	{
-			case ECPGt_char:
+		case ECPGt_char:
 			return "char";
 		case ECPGt_unsigned_char:
 			return "unsigned char";
@@ -32,6 +32,8 @@ ECPGtype_name(enum ECPGttype typ)
 			return "bool";
 		case ECPGt_varchar:
 			return "varchar";
+		case ECPGt_char_variable:
+			return "char";
 		default:
 			abort();
 	}
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 7fd98c8f06b20b564c6484bc00ca1e7c31c7c31a..87e788c83ccdf2b4e4ef9cc404c0b236b2921073 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -2,20 +2,25 @@ SRCDIR= ../../..
 include $(SRCDIR)/Makefile.global
 
 MAJOR_VERSION=2
-MINOR_VERSION=4
-PATCHLEVEL=9
+MINOR_VERSION=5
+PATCHLEVEL=0
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
 	-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
-	-DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\" 
+	-DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\"
 
-OBJ=y.tab.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
+OBJ=preproc.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
     keywords.o c_keywords.o ../lib/typename.o
 
 all:: ecpg
 
+preproc.c preproc.h: preproc.y
+	$(YACC) $(YFLAGS) $<
+	mv y.tab.c preproc.c
+	mv y.tab.h preproc.h
+
 clean:
-	rm -f *.o core a.out ecpg$(X) y.tab.h y.tab.c pgc.c *~
+	rm -f *.o core a.out ecpg$(X) *~
 
 install: all
 	$(INSTALL) $(INSTL_EXE_OPTS) ecpg$(X) $(DESTDIR)$(BINDIR)
@@ -31,13 +36,10 @@ pgc.c: pgc.l
 	$(LEX) $<
 	mv lex.yy.c pgc.c
 
-y.tab.h y.tab.c: preproc.y
-	$(YACC) $(YFLAGS) $<
-
-y.tab.o : y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
+preproc.o : preproc.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
 type.o : ../include/ecpgtype.h
-pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c y.tab.h
-keywords.o: ../include/ecpgtype.h y.tab.h
-c_keywords.o: ../include/ecpgtype.h y.tab.h
-ecpg_keywords.o: ../include/ecpgtype.h y.tab.h
+pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c preproc.h
+keywords.o: ../include/ecpgtype.h preproc.h
+c_keywords.o: ../include/ecpgtype.h preproc.h 
+ecpg_keywords.o: ../include/ecpgtype.h preproc.h 
 
diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c
index 8629b0d133eaba9ba44a4365590591328bf3f7c8..5395b533d3845b5a690b837534ebc83aefa1ffee 100644
--- a/src/interfaces/ecpg/preproc/c_keywords.c
+++ b/src/interfaces/ecpg/preproc/c_keywords.c
@@ -9,9 +9,8 @@
 #include <string.h>
 
 #include "postgres.h"
-#include "type.h"
-#include "y.tab.h"
 #include "extern.h"
+#include "preproc.h"
 
 /*
  * List of (keyword-name, keyword-token-value) pairs.
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index 11ed36ef65c65d583cc3754ccd0c24f5d03b0419..2594718cd124bdcbd1e78207c0ba66e63860bb70 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -25,6 +25,7 @@ extern char *optarg;
 struct _include_path *include_paths;
 int			no_auto_trans = 0;
 struct cursor *cur = NULL;
+struct typedefs *types = NULL;
 
 static void
 usage(char *progname)
@@ -155,22 +156,22 @@ main(int argc, char *const argv[])
 			{
 				struct cursor *ptr;
 				struct _defines *defptr;
-
+				struct typedefs *typeptr;
+				
 				/* remove old cursor definitions if any are still there */
 				for (ptr = cur; ptr != NULL;)
 				{
 					struct cursor *this = ptr;
-					struct arguments *l1,
-							   *l2;
+					struct arguments *l1, *l2;
 
 					free(ptr->command);
 					free(ptr->name);
-					for (l1 = argsinsert; l1; l1 = l2)
+					for (l1 = ptr->argsinsert; l1; l1 = l2)
 					{
 						l2 = l1->next;
 						free(l1);
 					}
-					for (l1 = argsresult; l1; l1 = l2)
+					for (l1 = ptr->argsresult; l1; l1 = l2)
 					{
 						l2 = l1->next;
 						free(l1);
@@ -189,7 +190,19 @@ main(int argc, char *const argv[])
 					defptr = defptr->next;
 					free(this);
 				}
+				
+				/* and old typedefs */
+				for (typeptr = types; typeptr != NULL;)
+				{
+					struct typedefs *this = typeptr;
 
+					free(typeptr->name);
+					free(typeptr->type);
+					ECPGfree_struct_member(typeptr->struct_member_list);
+					typeptr = typeptr->next;
+					free(this);
+				}
+				
 				/* initialize lex */
 				lex_init();
 
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 5a1bfb8ee07b08d08a8b9ab35ff9a7b7ed97d8c5..52eea065b8373faa30f8484aae60ecf35e246aa4 100644
--- a/src/interfaces/ecpg/preproc/ecpg_keywords.c
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -9,9 +9,8 @@
 #include <string.h>
 
 #include "postgres.h"
-#include "type.h"
 #include "extern.h"
-#include "y.tab.h"
+#include "preproc.h"
 
 /*
  * List of (keyword-name, keyword-token-value) pairs.
@@ -21,25 +20,38 @@
  */
 static ScanKeyword ScanKeywords[] = {
 	/* name					value			*/
+	{"bool", SQL_BOOL},
 	{"break", SQL_BREAK},
 	{"call", SQL_CALL},
 	{"connect", SQL_CONNECT},
 	{"connection", SQL_CONNECTION},
 	{"continue", SQL_CONTINUE},
+	{"deallocate", SQL_DEALLOCATE},
 	{"disconnect", SQL_DISCONNECT},
+	{"enum", SQL_ENUM},
 	{"found", SQL_FOUND},
+	{"free", SQL_FREE},
 	{"go", SQL_GO},
 	{"goto", SQL_GOTO},
 	{"identified", SQL_IDENTIFIED},
 	{"immediate", SQL_IMMEDIATE},
 	{"indicator", SQL_INDICATOR},
+	{"int", SQL_INT},
+	{"long", SQL_LONG},
 	{"open", SQL_OPEN},
+	{"prepare", SQL_PREPARE},
+	{"reference", SQL_REFERENCE},
 	{"release", SQL_RELEASE},
 	{"section", SQL_SECTION},
+	{"short", SQL_SHORT},
+	{"signed", SQL_SIGNED},
 	{"sqlerror", SQL_SQLERROR},
 	{"sqlprint", SQL_SQLPRINT},
 	{"sqlwarning", SQL_SQLWARNING},
 	{"stop", SQL_STOP},
+	{"struct", SQL_STRUCT},
+	{"unsigned", SQL_UNSIGNED},
+	{"var", SQL_VAR},
 	{"whenever", SQL_WHENEVER},
 };
 
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index c7bb651a586640eba0cb1ff2b2d7e84901db68a1..d5bc1fc9cabb4afa5379bc861629e84c987627df 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -1,63 +1,23 @@
 #include "parser/keywords.h"
+#include "type.h"
 #include <errno.h>
 
 /* variables */
 
 extern int	braces_open,
-			no_auto_trans;
+			no_auto_trans, struct_level;
 extern char *yytext;
 extern int	yylineno,
 			yyleng;
 extern FILE *yyin,
 		   *yyout;
 
-struct _include_path
-{
-	char	   *path;
-	struct _include_path *next;
-};
-
 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;
-
-struct _defines
-{
-	char	   *old;
-	char	   *new;
-	struct _defines *next;
-};
-
+extern struct typedefs *types;
 extern struct _defines *defines;
-
-/* This is a linked list of the variable names and types. */
-struct variable
-{
-	char	   *name;
-	struct ECPGtype *type;
-	int			brace_level;
-	struct variable *next;
-};
-
 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;
 
@@ -74,9 +34,10 @@ extern void yyerror(char *);
 
 /* return codes */
 
-#define OK		0
-#define PARSE_ERROR -1
-#define ILLEGAL_OPTION	-2
+#define OK			 0
+#define PARSE_ERROR 		-1
+#define ILLEGAL_OPTION		-2
+#define INDICATOR_NOT_ARRAY	-3
 
 #define NO_INCLUDE_FILE ENOENT
 #define OUT_OF_MEMORY	ENOMEM
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index c12504b392ff4f9532cbd08a9ba2b22e512a3230..bcbb3242de9bca202dd9f75db95d0561c00b2886 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.10 1999/02/13 23:22:35 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.11 1999/02/20 07:01:00 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,7 @@
 #include "nodes/parsenodes.h"
 #include "nodes/pg_list.h"
 #include "type.h"
-#include "y.tab.h"
+#include "preproc.h"
 #include "parser/keywords.h"
 #include "utils/elog.h"
 
@@ -69,9 +69,6 @@ static ScanKeyword ScanKeywords[] = {
 	{"createdb", CREATEDB},
 	{"createuser", CREATEUSER},
 	{"cross", CROSS},
-	{"current", CURRENT},		/* 6.4 to 6.5 is migration time! CURRENT
-								 * will be removed in 6.5! Use OLD keyword
-								 * in rules. Jan */
 	{"current_date", CURRENT_DATE},
 	{"current_time", CURRENT_TIME},
 	{"current_timestamp", CURRENT_TIMESTAMP},
@@ -96,6 +93,7 @@ static ScanKeyword ScanKeywords[] = {
 	{"end", END_TRANS},
 	/***S*I***/
 	{"except", EXCEPT},
+
 	{"execute", EXECUTE},
 	{"exists", EXISTS},
 	{"explain", EXPLAIN},
@@ -125,6 +123,7 @@ static ScanKeyword ScanKeywords[] = {
 	{"instead", INSTEAD},
 	/***S*I***/
 	{"intersect", INTERSECT},
+
 	{"interval", INTERVAL},
 	{"into", INTO},
 	{"is", IS},
@@ -138,6 +137,7 @@ static ScanKeyword ScanKeywords[] = {
 	{"left", LEFT},
 	{"level", LEVEL},
 	{"like", LIKE},
+	{"limit", LIMIT},
 	{"listen", LISTEN},
 	{"load", LOAD},
 	{"local", LOCAL},
@@ -167,6 +167,7 @@ static ScanKeyword ScanKeywords[] = {
 	{"nullif", NULLIF},
 	{"numeric", NUMERIC},
 	{"of", OF},
+	{"offset", OFFSET},
 	{"oids", OIDS},
 	{"old", CURRENT},
 	{"on", ON},
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index e6ef819a595821df005ed8deea562917ca98ac3d..5ddac659bbc4cef6f3f57f22db512f6b4144023c 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -24,9 +24,8 @@
 #include "nodes/parsenodes.h"
 #include "parser/gramparse.h"
 #include "parser/scansup.h"
-#include "type.h"
 #include "extern.h"
-#include "y.tab.h"
+#include "preproc.h"
 #include "utils/builtins.h"
 
 /* some versions of lex define this as a macro */
@@ -241,7 +240,7 @@ cppline		{space}*#.*(\\{space}*\n)*\n*
 				}
 <xq>{xqstop}	{
 					BEGIN(SQL);
-					yylval.str = strdup(scanstr(literal));
+					yylval.str = mm_strdup(scanstr(literal));
 					return SCONST;
 				}
 <xq>{xqdouble}	|
@@ -276,7 +275,7 @@ cppline		{space}*#.*(\\{space}*\n)*\n*
 				}
 <xd>{xdstop}	{
 					BEGIN(SQL);
-					yylval.str = strdup(literal);
+					yylval.str = mm_strdup(literal);
 					return CSTRING;
 				}
 <xd>{xdinside}	{
@@ -292,7 +291,7 @@ cppline		{space}*#.*(\\{space}*\n)*\n*
 				}
 <xdc>{xdstop}	{
 					BEGIN(C);
-					yylval.str = strdup(literal);
+					yylval.str = mm_strdup(literal);
 					return CSTRING;
 				}
 <xdc>{xdinside}	{
@@ -316,14 +315,14 @@ cppline		{space}*#.*(\\{space}*\n)*\n*
 				}
 <SQL>{self}				{ 	return yytext[0]; }
 <SQL>{operator}/-[\.0-9]	{
-					yylval.str = strdup((char*)yytext);
+					yylval.str = mm_strdup((char*)yytext);
 					return Op;
 				}
 <SQL>{operator}		{
 					if (strcmp((char*)yytext,"!=") == 0)
-						yylval.str = strdup("<>"); /* compatability */
+						yylval.str = mm_strdup("<>"); /* compatability */
 					else
-						yylval.str = strdup((char*)yytext);
+						yylval.str = mm_strdup((char*)yytext);
 					return Op;
 				}
 <SQL>{param}			{
@@ -342,7 +341,6 @@ cppline		{space}*#.*(\\{space}*\n)*\n*
 						if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
 							lower_text[i] = tolower(lower_text[i]);
 
-printf("yyt= %s, lt = %s\n", yytext, lower_text);
 					keyword = ScanKeywordLookup((char*)lower_text);
 					if (keyword != NULL) {
 						return keyword->value;
@@ -367,7 +365,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 
 						                        yb->buffer =  YY_CURRENT_BUFFER;
 						                        yb->lineno = yylineno;
-						                        yb->filename = strdup(input_filename);
+						                        yb->filename = mm_strdup(input_filename);
 						                        yb->next = yy_buffer;
 
 						                        yy_buffer = yb;
@@ -378,7 +376,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 							}
 							if (ptr == NULL) 
 							{
-								yylval.str = strdup((char*)yytext);
+								yylval.str = mm_strdup((char*)yytext);
 								return IDENT;
 							}
 						}
@@ -470,7 +468,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 					return ICONST;
 				}
 <SQL>:{identifier}(("->"|\.){identifier})*	{
-					yylval.str = strdup((char*)yytext+1);
+					yylval.str = mm_strdup((char*)yytext+1);
 					return(CVARIABLE);
 			}
 <SQL>{identifier}	{
@@ -484,7 +482,6 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 						if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
 							lower_text[i] = tolower(lower_text[i]);
 
-printf("yyt= %s, lt = %s\n", yytext, lower_text);
 					keyword = ScanKeywordLookup((char*)lower_text);
 					if (keyword != NULL) {
 						return keyword->value;
@@ -509,7 +506,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 
 						                        yb->buffer =  YY_CURRENT_BUFFER;
 						                        yb->lineno = yylineno;
-						                        yb->filename = strdup(input_filename);
+						                        yb->filename = mm_strdup(input_filename);
 						                        yb->next = yy_buffer;
 
 						                        yy_buffer = yb;
@@ -520,19 +517,26 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 							}
 							if (ptr == NULL) 
 							{
-								yylval.str = strdup((char*)yytext);
+								yylval.str = mm_strdup((char*)yytext);
 								return IDENT;
 							}
 						}
 					}
 				}
 <SQL>{space}			{ /* ignore */ }
-<SQL>";"	                { BEGIN C; return SQL_SEMI; }
+<SQL>";"	                { /* 
+				   * We may find a ';' inside a structure
+				   * definition in a TYPE or VAR statement.
+				   * This is not a EOL marker.
+				   */
+				  if (struct_level == 0)
+					 BEGIN C;
+				  return SQL_SEMI; }
 <SQL>{other}			{ return yytext[0]; }
 <C>{exec}{space}{sql}		{ BEGIN SQL; return SQL_START; }
 <C>{ccomment}			{ /* ignore */ } 
 <C>{cppline}			{
-					yylval.str = strdup((char*)yytext);
+					yylval.str = mm_strdup((char*)yytext);
 					return(CPP_LINE);
 				}
 <C>{identifier}	{
@@ -556,7 +560,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 
 					                        yb->buffer =  YY_CURRENT_BUFFER;
 					                        yb->lineno = yylineno;
-					                        yb->filename = strdup(input_filename);
+					                        yb->filename = mm_strdup(input_filename);
 					                        yb->next = yy_buffer;
 
 					                        yy_buffer = yb;
@@ -567,7 +571,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 						}
 						if (ptr == NULL) 
 						{
-							yylval.str = strdup((char*)yytext);
+							yylval.str = mm_strdup((char*)yytext);
 							return IDENT;
 						}
 					}
@@ -585,7 +589,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 <C>{exec}{space}{sql}{space}{define}	{BEGIN(def_ident);}
 <def_ident>{space}	{}
 <def_ident>{identifier}	{
-				old = strdup(yytext);
+				old = mm_strdup(yytext);
 				BEGIN(def);
 				llen = 0;
 				*literal = '\0';
@@ -599,7 +603,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
                                      if (strcmp(old, ptr->old) == 0)
                                      {
 					free(ptr->new);
-					ptr->new = strdup(scanstr(literal));
+					ptr->new = mm_strdup(scanstr(literal));
                                      }
                                 }
 				if (ptr == NULL)
@@ -608,7 +612,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 
                                         /* initial definition */
                                         this->old = old;
-                                        this->new = strdup(scanstr(literal));
+                                        this->new = mm_strdup(scanstr(literal));
 					this->next = defines;
 					defines = this;
 				}
@@ -666,7 +670,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
 				exit(NO_INCLUDE_FILE); 
 			  }
 
-			  input_filename = strdup(inc_file);
+			  input_filename = mm_strdup(inc_file);
 			  yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
 			  yylineno = 0;
 
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 355bf31dda095e5c2b0b008f85676eb3b20b3970..7bb95d77e8cb8c2e58546e922c2c1f51daa6c8fa 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -6,7 +6,6 @@
 #include "catalog/catname.h"
 #include "utils/numeric.h"
 
-#include "type.h"
 #include "extern.h"
 
 #ifdef MULTIBYTE
@@ -18,10 +17,10 @@
 /*
  * Variables containing simple states.
  */
-static int	struct_level = 0;
+int	struct_level = 0;
 static char	errortext[128];
 static int      QueryIsRule = 0, ForUpdateNotAllowed = 0;
-static enum ECPGttype actual_type[STRUCT_DEPTH];
+static struct this_type actual_type[STRUCT_DEPTH];
 static char     *actual_storage[STRUCT_DEPTH];
 
 /* temporarily store struct members while creating the data structure */
@@ -30,6 +29,8 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
 struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
 struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
 
+struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
+
 /*
  * Handle the filename and line numbering.
  */
@@ -505,6 +506,98 @@ output_statement(char * stmt, int mode)
 	free(stmt);
 }
 
+static struct typedefs *
+get_typedef(char *name)
+{
+	struct typedefs *this;
+
+	for (this = types; this && strcmp(this->name, name); this = this->next);
+	if (!this)
+	{
+		sprintf(errortext, "invalid datatype '%s'", name);
+		yyerror(errortext);
+	}
+
+	return(this);
+}
+
+static void
+adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer)
+{
+	if (type_index >= 0) 
+	{
+		if (*length >= 0)
+                      	yyerror("No multi-dimensional array support");
+
+		*length = type_index;
+	}
+		       
+	if (type_dimension >= 0)
+	{
+		if (*dimension >= 0 && *length >= 0)
+			yyerror("No multi-dimensional array support");
+
+		if (*dimension >= 0)
+			*length = *dimension;
+
+		*dimension = type_dimension;
+	}
+
+	switch (type_enum)
+	{
+	   case ECPGt_struct:
+	        /* pointer has to get dimension 0 */
+                if (pointer)
+	        {
+		    *length = *dimension;
+                    *dimension = 0;
+	        }
+
+                if (*length >= 0)
+                   yyerror("No multi-dimensional array support for structures");
+
+                break;
+           case ECPGt_varchar:
+	        /* pointer has to get length 0 */
+                if (pointer)
+                    *length=0;
+
+                /* one index is the string length */
+                if (*length < 0)
+                {
+                   *length = *dimension;
+                   *dimension = -1;
+                }
+
+                break;
+           case ECPGt_char:
+           case ECPGt_unsigned_char:
+	        /* pointer has to get length 0 */
+                if (pointer)
+                    *length=0;
+
+                /* one index is the string length */
+                if (*length < 0)
+                {
+                   *length = (*dimension < 0) ? 1 : *dimension;
+                   *dimension = -1;
+                }
+
+                break;
+           default:
+ 	        /* a pointer has dimension = 0 */
+                if (pointer) {
+                    *length = *dimension;
+		    *dimension = 0;
+	        }
+
+                if (*length >= 0)
+                   yyerror("No multi-dimensional array support for simple data types");
+
+                break;
+	}
+}
+
 %}
 
 %union {
@@ -519,12 +612,15 @@ output_statement(char * stmt, int mode)
 }
 
 /* special embedded SQL token */
-%token		SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
-%token		SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
-%token		SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN 
-%token		SQL_PREPARE SQL_RELEASE
-%token		SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
-%token		SQL_STOP SQL_WHENEVER SQL_SQLWARNING
+%token		SQL_BOOL SQL_BREAK 
+%token		SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
+%token		SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM 
+%token		SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
+%token		SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_INT SQL_LONG
+%token		SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
+%token		SQL_SECTION SQL_SEMI SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
+%token		SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
+%token		SQL_VAR SQL_WHENEVER
 
 /* C token */
 %token		S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN
@@ -577,9 +673,9 @@ output_statement(char * stmt, int mode)
                 DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND,
                 FORWARD, FUNCTION, HANDLER,
                 INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
-                LANCOMPILER, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
+                LANCOMPILER, LIMIT, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
                 NEW,  NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
-		OIDS, OPERATOR, PASSWORD, PROCEDURAL,
+		OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
                 RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
                 SERIAL, SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
                 UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
@@ -654,8 +750,9 @@ output_statement(char * stmt, int mode)
 %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 OptStmtMulti OptStmtBlock
-%type  <str>    OptStmtList RuleStmt opt_column opt_name oper_argtypes
+%type  <str>    opt_instead event event_object RuleActionList,
+%type  <str>	RuleActionBlock RuleActionMulti 
+%type  <str>    RuleStmt opt_column opt_name oper_argtypes
 %type  <str>    MathOp RemoveFuncStmt aggr_argtype for_update_clause
 %type  <str>    RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt
 %type  <str>    RemoveOperStmt RenameStmt all_Op user_valid_clause
@@ -665,7 +762,7 @@ output_statement(char * stmt, int mode)
 %type  <str>    user_createuser_clause user_group_list user_group_clause
 %type  <str>    CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
 %type  <str>    OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
-%type  <str>	DropTrigStmt TriggerOneEvent TriggerEvents
+%type  <str>	DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt
 %type  <str>    TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
 %type  <str>    CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
 %type  <str>    ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location
@@ -673,27 +770,32 @@ output_statement(char * stmt, int mode)
 %type  <str>	GrantStmt privileges operation_commalist operation
 %type  <str>	cursor_clause opt_cursor opt_readonly opt_of opt_lmode
 %type  <str>	case_expr when_clause_list case_default case_arg when_clause
-%type  <str>    select_w_o_sort 
+%type  <str>    select_w_o_sort opt_select_limit select_limit_value,
+%type  <str>    select_offset_value
 
-%type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
-%type  <str>	indicator ECPGExecute ecpg_expr dotext
+%type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen opt_using
+%type  <str>	indicator ECPGExecute ecpg_expr dotext ECPGPrepare
 %type  <str>    storage_clause opt_initializer vartext c_anything blockstart
 %type  <str>    blockend variable_list variable var_anything do_anything
 %type  <str>	opt_pointer cvariable ECPGDisconnect dis_name
 %type  <str>	stmt symbol opt_symbol ECPGRelease execstring server_name
-%type  <str>	connection_object opt_server opt_port c_thing
+%type  <str>	connection_object opt_server opt_port c_thing opt_reference
 %type  <str>    user_name opt_user char_variable ora_user ident
 %type  <str>    db_prefix server opt_options opt_connection_name
-%type  <str>	ECPGSetConnection c_line cpp_line s_enum
-%type  <str>	enum_type
+%type  <str>	ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
+%type  <str>	enum_type civariableonly ECPGCursorStmt ECPGDeallocate
+%type  <str>	ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
+%type  <str>	sql_declaration sql_variable_list sql_variable
+%type  <str>    struct_type s_struct declaration variable_declarations
 
-%type  <type_enum> simple_type
+%type  <type_enum> simple_type varchar_type
 
-%type  <type>	type
+%type  <type>	type ctype
 
 %type  <action> action
 
-%type  <index>	opt_array_bounds nest_array_bounds
+%type  <index>	opt_array_bounds nest_array_bounds opt_type_array_bounds
+%type  <index>  nest_type_array_bounds
 
 %%
 prog: statements;
@@ -769,13 +871,29 @@ stmt:  AddAttrStmt			{ output_statement($1, 0); }
 						whenever_action(0);
 						free($1);
 					} 
+		| ECPGCursorStmt	{
+						fputs($1, yyout);
+                                                free($1); 
+					}
+		| ECPGDeallocate	{
+						fputs($1, yyout);
+						whenever_action(0);
+						free($1);
+					}
+		| ECPGDeclare		{
+						fputs($1, yyout);
+						free($1);
+					}
 		| ECPGDisconnect	{
 						fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1); 
 						whenever_action(0);
 						free($1);
 					} 
 		| ECPGExecute		{
-						fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT);", $1);
+						output_statement($1, 0);
+					}
+		| ECPGFree		{
+						fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1); 
 						whenever_action(0);
 						free($1);
 					}
@@ -797,26 +915,39 @@ stmt:  AddAttrStmt			{ output_statement($1, 0); }
 						fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
 						/* dump variables to C file*/
 						dump_variables(ptr->argsinsert, 0);
+						dump_variables(argsinsert, 0);
 						fputs("ECPGt_EOIT, ", yyout);
 						dump_variables(ptr->argsresult, 0);
 						fputs("ECPGt_EORT);", yyout);
 						whenever_action(0);
 						free($1);
 					}
+		| ECPGPrepare		{
+						fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1); 
+						whenever_action(0);
+						free($1);
+					}
 		| ECPGRelease		{ /* output already done */ }
 		| ECPGSetConnection     {
 						fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
 						whenever_action(0);
                                        		free($1);
 					}
+		| ECPGTypedef		{
+						fputs($1, yyout);
+                                                free($1);
+					}
+		| ECPGVar		{
+						fputs($1, yyout);
+                                                free($1);
+					}
 		| ECPGWhenever		{
 						fputs($1, yyout);
 						output_line_number();
 						free($1);
 					}
-		| ECPGPrepare		{
-						yyerror("PREPARE is not supported yet.");
-					}
+		;
+
 
 /*
  * We start with a lot of stuff that's very similar to the backend's parsing
@@ -1098,7 +1229,7 @@ copy_delimiter:  USING DELIMITERS Sconst		{ $$ = cat2_str(make1_str("using delim
 CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
 				OptInherit
 				{
-					$$ = cat5_str(make1_str("create"), $2, make1_str("table"), make3_str(make1_str("("), $6, make1_str(")")), $8);
+					$$ = cat3_str(cat4_str(make1_str("create"), $2, make1_str("table"), $4), make3_str(make1_str("("), $6, make1_str(")")), $8);
 				}
 		;
 
@@ -2127,40 +2258,37 @@ opt_column:  COLUMN					{ $$ = make1_str("colmunn"); }
 RuleStmt:  CREATE RULE name AS
 		   { QueryIsRule=1; }
 		   ON event TO event_object where_clause
-		   DO opt_instead OptStmtList
+		   DO opt_instead RuleActionList
 				{
 					$$ = cat2_str(cat5_str(cat5_str(make1_str("create rule"), $3, make1_str("as on"), $7, make1_str("to")), $9, $10, make1_str("do"), $12), $13);
 				}
 		;
 
-OptStmtList:  NOTHING					{ $$ = make1_str("nothing"); }
-		| OptimizableStmt			{ $$ = $1; }
-		| '[' OptStmtBlock ']'			{ $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
-/***S*I*D***/
-/* We comment this out because it produces a shift / reduce conflict 
- * with the select_w_o_sort rule */
-/*		| '(' OptStmtBlock ')'			{ $$ = cat3_str(make1_str("("), $2, make1_str(")")); }*/
-		;
+RuleActionList:  NOTHING                               { $$ = make1_str("nothing"); }
+               | SelectStmt                            { $$ = $1; }
+               | RuleActionStmt                        { $$ = $1; }
+               | '[' RuleActionBlock ']'               { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
+               | '(' RuleActionBlock ')'               { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }
+                ;
 
-OptStmtBlock:  OptStmtMulti
-				{  $$ = $1; }
-		| OptimizableStmt
-				{ $$ = $1; }
+RuleActionBlock:  RuleActionMulti              {  $$ = $1; }
+               | RuleActionStmt                {  $$ = $1; }
 		;
 
-OptStmtMulti:  OptStmtMulti OptimizableStmt ';'
+RuleActionMulti:  RuleActionMulti RuleActionStmt
+                                {  $$ = cat2_str($1, $2); }
+		| RuleActionMulti RuleActionStmt ';'
 				{  $$ = cat3_str($1, $2, make1_str(";")); }
-/***S*I***/
-/* We comment the next rule because it seems to be redundant
- * and produces 16 shift/reduce conflicts with the new SelectStmt rule
- * needed for EXCEPT and INTERSECT. So far I did not notice any
- * violations by removing the rule! */
-/*		| OptStmtMulti OptimizableStmt
-				{  $$ = cat2_str($1, $2); }*/
-		| OptimizableStmt ';'
+		| RuleActionStmt ';'
 				{ $$ = cat2_str($1, make1_str(";")); }
 		;
 
+RuleActionStmt:        InsertStmt
+                | UpdateStmt
+                | DeleteStmt
+		| NotifyStmt
+                ;
+
 event_object:  relation_name '.' attr_name
 				{
 					$$ = make3_str($1, make1_str("."), $3);
@@ -2588,7 +2716,7 @@ CursorStmt:  DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
 					{
 						if (strcmp($2, ptr->name) == 0)
 						{
-						        /* re-definition is a bug*/
+						        /* re-definition is a bug */
 							sprintf(errortext, "cursor %s already defined", $2);
 							yyerror(errortext);
 				                }
@@ -2642,13 +2770,13 @@ opt_of:  OF columnList { $$ = make2_str(make1_str("of"), $2); }
 /* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT a nd UNION
  * accepts the use of '(' and ')' to select an order of set operations.
  */
-SelectStmt:  select_w_o_sort sort_clause for_update_clause
+SelectStmt:  select_w_o_sort sort_clause for_update_clause opt_select_limit
 				{
 					if (strlen($3) > 0 && ForUpdateNotAllowed != 0)
 							yyerror("SELECT FOR UPDATE is not allowed in this context");
 
 					ForUpdateNotAllowed = 0;
-					$$ = cat3_str($1, $2, $3);
+					$$ = cat4_str($1, $2, $3, $4);
 				}
 
 /***S*I***/ 
@@ -2736,6 +2864,29 @@ OptUseOp:  USING Op				{ $$ = cat2_str(make1_str("using"), $2); }
 		| /*EMPTY*/			{ $$ = make1_str(""); }
 		;
 
+opt_select_limit:      LIMIT select_limit_value ',' select_offset_value
+                       { $$ = cat4_str(make1_str("limit"), $2, make1_str(","), $4); }
+               | LIMIT select_limit_value OFFSET select_offset_value
+                       { $$ = cat4_str(make1_str("limit"), $2, make1_str("offset"), $4); }
+               | LIMIT select_limit_value
+                       { $$ = cat2_str(make1_str("limit"), $2);; }
+               | OFFSET select_offset_value LIMIT select_limit_value
+                       { $$ = cat4_str(make1_str("offset"), $2, make1_str("limit"), $4); }
+               | OFFSET select_offset_value
+                       { $$ = cat2_str(make1_str("offset"), $2); }
+               | /* EMPTY */
+                       { $$ = make1_str(""); }
+               ;
+
+select_limit_value:	Iconst	{ $$ = $1; }
+	          	| ALL	{ $$ = make1_str("all"); }
+			| PARAM { $$ = make_name(); }
+               ;
+
+select_offset_value:  	Iconst	{ $$ = $1; }
+			| PARAM { $$ = make_name(); }
+               ;
+
 /*
  *	jimmy bell-style recursive queries aren't supported in the
  *	current system.
@@ -2952,6 +3103,36 @@ Generic:  generic
 
 generic:  ident					{ $$ = $1; }
 		| TYPE_P			{ $$ = make1_str("type"); }
+		| SQL_BOOL			{ $$ = make1_str("bool"); }
+		| SQL_BREAK			{ $$ = make1_str("break"); }
+		| SQL_CALL			{ $$ = make1_str("call"); }
+		| SQL_CONNECT			{ $$ = make1_str("connect"); }
+		| SQL_CONNECTION		{ $$ = make1_str("connection"); }
+		| SQL_CONTINUE			{ $$ = make1_str("continue"); }
+		| SQL_DEALLOCATE		{ $$ = make1_str("deallocate"); }
+		| SQL_DISCONNECT		{ $$ = make1_str("disconnect"); }
+		| SQL_FOUND			{ $$ = make1_str("found"); }
+		| SQL_GO			{ $$ = make1_str("go"); }
+		| SQL_GOTO			{ $$ = make1_str("goto"); }
+		| SQL_IDENTIFIED		{ $$ = make1_str("identified"); }
+		| SQL_IMMEDIATE			{ $$ = make1_str("immediate"); }
+		| SQL_INDICATOR			{ $$ = make1_str("indicator"); }
+		| SQL_INT			{ $$ = make1_str("int"); }
+		| SQL_LONG			{ $$ = make1_str("long"); }
+		| SQL_OPEN			{ $$ = make1_str("open"); }
+		| SQL_PREPARE			{ $$ = make1_str("prepare"); }
+		| SQL_RELEASE			{ $$ = make1_str("release"); }
+		| SQL_SECTION			{ $$ = make1_str("section"); }
+		| SQL_SHORT			{ $$ = make1_str("short"); }
+		| SQL_SIGNED			{ $$ = make1_str("signed"); }
+		| SQL_SQLERROR			{ $$ = make1_str("sqlerror"); }
+		| SQL_SQLPRINT			{ $$ = make1_str("sqlprint"); }
+		| SQL_SQLWARNING		{ $$ = make1_str("sqlwarning"); }
+		| SQL_STOP			{ $$ = make1_str("stop"); }
+		| SQL_STRUCT			{ $$ = make1_str("struct"); }
+		| SQL_UNSIGNED			{ $$ = make1_str("unsigned"); }
+		| SQL_VAR			{ $$ = make1_str("var"); }
+		| SQL_WHENEVER			{ $$ = make1_str("whenever"); }
 		;
 
 /* SQL92 numeric data types
@@ -3638,7 +3819,7 @@ b_expr:  attr opt_indirection
 					$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
 				}
 		| civariableonly
-			        { $$ = make1_str(";;"); }
+			        { 	$$ = $1; }
 		;
 
 opt_indirection:  '[' ecpg_expr ']' opt_indirection
@@ -4125,6 +4306,36 @@ ColId:  ident					{ $$ = $1; }
 		| VALID				{ $$ = make1_str("valid"); }
 		| VERSION			{ $$ = make1_str("version"); }
 		| ZONE				{ $$ = make1_str("zone"); }
+		| SQL_BOOL			{ $$ = make1_str("bool"); }
+		| SQL_BREAK			{ $$ = make1_str("break"); }
+		| SQL_CALL			{ $$ = make1_str("call"); }
+		| SQL_CONNECT			{ $$ = make1_str("connect"); }
+		| SQL_CONNECTION		{ $$ = make1_str("connection"); }
+		| SQL_CONTINUE			{ $$ = make1_str("continue"); }
+		| SQL_DEALLOCATE		{ $$ = make1_str("deallocate"); }
+		| SQL_DISCONNECT		{ $$ = make1_str("disconnect"); }
+		| SQL_FOUND			{ $$ = make1_str("found"); }
+		| SQL_GO			{ $$ = make1_str("go"); }
+		| SQL_GOTO			{ $$ = make1_str("goto"); }
+		| SQL_IDENTIFIED		{ $$ = make1_str("identified"); }
+		| SQL_IMMEDIATE			{ $$ = make1_str("immediate"); }
+		| SQL_INDICATOR			{ $$ = make1_str("indicator"); }
+		| SQL_INT			{ $$ = make1_str("int"); }
+		| SQL_LONG			{ $$ = make1_str("long"); }
+		| SQL_OPEN			{ $$ = make1_str("open"); }
+		| SQL_PREPARE			{ $$ = make1_str("prepare"); }
+		| SQL_RELEASE			{ $$ = make1_str("release"); }
+		| SQL_SECTION			{ $$ = make1_str("section"); }
+		| SQL_SHORT			{ $$ = make1_str("short"); }
+		| SQL_SIGNED			{ $$ = make1_str("signed"); }
+		| SQL_SQLERROR			{ $$ = make1_str("sqlerror"); }
+		| SQL_SQLPRINT			{ $$ = make1_str("sqlprint"); }
+		| SQL_SQLWARNING		{ $$ = make1_str("sqlwarning"); }
+		| SQL_STOP			{ $$ = make1_str("stop"); }
+		| SQL_STRUCT			{ $$ = make1_str("struct"); }
+		| SQL_UNSIGNED			{ $$ = make1_str("unsigned"); }
+		| SQL_VAR			{ $$ = make1_str("var"); }
+		| SQL_WHENEVER			{ $$ = make1_str("whenever"); }
 		;
 /* Column label
  * Allowed labels in "AS" clauses.
@@ -4197,223 +4408,6 @@ SpecialRuleRelation:  CURRENT
  * and now special embedded SQL stuff
  */
 
-/*
- * variable declaration inside the exec sql declare block
- */
-ECPGDeclaration: sql_startdeclare variable_declarations sql_enddeclare {}
-
-sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {
-	fputs("/* exec sql begin declare section */\n", yyout);
-	output_line_number();
- }
-
-sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {
-    fputs("/* exec sql end declare section */\n", yyout); 
-    output_line_number();
-}
-
-variable_declarations: /* empty */
-	| declaration variable_declarations;
-
-declaration: storage_clause type
-	{
-		actual_storage[struct_level] = $1;
-		actual_type[struct_level] = $2.type_enum;
-		if ($2.type_enum != ECPGt_varchar && $2.type_enum != ECPGt_struct)
-			fprintf(yyout, "%s %s", $1, $2.type_str);
-		free($2.type_str);
-	}
-	variable_list ';' { fputc(';', yyout); }
-
-storage_clause : S_EXTERN	{ $$ = "extern"; }
-       | S_STATIC		{ $$ = "static"; }
-       | S_SIGNED		{ $$ = "signed"; }
-       | S_CONST		{ $$ = "const"; }
-       | S_REGISTER		{ $$ = "register"; }
-       | S_AUTO			{ $$ = "auto"; }
-       | /* empty */		{ $$ = ""; }
-
-type: simple_type
-		{
-			$$.type_enum = $1;
-			$$.type_str = mm_strdup(ECPGtype_name($1));
-		}
-	| struct_type
-		{
-			$$.type_enum = ECPGt_struct;
-			$$.type_str = make1_str("");
-		}
-	| enum_type
-		{
-			$$.type_str = $1;
-			$$.type_enum = ECPGt_int;
-		}
-
-enum_type: s_enum '{' c_line '}'
-	{
-		$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
-	}
-	
-s_enum: S_ENUM opt_symbol	{ $$ = cat2_str(make1_str("enum"), $2); }
-
-struct_type: s_struct '{' variable_declarations '}'
-	{
-	    ECPGfree_struct_member(struct_member_list[struct_level]);
-	    free(actual_storage[struct_level--]);
-	    fputs("} ", yyout);
-	}
-
-s_struct : S_STRUCT opt_symbol
-        {
-            struct_member_list[struct_level++] = NULL;
-            if (struct_level >= STRUCT_DEPTH)
-                 yyerror("Too many levels in nested structure definition");
-	    fprintf(yyout, "struct %s {", $2);
-	    free($2);
-	}
-
-opt_symbol: /* empty */ 	{ $$ = make1_str(""); }
-	| symbol		{ $$ = $1; }
-
-simple_type: S_SHORT		{ $$ = ECPGt_short; }
-           | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
-	   | S_INT 		{ $$ = ECPGt_int; }
-           | S_UNSIGNED S_INT	{ $$ = ECPGt_unsigned_int; }
-	   | S_LONG		{ $$ = ECPGt_long; }
-           | S_UNSIGNED S_LONG	{ $$ = ECPGt_unsigned_long; }
-           | S_FLOAT		{ $$ = ECPGt_float; }
-           | S_DOUBLE		{ $$ = ECPGt_double; }
-	   | S_BOOL		{ $$ = ECPGt_bool; };
-	   | S_CHAR		{ $$ = ECPGt_char; }
-           | S_UNSIGNED S_CHAR	{ $$ = ECPGt_unsigned_char; }
-	   | S_VARCHAR		{ $$ = ECPGt_varchar; }
-
-variable_list: variable 
-	| variable_list ','
-	{
-		if (actual_type[struct_level] != ECPGt_varchar)
-			fputs(", ", yyout);
-		else
-			fputs(";\n ", yyout);
-	} variable
-
-variable: opt_pointer symbol opt_array_bounds opt_initializer
-		{
-			struct ECPGtype * type;
-                        int dimension = $3.index1; /* dimension of array */
-                        int length = $3.index2;    /* lenght of string */
-                        char dim[14L];
-
-			switch (actual_type[struct_level])
-			{
-			   case ECPGt_struct:
-			       /* pointer has to get dimension 0 */
-        	               if (strlen($1) > 0)
-			       {
-				    length = dimension;
-                	            dimension = 0;
-			       }
-
-                               if (length >= 0)
-                                   yyerror("No multi-dimensional array support for structures");
-
-                               if (dimension == 1 || dimension < 0)
-                                   type = ECPGmake_struct_type(struct_member_list[struct_level]);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension); 
-
-                               fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
-                               break;
-                           case ECPGt_varchar:
-			       /* pointer has to get length 0 */
-        	               if (strlen($1) > 0)
-                	            length=0;
-
-                               /* one index is the string length */
-                               if (length < 0)
-                               {
-                                   length = dimension;
-                                   dimension = 1;
-                               }
-
-                               if (dimension == 1)
-                                   type = ECPGmake_simple_type(actual_type[struct_level], length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
-
-                               switch(dimension)
-                               {
-                                  case 0:
-                                      strcpy(dim, "[]");
-                                      break;
-                                  case 1:
-                                      *dim = '\0';
-                                      break;
-                                  default:
-                                      sprintf(dim, "[%d]", dimension);
-                                      break;
-                                }
-                               if (length > 0)
-                                   fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s%s", actual_storage[struct_level], $2, length, $2, dim);
-                               else
-                                   fprintf(yyout, "%s struct varchar_%s { int len; char *arr; } %s%s", actual_storage[struct_level], $2, $2, dim);
-                               break;
-                           case ECPGt_char:
-                           case ECPGt_unsigned_char:
-			       /* pointer has to get length 0 */
-        	               if (strlen($1) > 0)
-                	            length=0;
-
-                               /* one index is the string length */
-                               if (length < 0)
-                               {
-                                   length = (dimension < 0) ? 1 : dimension;
-                                   dimension = 1;
-                               }
-
-                               if (dimension == 1)
-                                   type = ECPGmake_simple_type(actual_type[struct_level], length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
-
-                               fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
-                               break;
-                           default:
-			       /* a pointer has dimension = 0 */
-        	               if (strlen($1) > 0) {
-                	            length = dimension;
-				    dimension = 0;
-			       }
-
-                               if (length >= 0)
-                                   yyerror("No multi-dimensional array support for simple data types");
-
-                               if (dimension == 1 || dimension < 0)
-                                   type = ECPGmake_simple_type(actual_type[struct_level], 1);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], 1), dimension);
-
-                               fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
-                               break;
-			}
-
-			if (struct_level == 0)
-				new_variable($2, type);
-			else
-				ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
-
-			free($1);
-			free($2);
-			free($3.str);
-			free($4);
-		}
-
-opt_initializer: /* empty */		{ $$ = make1_str(""); }
-	| '=' vartext			{ $$ = make2_str(make1_str("="), $2); }
-
-opt_pointer: /* empty */	{ $$ = make1_str(""); }
-	| '*'			{ $$ = make1_str("*"); }
-
 /*
  * the exec sql connect statement: connect to the given database 
  */
@@ -4585,49 +4579,368 @@ opt_options: Op ColId
 	| /* empty */ { $$ = make1_str(""); }
 
 /*
- * the exec sql disconnect statement: disconnect from the given database 
+ * Declare a prepared cursor. The syntax is different from the standard
+ * declare statement, so we create a new rule.
  */
-ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
+ECPGCursorStmt:  DECLARE name opt_cursor CURSOR FOR ident cursor_clause
+				{
+					struct cursor *ptr, *this;
+					struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
 
-dis_name: connection_object	{ $$ = $1; }
-	| CURRENT	{ $$ = make1_str("CURRENT"); }
-	| ALL		{ $$ = make1_str("ALL"); }
-	| /* empty */	{ $$ = make1_str("CURRENT"); }
+					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);
+				                }
+        				}
 
-connection_object: connection_target { $$ = $1; }
-	| DEFAULT	{ $$ = make1_str("DEFAULT"); }
+        				this = (struct cursor *) mm_alloc(sizeof(struct cursor));
 
-/*
- * execute a given string as sql command
- */
-ECPGExecute : EXECUTE SQL_IMMEDIATE execstring { $$ = $3; };
+			        	/* initial definition */
+				        this->next = cur;
+				        this->name = $2;
+				        this->command =  cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
+					this->argsresult = NULL;
 
-execstring: cvariable |
-	CSTRING	 { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); };
+					thisquery->type = &ecpg_query;
+					thisquery->brace_level = 0;
+					thisquery->next = NULL;
+					thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($6));
+					sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $6);
 
-/*
- * open is an open cursor, at the moment this has to be removed
- */
-ECPGOpen: SQL_OPEN name open_opts {
-		$$ = $2;
-};
+					this->argsinsert = NULL;
+					add_variable(&(this->argsinsert), thisquery, &no_indicator); 
 
-open_opts: /* empty */		{ $$ = make1_str(""); }
-	| USING cvariable	{
-					yyerror ("open cursor with variables not implemented yet");
+			        	cur = this;
+					
+					$$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/"));
 				}
+		;
 
 /*
- * for compatibility with ORACLE we will also allow the keyword RELEASE
- * after a transaction statement to disconnect from the database.
+ * the exec sql deallocate prepare command to deallocate a previously
+ * prepared statement
  */
+ECPGDeallocate:	SQL_DEALLOCATE SQL_PREPARE ident	{ $$ = make3_str(make1_str("ECPGdeallocate(__LINE__, \""), $3, make1_str("\");")); }
 
-ECPGRelease: TransactionStmt SQL_RELEASE
+/*
+ * variable declaration inside the exec sql declare block
+ */
+ECPGDeclaration: sql_startdeclare
 	{
-		if (strncmp($1, "begin", 5) == 0)
-                        yyerror("RELEASE does not make sense when beginning a transaction");
-
-		fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
+		fputs("/* exec sql begin declare section */", yyout);
+	        output_line_number();
+	}
+	variable_declarations sql_enddeclare
+	{
+		fprintf(yyout, "%s/* exec sql end declare section */", $3);
+		free($3);
+		output_line_number();
+	}
+
+sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {}
+
+sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {}
+
+variable_declarations: /* empty */
+	{
+		$$ = make1_str("");
+	}
+	| declaration variable_declarations
+	{
+		$$ = cat2_str($1, $2);
+	}
+
+declaration: storage_clause
+	{
+		actual_storage[struct_level] = mm_strdup($1);
+	}
+	type
+	{
+		actual_type[struct_level].type_enum = $3.type_enum;
+		actual_type[struct_level].type_dimension = $3.type_dimension;
+		actual_type[struct_level].type_index = $3.type_index;
+	}
+	variable_list ';'
+	{
+ 		$$ = cat4_str($1, $3.type_str, $5, make1_str(";\n"));
+	}
+
+storage_clause : S_EXTERN	{ $$ = make1_str("extern"); }
+       | S_STATIC		{ $$ = make1_str("static"); }
+       | S_SIGNED		{ $$ = make1_str("signed"); }
+       | S_CONST		{ $$ = make1_str("const"); }
+       | S_REGISTER		{ $$ = make1_str("register"); }
+       | S_AUTO			{ $$ = make1_str("auto"); }
+       | /* empty */		{ $$ = make1_str(""); }
+
+type: simple_type
+		{
+			$$.type_enum = $1;
+			$$.type_str = mm_strdup(ECPGtype_name($1));
+			$$.type_dimension = -1;
+  			$$.type_index = -1;
+		}
+	| varchar_type
+		{
+			$$.type_enum = ECPGt_varchar;
+			$$.type_str = make1_str("");
+			$$.type_dimension = -1;
+  			$$.type_index = -1;
+		}
+	| struct_type
+		{
+			$$.type_enum = ECPGt_struct;
+			$$.type_str = $1;
+			$$.type_dimension = -1;
+  			$$.type_index = -1;
+		}
+	| enum_type
+		{
+			$$.type_str = $1;
+			$$.type_enum = ECPGt_int;
+			$$.type_dimension = -1;
+  			$$.type_index = -1;
+		}
+	| symbol
+		{
+			/* this is for typedef'ed types */
+			struct typedefs *this = get_typedef($1);
+
+			$$.type_str = mm_strdup(this->name);
+                        $$.type_enum = this->type->type_enum;
+			$$.type_dimension = this->type->type_dimension;
+  			$$.type_index = this->type->type_index;
+			struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+		}
+
+enum_type: s_enum '{' c_line '}'
+	{
+		$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
+	}
+	
+s_enum: S_ENUM opt_symbol	{ $$ = cat2_str(make1_str("enum"), $2); }
+
+struct_type: s_struct '{' variable_declarations '}'
+	{
+	    ECPGfree_struct_member(struct_member_list[struct_level]);
+	    free(actual_storage[struct_level--]);
+	    $$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
+	}
+
+s_struct : S_STRUCT opt_symbol
+        {
+            struct_member_list[struct_level++] = NULL;
+            if (struct_level >= STRUCT_DEPTH)
+                 yyerror("Too many levels in nested structure definition");
+	    $$ = cat2_str(make1_str("struct"), $2);
+	}
+
+opt_symbol: /* empty */ 	{ $$ = make1_str(""); }
+	| symbol		{ $$ = $1; }
+
+simple_type: S_SHORT		{ $$ = ECPGt_short; }
+           | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
+	   | S_INT 		{ $$ = ECPGt_int; }
+           | S_UNSIGNED S_INT	{ $$ = ECPGt_unsigned_int; }
+	   | S_LONG		{ $$ = ECPGt_long; }
+           | S_UNSIGNED S_LONG	{ $$ = ECPGt_unsigned_long; }
+           | S_FLOAT		{ $$ = ECPGt_float; }
+           | S_DOUBLE		{ $$ = ECPGt_double; }
+	   | S_BOOL		{ $$ = ECPGt_bool; };
+	   | S_CHAR		{ $$ = ECPGt_char; }
+           | S_UNSIGNED S_CHAR	{ $$ = ECPGt_unsigned_char; }
+
+varchar_type:  S_VARCHAR		{ $$ = ECPGt_varchar; }
+
+variable_list: variable 
+	{
+		$$ = $1;
+	}
+	| variable_list ',' variable
+	{
+		$$ = cat3_str($1, make1_str(","), $3);
+	}
+
+variable: opt_pointer symbol opt_array_bounds opt_initializer
+		{
+			struct ECPGtype * type;
+                        int dimension = $3.index1; /* dimension of array */
+                        int length = $3.index2;    /* lenght of string */
+                        char dim[14L], ascii_len[12];
+
+			adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
+
+			switch (actual_type[struct_level].type_enum)
+			{
+			   case ECPGt_struct:
+                               if (dimension < 0)
+                                   type = ECPGmake_struct_type(struct_member_list[struct_level]);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension); 
+
+                               $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+                               break;
+                           case ECPGt_varchar:
+                               if (dimension == -1)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+                               switch(dimension)
+                               {
+                                  case 0:
+                                      strcpy(dim, "[]");
+                                      break;
+				  case -1:
+                                  case 1:
+                                      *dim = '\0';
+                                      break;
+                                  default:
+                                      sprintf(dim, "[%d]", dimension);
+                                      break;
+                               }
+			       sprintf(ascii_len, "%d", length);
+
+                               if (length > 0)
+                                   $$ = make4_str(make5_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2), make1_str(" { int len; char arr["), mm_strdup(ascii_len)), make1_str("]; } "), mm_strdup($2), mm_strdup(dim));
+                               else
+                                   $$ = make4_str(make3_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2)), make1_str(" { int len; char *arr; } "), mm_strdup($2), mm_strdup(dim));
+                               break;
+                           case ECPGt_char:
+                           case ECPGt_unsigned_char:
+                               if (dimension == -1)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+			       $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+                               break;
+                           default:
+                               if (dimension < 0)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
+
+			       $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+                               break;
+			}
+
+			if (struct_level == 0)
+				new_variable($2, type);
+			else
+				ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
+
+			free($2);
+		}
+
+opt_initializer: /* empty */		{ $$ = make1_str(""); }
+	| '=' vartext			{ $$ = make2_str(make1_str("="), $2); }
+
+opt_pointer: /* empty */	{ $$ = make1_str(""); }
+	| '*'			{ $$ = make1_str("*"); }
+
+/*
+ * As long as the prepare statement is not supported by the backend, we will
+ * try to simulate it here so we get dynamic SQL 
+ */
+ECPGDeclare: DECLARE STATEMENT ident
+	{
+		/* this is only supported for compatibility */
+		$$ = cat3_str(make1_str("/* declare statement"), $3, make1_str("*/"));
+	}
+/*
+ * the exec sql disconnect statement: disconnect from the given database 
+ */
+ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
+
+dis_name: connection_object	{ $$ = $1; }
+	| CURRENT	{ $$ = make1_str("CURRENT"); }
+	| ALL		{ $$ = make1_str("ALL"); }
+	| /* empty */	{ $$ = make1_str("CURRENT"); }
+
+connection_object: connection_target { $$ = $1; }
+	| DEFAULT	{ $$ = make1_str("DEFAULT"); }
+
+/*
+ * execute a given string as sql command
+ */
+ECPGExecute : EXECUTE SQL_IMMEDIATE execstring
+	{ 
+		struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+
+		thisquery->type = &ecpg_query;
+		thisquery->brace_level = 0;
+		thisquery->next = NULL;
+		thisquery->name = $3;
+
+		add_variable(&argsinsert, thisquery, &no_indicator); 
+
+		$$ = make1_str(";;");
+	}
+	| EXECUTE ident 
+	{
+		struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+
+		thisquery->type = &ecpg_query;
+		thisquery->brace_level = 0;
+		thisquery->next = NULL;
+		thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2));
+		sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
+
+		add_variable(&argsinsert, thisquery, &no_indicator); 
+	} opt_using
+	{
+		$$ = make1_str(";;");
+	}
+
+execstring: char_variable |
+	CSTRING	 { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); };
+
+/*
+ * the exec sql free command to deallocate a previously
+ * prepared statement
+ */
+ECPGFree:	SQL_FREE ident	{ $$ = $2; }
+
+/*
+ * open is an open cursor, at the moment this has to be removed
+ */
+ECPGOpen: SQL_OPEN name opt_using {
+		$$ = $2;
+};
+
+opt_using: /* empty */		{ $$ = make1_str(""); }
+	| USING variablelist	{
+					/* yyerror ("open cursor with variables not implemented yet"); */
+					$$ = make1_str("");
+				}
+
+variablelist: cinputvariable | cinputvariable ',' variablelist
+
+/*
+ * As long as the prepare statement is not supported by the backend, we will
+ * try to simulate it here so we get dynamic SQL 
+ */
+ECPGPrepare: SQL_PREPARE ident FROM char_variable
+	{
+		$$ = make4_str(make1_str("\""), $2, make1_str("\", "), $4);
+	}
+
+/*
+ * for compatibility with ORACLE we will also allow the keyword RELEASE
+ * after a transaction statement to disconnect from the database.
+ */
+
+ECPGRelease: TransactionStmt SQL_RELEASE
+	{
+		if (strncmp($1, "begin", 5) == 0)
+                        yyerror("RELEASE does not make sense when beginning a transaction");
+
+		fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
 		whenever_action(0);
 		fprintf(yyout, "ECPGdisconnect(\"\");"); 
 		whenever_action(0);
@@ -4642,6 +4955,378 @@ ECPGSetConnection:  SET SQL_CONNECTION connection_object
            		{
 				$$ = $3;
                         }
+
+/*
+ * define a new type for embedded SQL
+ */
+ECPGTypedef: TYPE_P symbol IS ctype opt_type_array_bounds opt_reference
+	{
+		/* add entry to list */
+		struct typedefs *ptr, *this;
+		int dimension = $5.index1;
+		int length = $5.index2;
+
+		for (ptr = types; ptr != NULL; ptr = ptr->next)
+		{
+			if (strcmp($2, ptr->name) == 0)
+			{
+			        /* re-definition is a bug */
+				sprintf(errortext, "type %s already defined", $2);
+				yyerror(errortext);
+	                }
+		}
+
+		adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
+
+        	this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
+
+        	/* initial definition */
+	        this->next = types;
+	        this->name = $2;
+		this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+		this->type->type_enum = $4.type_enum;
+		this->type->type_str = mm_strdup($2);
+		this->type->type_dimension = dimension; /* dimension of array */
+		this->type->type_index = length;    /* lenght of string */
+		this->struct_member_list = struct_member_list[struct_level];
+
+		if ($4.type_enum != ECPGt_varchar &&
+		    $4.type_enum != ECPGt_char &&
+	            $4.type_enum != ECPGt_unsigned_char &&
+		    this->type->type_index >= 0)
+                            yyerror("No multi-dimensional array support for simple data types");
+
+        	types = this;
+
+		$$ = cat5_str(cat3_str(make1_str("/* exec sql type"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
+	}
+
+opt_type_array_bounds:  '[' ']' nest_type_array_bounds
+			{
+                            $$.index1 = 0;
+                            $$.index2 = $3.index1;
+                            $$.str = cat2_str(make1_str("[]"), $3.str);
+                        }
+		| '(' ')' nest_type_array_bounds
+			{
+                            $$.index1 = 0;
+                            $$.index2 = $3.index1;
+                            $$.str = cat2_str(make1_str("[]"), $3.str);
+                        }
+		| '[' Iconst ']' nest_type_array_bounds
+			{
+                            $$.index1 = atol($2);
+                            $$.index2 = $4.index1;
+                            $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+                        }
+		| '(' Iconst ')' nest_type_array_bounds
+			{
+                            $$.index1 = atol($2);
+                            $$.index2 = $4.index1;
+                            $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+                        }
+		| /* EMPTY */
+			{
+                            $$.index1 = -1;
+                            $$.index2 = -1;
+                            $$.str= make1_str("");
+                        }
+		;
+
+nest_type_array_bounds:	'[' ']' nest_type_array_bounds
+                        {
+                            $$.index1 = 0;
+                            $$.index2 = $3.index1;
+                            $$.str = cat2_str(make1_str("[]"), $3.str);
+                        }
+		| '(' ')' nest_type_array_bounds
+                        {
+                            $$.index1 = 0;
+                            $$.index2 = $3.index1;
+                            $$.str = cat2_str(make1_str("[]"), $3.str);
+                        }
+		| '[' Iconst ']' nest_type_array_bounds
+			{
+                            $$.index1 = atol($2);
+                            $$.index2 = $4.index1;
+                            $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+                        }
+		| '(' Iconst ')' nest_type_array_bounds
+			{
+                            $$.index1 = atol($2);
+                            $$.index2 = $4.index1;
+                            $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+                        }
+		| /* EMPTY */
+			{
+                            $$.index1 = -1;
+                            $$.index2 = -1;
+                            $$.str= make1_str("");
+                        }
+                ;
+opt_reference: SQL_REFERENCE { $$ = make1_str("reference"); }
+	| /* empty */ 	     { $$ = make1_str(""); }
+
+ctype: CHAR
+	{
+		$$.type_str = make1_str("char");
+                $$.type_enum = ECPGt_char;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| VARCHAR
+	{
+		$$.type_str = make1_str("varchar");
+                $$.type_enum = ECPGt_varchar;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| FLOAT
+	{
+		$$.type_str = make1_str("float");
+                $$.type_enum = ECPGt_float;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| DOUBLE
+	{
+		$$.type_str = make1_str("double");
+                $$.type_enum = ECPGt_double;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| opt_signed SQL_INT
+	{
+		$$.type_str = make1_str("int");
+       	        $$.type_enum = ECPGt_int;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_ENUM
+	{
+		$$.type_str = make1_str("int");
+       	        $$.type_enum = ECPGt_int;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| opt_signed SQL_SHORT
+	{
+		$$.type_str = make1_str("short");
+       	        $$.type_enum = ECPGt_short;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| opt_signed SQL_LONG
+	{
+		$$.type_str = make1_str("long");
+       	        $$.type_enum = ECPGt_long;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_BOOL
+	{
+		$$.type_str = make1_str("bool");
+       	        $$.type_enum = ECPGt_bool;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_UNSIGNED SQL_INT
+	{
+		$$.type_str = make1_str("unsigned int");
+       	        $$.type_enum = ECPGt_unsigned_int;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_UNSIGNED SQL_SHORT
+	{
+		$$.type_str = make1_str("unsigned short");
+       	        $$.type_enum = ECPGt_unsigned_short;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_UNSIGNED SQL_LONG
+	{
+		$$.type_str = make1_str("unsigned long");
+       	        $$.type_enum = ECPGt_unsigned_long;
+		$$.type_index = -1;
+		$$.type_dimension = -1;
+	}
+	| SQL_STRUCT
+	{
+		struct_member_list[struct_level++] = NULL;
+		if (struct_level >= STRUCT_DEPTH)
+        		yyerror("Too many levels in nested structure definition");
+	} '{' sql_variable_declarations '}'
+	{
+		ECPGfree_struct_member(struct_member_list[struct_level--]);
+		$$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}"));
+		$$.type_enum = ECPGt_struct;
+                $$.type_index = -1;
+                $$.type_dimension = -1;
+	}
+	| symbol
+	{
+		struct typedefs *this = get_typedef($1);
+
+		$$.type_str = mm_strdup($1);
+		$$.type_enum = this->type->type_enum;
+		$$.type_dimension = this->type->type_dimension;
+		$$.type_index = this->type->type_index;
+		struct_member_list[struct_level] = this->struct_member_list;
+	}
+
+opt_signed: SQL_SIGNED | /* empty */
+
+sql_variable_declarations: /* empty */
+	{
+		$$ = make1_str("");
+	}
+	| sql_declaration sql_variable_declarations
+	{
+		$$ = cat2_str($1, $2);
+	}
+	;
+
+sql_declaration: ctype
+	{
+		actual_type[struct_level].type_enum = $1.type_enum;
+		actual_type[struct_level].type_dimension = $1.type_dimension;
+		actual_type[struct_level].type_index = $1.type_index;
+	}
+	sql_variable_list SQL_SEMI
+	{
+		$$ = cat3_str($1.type_str, $3, make1_str(";"));
+	}
+
+sql_variable_list: sql_variable 
+	{
+		$$ = $1;
+	}
+	| sql_variable_list ',' sql_variable
+	{
+		$$ = make3_str($1, make1_str(","), $3);
+	}
+
+sql_variable: opt_pointer symbol opt_array_bounds
+		{
+			int dimension = $3.index1;
+			int length = $3.index2;
+			struct ECPGtype * type;
+                        char dim[14L];
+
+			adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
+
+			switch (actual_type[struct_level].type_enum)
+			{
+			   case ECPGt_struct:
+                               if (dimension < 0)
+                                   type = ECPGmake_struct_type(struct_member_list[struct_level]);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension); 
+
+                               break;
+                           case ECPGt_varchar:
+                               if (dimension == -1)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+                               switch(dimension)
+                               {
+                                  case 0:
+                                      strcpy(dim, "[]");
+                                      break;
+				  case -1:
+                                  case 1:
+                                      *dim = '\0';
+                                      break;
+                                  default:
+                                      sprintf(dim, "[%d]", dimension);
+                                      break;
+                                }
+
+                               break;
+                           case ECPGt_char:
+                           case ECPGt_unsigned_char:
+                               if (dimension == -1)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+                               break;
+                           default:
+			       if (length >= 0)
+                	            yyerror("No multi-dimensional array support for simple data types");
+
+                               if (dimension < 0)
+                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
+                               else
+                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
+
+                               break;
+			}
+
+			if (struct_level == 0)
+				new_variable($2, type);
+			else
+				ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
+
+			$$ = cat3_str($1, $2, $3.str);
+		}
+
+/*
+ * define the type of one variable for embedded SQL
+ */
+ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference
+	{
+		struct variable *p = find_variable($2);
+		int dimension = $5.index1;
+		int length = $5.index2;
+		struct ECPGtype * type;
+
+		adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
+
+		switch ($4.type_enum)
+		{
+		   case ECPGt_struct:
+                        if (dimension < 0)
+                            type = ECPGmake_struct_type(struct_member_list[struct_level]);
+                        else
+                            type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension); 
+                        break;
+                   case ECPGt_varchar:
+                        if (dimension == -1)
+                            type = ECPGmake_simple_type($4.type_enum, length);
+                        else
+                            type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
+
+			break;
+                   case ECPGt_char:
+                   case ECPGt_unsigned_char:
+                        if (dimension == -1)
+                            type = ECPGmake_simple_type($4.type_enum, length);
+                        else
+                            type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
+
+			break;
+		   default:
+			if (length >= 0)
+                	    yyerror("No multi-dimensional array support for simple data types");
+
+                        if (dimension < 0)
+                            type = ECPGmake_simple_type($4.type_enum, 1);
+                        else
+                            type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, 1), dimension);
+
+			break;
+		}	
+
+		ECPGfree_type(p->type);
+		p->type = type;
+
+		$$ = cat5_str(cat3_str(make1_str("/* exec sql var"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
+	}
+
 /*
  * whenever statement: decide what to do in case of error/no data found
  * according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
@@ -4703,14 +5388,6 @@ action : SQL_CONTINUE {
 	$<action>$.str = cat2_str(make1_str("call"), mm_strdup($<action>$.command));
 }
 
-/*
- * As long as the prepare statement in not supported by the backend, we will
- * try to simulate it here so we get dynamic SQL 
- */
-ECPGPrepare: SQL_PREPARE name FROM name
-	{
-	}
-
 /* some other stuff for ecpg */
 ecpg_expr:  attr opt_indirection
 				{
@@ -4987,7 +5664,7 @@ ecpg_expr:  attr opt_indirection
 		| NOT ecpg_expr
 				{	$$ = cat2_str(make1_str("not"), $2); }
 		| civariableonly
-			        { $$ = make1_str(";;"); }
+			        { 	$$ = $1; }
 		;
 
 into_list : coutputvariable | into_list ',' coutputvariable;
@@ -5010,6 +5687,7 @@ cinputvariable : cvariable indicator {
 
 civariableonly : cvariable {
 		add_variable(&argsinsert, find_variable($1), &no_indicator); 
+		$$ = make1_str(";;");
 }
 
 cvariable: CVARIABLE			{ $$ = $1; }
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 52cc8f8087a4e42e882c9175b290327eb55235d1..dd3546b50ad83ea186461a496e5ba17fe9c9d412 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -2,7 +2,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include "type.h"
 #include "extern.h"
 
 /* malloc + error check */
@@ -36,8 +35,8 @@ mm_strdup(const char *string)
 }
 
 /* duplicate memberlist */
-static struct ECPGstruct_member *
-struct_member_dup(struct ECPGstruct_member * rm)
+struct ECPGstruct_member *
+ECPGstruct_member_dup(struct ECPGstruct_member * rm)
 {
 	struct ECPGstruct_member *new = NULL;
 
@@ -71,7 +70,8 @@ void
 ECPGmake_struct_member(char *name, struct ECPGtype * type, struct ECPGstruct_member ** start)
 {
 	struct ECPGstruct_member *ptr,
-			   *ne = (struct ECPGstruct_member *) mm_alloc(sizeof(struct ECPGstruct_member));
+			   *ne =
+	(struct ECPGstruct_member *) mm_alloc(sizeof(struct ECPGstruct_member));
 
 	ne->name = strdup(name);
 	ne->typ = type;
@@ -112,7 +112,7 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm)
 {
 	struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_struct, 1);
 
-	ne->u.members = struct_member_dup(rm);
+	ne->u.members = ECPGstruct_member_dup(rm);
 
 	return ne;
 }
@@ -160,6 +160,9 @@ get_type(enum ECPGttype typ)
 		case ECPGt_NO_INDICATOR:		/* no indicator */
 			return ("ECPGt_NO_INDICATOR");
 			break;
+		case ECPGt_char_variable:			/* string that should not be quoted */
+			return ("ECPGt_char_variable");
+			break;
 		default:
 			abort();
 	}
@@ -202,23 +205,30 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
 			{
 				ECPGdump_a_simple(o, name, typ->u.element->typ,
 						  typ->u.element->size, typ->size, NULL, prefix);
-				if (ind_typ == &ecpg_no_indicator)
+				if (ind_typ->typ == ECPGt_NO_INDICATOR)
 					ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
 				else
+				{
+					if (ind_typ->typ != ECPGt_array)
+					{
+						fprintf(stderr, "Indicator for an array has to be array too.\n");
+					        exit(INDICATOR_NOT_ARRAY);
+					}                	
 					ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
 									  ind_typ->u.element->size, ind_typ->size, NULL, prefix);
+				}
 			}
 			else if (typ->u.element->typ == ECPGt_array)
 			{
-				yyerror("No nested arrays allowed (except strings)");	/* Array of array, */
+				yyerror("No nested arrays allowed (except strings)");	/* array of array */
 			}
 			else if (typ->u.element->typ == ECPGt_struct)
 			{
-				/* Array of structs. */
+				/* Array of structs */
 				ECPGdump_a_struct(o, name, ind_name, typ->size, typ->u.element, ind_typ->u.element, NULL, prefix, ind_prefix);
 			}
 			else
-				yyerror("Internal error: unknown datatype, pleqase inform pgsql-bugs@postgresql.org");
+				yyerror("Internal error: unknown datatype, please inform pgsql-bugs@postgresql.org");
 			break;
 		case ECPGt_struct:
 			ECPGdump_a_struct(o, name, ind_name, 1, typ, ind_typ, NULL, prefix, ind_prefix);
@@ -260,6 +270,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
 				break;
 			case ECPGt_char:
 			case ECPGt_unsigned_char:
+			case ECPGt_char_variable:
 				sprintf(offset, "%ld*sizeof(char)", varcharsize);
 				break;
 			default:
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index f5c5941c1308b7bba225d44eef584c8ecfcbeec9..f9642d92766e922b74c12454201b615e5cb2f09c 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -30,6 +30,7 @@ struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, long);
 struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long);
 struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, long);
 struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *);
+struct ECPGstruct_member * ECPGstruct_member_dup(struct ECPGstruct_member *);
 
 /* Frees a type. */
 void		ECPGfree_struct_member(struct ECPGstruct_member *);
@@ -84,6 +85,54 @@ struct index
 
 struct this_type
 {
-	enum ECPGttype type_enum;
-	char	   *type_str;
+	enum ECPGttype 	type_enum;
+	char	   	*type_str;
+	int		type_dimension;
+	int		type_index;
+};
+
+struct _include_path
+{
+	char	   *path;
+	struct _include_path *next;
+};
+
+struct cursor
+{
+	char	   *name;
+	char	   *command;
+	struct arguments *argsinsert;
+	struct arguments *argsresult;
+	struct cursor *next;
+};
+
+struct typedefs
+{
+	char       *name;
+	struct this_type  *type;
+	struct ECPGstruct_member *struct_member_list;
+	struct typedefs *next;
+};
+
+struct _defines
+{
+	char	   *old;
+	char	   *new;
+	struct _defines *next;
+};
+
+/* This is a linked list of the variable names and types. */
+struct variable
+{
+	char	   *name;
+	struct ECPGtype *type;
+	int			brace_level;
+	struct variable *next;
+};
+
+struct arguments
+{
+	struct variable *variable;
+	struct variable *indicator;
+	struct arguments *next;
 };
diff --git a/src/interfaces/ecpg/test/test1.pgc b/src/interfaces/ecpg/test/test1.pgc
index fde066a668e04c776de449f79ea3c03975b68991..ac2dbdc04e165ded68688c8da6b99e780dcabeb8 100644
--- a/src/interfaces/ecpg/test/test1.pgc
+++ b/src/interfaces/ecpg/test/test1.pgc
@@ -4,16 +4,25 @@ exec sql whenever sqlerror sqlprint;
 
 exec sql include sqlca;
 
-exec sql define AMOUNT 5;
+exec sql define AMOUNT 8;
+
+exec sql type intarray is int[AMOUNT];
+exec sql type string is char(6); 
+
+typedef int intarray[AMOUNT];
 
 int
 main ()
 {
 exec sql begin declare section;
-        int amount[AMOUNT];
-        char name[AMOUNT][8];
+        intarray amount;
+	int increment=100;
+        char name[AMOUNT][6];
+	char letter[AMOUNT][1];
+	char command[128];
 exec sql end declare section;
-	char msg[128], command[128];
+	exec sql var name is string(AMOUNT);
+	char msg[128];
         FILE *dbgs;
         int i,j;
 
@@ -24,30 +33,40 @@ exec sql end declare section;
 	exec sql connect to mm;
 
 	strcpy(msg, "create");
-	exec sql create table test(name char(8), amount int);
+	exec sql create table test(name char(6), amount int, letter char(1));
+
+	strcpy(msg, "commit");
+	exec sql commit;
 
 	strcpy(msg, "execute insert 1");
-        sprintf(command, "insert into test(name, amount) values ('foobar', 1)");
+        sprintf(command, "insert into test(name, amount, letter) values ('foobar', 1, 'f')");
         exec sql execute immediate :command;
 
-        strcpy(msg, "excute insert 2");
-        sprintf(command, "insert into test(name, amount) select name, amount+1 from test");
+        strcpy(msg, "execute insert 2");
+        sprintf(command, "insert into test(name, amount, letter) select name, amount+1, letter from test");
         exec sql execute immediate :command;
 
-        strcpy(msg, "excute insert 3");
-        sprintf(command, "insert into test(name, amount) select name, amount+10 from test");
+        strcpy(msg, "execute insert 3");
+        sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test");
         exec sql execute immediate :command;
         
 	printf("Inserted %d tuples via execute immediate\n", sqlca.sqlerrd[2]);
 
+        strcpy(msg, "execute insert 4");
+        sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
+	exec sql prepare I from :command;
+        exec sql execute I using :increment;
+        
+	printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
+
 	strcpy(msg, "commit");
 	exec sql commit;
 
         strcpy(msg, "select");
-        exec sql select name, amount into :name, :amount from test;
+        exec sql select name, amount, letter into :name, :amount, :letter from test;
 
         for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
-            printf("name[%d]=%8.8s, amount[%d]=%d\n", i, name[i], i, amount[i]);
+            printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
         
 	strcpy(msg, "drop");
 	exec sql drop table test;
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index 5b06c0390e578c80a29aaab3c76021b0dc20e022..ed06f179bc488b4d4d90badc733f6cb0214a09e8 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -2,26 +2,31 @@
 
 exec sql include header_test;
 
+exec sql type c is char reference;
+typedef char* c;
+
 int
 main ()
 {
+	typedef struct { long born; short age; } birthinfo;
+	exec sql type birthinfo is struct { long born; short age; };
 exec sql begin declare section;
 	struct personal_struct	{	varchar name[8];
-					struct birth_struct {	long born;
-								short age;
-					} birth;
+					birthinfo birth;
 				} personal;
-	struct personal_indicator {	short ind_name;
-					struct birth_indicator {	short ind_born;
-									int ind_age;
-					} ind_birth;
+	struct personal_indicator {	int ind_name;
+					birthinfo ind_birth;
 				  } ind_personal;
-	long ind_married;
+	int ind_married;
 	char married[9];
+	c testname="Petra";
+	char *query="select name, born, age, married from meskes where name = :var1";
 exec sql end declare section;
 
-exec sql declare cur cursor for
-       select name, born, age, married from meskes;
+	exec sql var ind_married is long;
+
+	exec sql declare cur cursor for
+	       select name, born, age, married from meskes;
 
 	char msg[128], command[128];
 	FILE *dbgs;
@@ -36,11 +41,11 @@ exec sql declare cur cursor for
 	exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
 
 	strcpy(msg, "insert");
-	exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 32, '19900404');
+	exec sql insert into meskes(name, married) values ('Petra', '19900404');
 	exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404');
-	exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7);
-	exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4);
-	exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0);
+	exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 8);
+	exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5);
+	exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1);
 
 	strcpy(msg, "commit");
 	exec sql commit;
@@ -53,12 +58,44 @@ exec sql declare cur cursor for
 	while (1) {
 		strcpy(msg, "fetch");
 		exec sql fetch in cur into :personal:ind_personal, :married:ind_married;
-                printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
+		printf("%8.8s", personal.name.arr);
+		if (!ind_personal.ind_birth.born)
+			printf(", born %d", personal.birth.born);
+		if (!ind_personal.ind_birth.age)
+			printf(", age = %d", personal.birth.age);
+		if (!ind_married)
+			printf(", married %s", married);
+		putchar('\n');
 	}
 
 	strcpy(msg, "close");
 	exec sql close cur;
 
+	/* and now the same query with prepare */
+	exec sql prepare MM from :query;
+	exec sql declare prep cursor for MM;
+
+	strcpy(msg, "open");
+	exec sql open prep using :testname;
+
+	exec sql whenever not found do break;
+
+	while (1) {
+		strcpy(msg, "fetch");
+		exec sql fetch in prep into :personal:ind_personal, :married:ind_married;
+		printf("%8.8s", personal.name.arr);
+		if (!ind_personal.ind_birth.born)
+			printf(", born %d", personal.birth.born);
+		if (!ind_personal.ind_birth.age)
+			printf(", age = %d", personal.birth.age);
+		if (!ind_married)
+			printf(", married %s", married);
+		putchar('\n');
+	}
+
+	strcpy(msg, "close");
+	exec sql close prep;
+
 	strcpy(msg, "drop");
 	exec sql drop table meskes;