diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 3d5828f6ba..157f219a30 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -809,5 +809,10 @@ Tue Feb 15 17:39:19 CET 2000
 Wed Feb 16 11:57:02 CET 2000
 
 	- Fixed library to be able to input complete arrays.
+
+Wed Feb 16 17:04:41 CET 2000
+
+	- Apply patch by Christof Petig <christof.petig@wtal.de> that adds
+	  descriptors.
 	- Set library version to 3.1.0.
 	- Set ecpg version to 2.7.0.
diff --git a/src/interfaces/ecpg/README.dynSQL b/src/interfaces/ecpg/README.dynSQL
new file mode 100644
index 0000000000..fedcf80402
--- /dev/null
+++ b/src/interfaces/ecpg/README.dynSQL
@@ -0,0 +1,20 @@
+descriptor statements have the following shortcomings
+
+- up to now the only reasonable statement is
+	FETCH ... INTO SQL DESCRIPTOR <name>
+  no input variables allowed!
+  
+  Reason: to fully support dynamic SQL the frontend/backend communication
+  	should change to recognize input parameters.
+  	Since this is not likely to happen in the near future and you
+  	can cover the same functionality with the existing infrastructure
+  	I'll leave the work to someone else.
+
+- string buffer overflow does not always generate warnings 
+	(beware: terminating 0 may be missing because strncpy is used)
+	:var=data sets sqlwarn accordingly (but not indicator)
+
+- char variables pointing to NULL are not allocated on demand
+	
+- string truncation does not show up in indicator
+
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 542894945d..747a87ac3f 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -18,8 +18,6 @@ cvariable for an array var
 
 How can one insert arrays from c variables?
 
-support for dynamic SQL with unknown number of variables with DESCRIPTORS
-
 What happens to the output variable during read if there was an
 indicator-error? 
 
diff --git a/src/interfaces/ecpg/include/Makefile b/src/interfaces/ecpg/include/Makefile
index db0ea7954e..6ab79fd856 100644
--- a/src/interfaces/ecpg/include/Makefile
+++ b/src/interfaces/ecpg/include/Makefile
@@ -10,11 +10,13 @@ install::
 	$(INSTALL) $(INSTLOPTS) ecpglib.h $(HEADERDIR)	
 	$(INSTALL) $(INSTLOPTS) ecpgtype.h $(HEADERDIR)	
 	$(INSTALL) $(INSTLOPTS) sqlca.h $(HEADERDIR)	
+	$(INSTALL) $(INSTLOPTS) sql3types.h $(HEADERDIR)	
 
 uninstall::
 	rm -f $(HEADERDIR)/ecpgerrno.h
 	rm -f $(HEADERDIR)/ecpglib.h
 	rm -f $(HEADERDIR)/ecpgtype.h
 	rm -f $(HEADERDIR)/sqlca.h
+	rm -f $(HEADERDIR)/sql3types.h
 
 dep depend:
diff --git a/src/interfaces/ecpg/include/ecpgerrno.h b/src/interfaces/ecpg/include/ecpgerrno.h
index db2618f31d..429703a29c 100644
--- a/src/interfaces/ecpg/include/ecpgerrno.h
+++ b/src/interfaces/ecpg/include/ecpgerrno.h
@@ -29,6 +29,10 @@
 
 #define ECPG_INVALID_STMT	-230
 
+/* dynamic SQL related */
+#define ECPG_UNKNOWN_DESCRIPTOR	-240
+#define ECPG_INVALID_DESCRIPTOR_INDEX	-241
+
 /* 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 9ceb691695..f50a2bb09d 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -1,4 +1,5 @@
 #include <postgres.h>
+#include <libpq-fe.h>
 
 #ifdef __cplusplus
 extern		"C"
@@ -49,6 +50,17 @@ extern		"C"
 
 #define		  SQLCODE	 sqlca.sqlcode
 
+/* dynamic SQL */
+
+	unsigned int	ECPGDynamicType(Oid type);
+	unsigned int	ECPGDynamicType_DDT(Oid type);
+	PGresult *		ECPGresultByDescriptor(int line,const char *name);
+	bool			ECPGdo_descriptor(int line,const char *connection,
+							const char *descriptor,const char *query);
+	bool			ECPGdeallocate_desc(int line,const char *name);
+	bool			ECPGallocate_desc(int line,const char *name);
+	void			ECPGraise(int line,int code);
+
 #ifdef __cplusplus
 }
 
diff --git a/src/interfaces/ecpg/include/sql3types.h b/src/interfaces/ecpg/include/sql3types.h
new file mode 100644
index 0000000000..c844975b4a
--- /dev/null
+++ b/src/interfaces/ecpg/include/sql3types.h
@@ -0,0 +1,38 @@
+/* SQL3 dynamic type codes
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/include/sql3types.h,v 1.1 2000/02/16 16:18:03 meskes Exp $
+ */
+
+/* chapter 13.1 table 2: Codes used for SQL data types in Dynamic SQL */
+
+enum { 	SQL3_CHARACTER=1,
+	SQL3_NUMERIC,
+	SQL3_DECIMAL,
+	SQL3_INTEGER,
+	SQL3_SMALLINT,
+	SQL3_FLOAT,
+	SQL3_REAL,
+	SQL3_DOUBLE_PRECISION,
+	SQL3_DATE_TIME_TIMESTAMP,
+	SQL3_INTERVAL, //10
+	SQL3_CHARACTER_VARYING=12,
+	SQL3_ENUMERATED,
+	SQL3_BIT,
+	SQL3_BIT_VARYING,
+	SQL3_BOOLEAN,
+	SQL3_abstract
+	// the rest is xLOB stuff
+     };
+
+/* chapter 13.1 table 3: Codes associated with datetime data types in Dynamic SQL */
+
+enum {	SQL3_DDT_DATE=1,
+	SQL3_DDT_TIME,
+	SQL3_DDT_TIMESTAMP,
+	SQL3_DDT_TIME_WITH_TIME_ZONE,
+	SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE,
+	
+	SQL3_DDT_ILLEGAL /* not a datetime data type (not part of standard) */
+     };
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index 296c3c5a40..947f9fd1a9 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -6,7 +6,7 @@
 # Copyright (c) 1994, Regents of the University of California
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.57 2000/02/16 11:52:24 meskes Exp $
+#    $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.58 2000/02/16 16:18:05 meskes Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -36,7 +36,7 @@ include $(SRCDIR)/Makefile.shlib
 install: install-lib $(install-shlib-dep)
 
 # Handmade dependencies in case make depend not done
-ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
+ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h dynamic.c
 typename.o : typename.c ../include/ecpgtype.h
 
 
diff --git a/src/interfaces/ecpg/lib/dynamic.c b/src/interfaces/ecpg/lib/dynamic.c
new file mode 100644
index 0000000000..ec8e927d64
--- /dev/null
+++ b/src/interfaces/ecpg/lib/dynamic.c
@@ -0,0 +1,290 @@
+/* dynamic SQL support routines
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.1 2000/02/16 16:18:12 meskes Exp $
+ */
+
+/* I borrowed the include files from ecpglib.c, maybe we don't need all of them */
+
+#if 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+
+#include <libpq-fe.h>
+#include <libpq/pqcomm.h>
+#include <ecpgtype.h>
+#include <ecpglib.h>
+#include <sqlca.h>
+#endif
+#include <sql3types.h>
+
+static struct descriptor
+{	char *name;
+	PGresult *result;
+	struct descriptor *next;
+} *all_descriptors=NULL;
+
+PGconn *ECPG_internal_get_connection(char *name);
+
+unsigned int ECPGDynamicType(Oid type)
+{	switch(type)
+	{	case 16:	return SQL3_BOOLEAN;	/* bool */
+		case 21:	return SQL3_SMALLINT;	/* int2 */
+		case 23:	return SQL3_INTEGER;	/* int4 */
+		case 25:	return SQL3_CHARACTER;	/* text */
+		case 700:	return SQL3_REAL;		/* float4 */
+		case 701:	return SQL3_DOUBLE_PRECISION;	/* float8 */
+		case 1042:	return SQL3_CHARACTER;	/* bpchar */
+		case 1043:	return SQL3_CHARACTER_VARYING;	/* varchar */
+		case 1082:	return SQL3_DATE_TIME_TIMESTAMP;	/* date */
+		case 1083:	return SQL3_DATE_TIME_TIMESTAMP;	/* time */
+		case 1184:	return SQL3_DATE_TIME_TIMESTAMP;	/* datetime */
+		case 1296:	return SQL3_DATE_TIME_TIMESTAMP;	/* timestamp */
+		case 1700:	return SQL3_NUMERIC;	/* numeric */
+		default:
+			return -type;
+	}
+}
+
+unsigned int ECPGDynamicType_DDT(Oid type)
+{	switch(type)
+	{	
+		case 1082:	return SQL3_DDT_DATE;	/* date */
+		case 1083:	return SQL3_DDT_TIME;	/* time */
+		case 1184:	return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;	/* datetime */
+		case 1296:	return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE;	/* timestamp */
+		default:
+			return SQL3_DDT_ILLEGAL;
+	}
+}
+
+// like ECPGexecute
+static bool execute_descriptor(int lineno,const char *query
+							,struct connection *con,PGresult **resultptr)
+{
+	bool	status = false;
+	PGresult   *results;
+	PGnotify   *notify;
+	
+	/* Now the request is built. */
+
+	if (con->committed && !con->autocommit)
+	{
+		if ((results = PQexec(con->connection, "begin transaction")) == NULL)
+		{
+			register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
+			return false;
+		}
+		PQclear(results);
+		con->committed = false;
+	}
+
+	ECPGlog("execute_descriptor line %d: QUERY: %s on connection %s\n", lineno, query, con->name);
+	results = PQexec(con->connection, query);
+
+	if (results == NULL)
+	{
+		ECPGlog("ECPGexecute line %d: error: %s", lineno,
+				PQerrorMessage(con->connection));
+		register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+			 PQerrorMessage(con->connection), lineno);
+	}
+	else
+	{	*resultptr=results;
+		switch (PQresultStatus(results))
+		{	int ntuples;
+			case PGRES_TUPLES_OK:
+				status = true;
+				sqlca.sqlerrd[2] = ntuples = PQntuples(results);
+				if (ntuples < 1)
+				{
+					ECPGlog("execute_descriptor line %d: Incorrect number of matches: %d\n",
+							lineno, ntuples);
+					register_error(ECPG_NOT_FOUND, "No data found line %d.", lineno);
+					status = false;
+					break;
+				}
+				break;
+#if 1 /* strictly these are not needed (yet) */
+			case PGRES_EMPTY_QUERY:
+				/* do nothing */
+				register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
+				break;
+			case PGRES_COMMAND_OK:
+				status = true;
+				sqlca.sqlerrd[1] = atol(PQoidStatus(results));
+				sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
+				ECPGlog("ECPGexecute line %d Ok: %s\n", lineno, PQcmdStatus(results));
+				break;
+			case PGRES_COPY_OUT:
+				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
+				PQendcopy(con->connection);
+				break;
+			case PGRES_COPY_IN:
+				ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", lineno);
+				PQendcopy(con->connection);
+				break;
+#else
+			case PGRES_EMPTY_QUERY:
+			case PGRES_COMMAND_OK:
+			case PGRES_COPY_OUT:
+			case PGRES_COPY_IN:
+				break;
+#endif
+			case PGRES_NONFATAL_ERROR:
+			case PGRES_FATAL_ERROR:
+			case PGRES_BAD_RESPONSE:
+				ECPGlog("ECPGexecute line %d: Error: %s",
+						lineno, PQerrorMessage(con->connection));
+				register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+							   PQerrorMessage(con->connection), lineno);
+				status = false;
+				break;
+			default:
+				ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
+						lineno);
+				register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
+							   PQerrorMessage(con->connection), lineno);
+				status = false;
+				break;
+		}
+	}
+
+	/* check for asynchronous returns */
+	notify = PQnotifies(con->connection);
+	if (notify)
+	{
+		ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+				lineno, notify->relname, notify->be_pid);
+		free(notify);
+	}
+	return status;
+}
+
+/* like ECPGdo */
+static bool do_descriptor2(int lineno,const char *connection_name,
+					PGresult **resultptr, const char *query)
+{
+	struct connection *con = get_connection(connection_name);
+	bool		status=true;
+	char *locale = setlocale(LC_NUMERIC, NULL);
+
+	/* Make sure we do NOT honor the locale for numeric input/output */
+	/* since the database wants teh standard decimal point */
+	setlocale(LC_NUMERIC, "C");
+
+	if (!ecpg_init(con, connection_name, lineno))
+	{	setlocale(LC_NUMERIC, locale);
+		return(false);
+	}
+
+	/* are we connected? */
+	if (con == NULL || con->connection == NULL)
+	{
+		ECPGlog("ECPGdo: not connected to %s\n", con->name);
+		register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
+		setlocale(LC_NUMERIC, locale);
+		return false;
+	}
+
+	status = execute_descriptor(lineno,query,con,resultptr);
+
+	/* and reset locale value so our application is not affected */
+	setlocale(LC_NUMERIC, locale);
+	return (status);
+}
+
+bool ECPGdo_descriptor(int line,const char *connection,
+							const char *descriptor,const char *query)
+{
+	struct descriptor *i;
+	for (i=all_descriptors;i!=NULL;i=i->next)
+	{	if (!strcmp(descriptor,i->name)) 
+	    {	
+			bool status;
+
+			/* free previous result */
+			if (i->result) PQclear(i->result);
+	    	i->result=NULL;
+	    	
+			status=do_descriptor2(line,connection,&i->result,query);
+			
+			if (!i->result) PQmakeEmptyPGresult(NULL, 0);
+			return (status);
+	    }
+	}
+	ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+	return false;
+}
+							
+PGresult *ECPGresultByDescriptor(int line,const char *name)
+{
+	struct descriptor *i;
+	for (i=all_descriptors;i!=NULL;i=i->next)
+	{	if (!strcmp(name,i->name)) return i->result;
+	}
+	ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+	return 0;
+} 
+
+
+bool ECPGdeallocate_desc(int line,const char *name)
+{
+	struct descriptor *i;
+	struct descriptor **lastptr=&all_descriptors;
+	for (i=all_descriptors;i;lastptr=&i->next,i=i->next)
+	{	if (!strcmp(name,i->name))
+		{	*lastptr=i->next;
+			free(i->name);
+			PQclear(i->result);
+			free(i);
+			return true;
+		}
+	}
+	ECPGraise(line,ECPG_UNKNOWN_DESCRIPTOR);
+	return false;
+} 
+
+bool ECPGallocate_desc(int line,const char *name)
+{
+	struct descriptor *new=(struct descriptor *)malloc(sizeof(struct descriptor));
+	
+	new->next=all_descriptors;
+	new->name=malloc(strlen(name)+1);
+	new->result=PQmakeEmptyPGresult(NULL, 0);
+	strcpy(new->name,name);
+	all_descriptors=new;
+	return true;
+}
+
+void ECPGraise(int line,int code)
+{	sqlca.sqlcode=code;
+	switch (code)
+	{ 	case ECPG_NOT_FOUND: 
+			snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+				"No data found line %d.",line);
+			break;
+		case ECPG_MISSING_INDICATOR: 
+			snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+				"NULL value without indicator, line %d.",line);
+			break;
+		case ECPG_UNKNOWN_DESCRIPTOR: 
+			snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+				"descriptor not found, line %d.",line);
+			break;
+		case ECPG_INVALID_DESCRIPTOR_INDEX: 
+			snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+				"descriptor index out of range, line %d.",line);
+			break;
+	    default:
+	    	snprintf(sqlca.sqlerrm.sqlerrmc,sizeof(sqlca.sqlerrm.sqlerrmc),
+				"SQL error #%d, line %d.",code,line);
+			break;
+	}
+}
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 5074bc20e0..a6e2b23e01 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -20,7 +20,6 @@
 #include <ctype.h>
 #include <locale.h>
 
-#include <libpq-fe.h>
 #include <libpq/pqcomm.h>
 #include <ecpgtype.h>
 #include <ecpglib.h>
@@ -753,7 +752,7 @@ ECPGexecute(struct statement * stmt)
 				{
 					char	   *pval;
 					char	   *scan_length;
-					char       *array_query;
+					char	   *array_query;
 					
 					if (var == NULL)
 					{
@@ -1127,36 +1126,44 @@ ECPGexecute(struct statement * stmt)
 bool
 ECPGdo(int lineno, const char *connection_name, char *query,...)
 {
-	va_list		args;
-	struct statement *stmt;
-	struct connection *con = get_connection(connection_name);
-	bool		status;
-	char *locale = setlocale(LC_NUMERIC, NULL);
+	va_list			args;
+	struct statement 	*stmt;
+	struct connection 	*con = get_connection(connection_name);
+	bool			status=true;
+	char 			*locale = setlocale(LC_NUMERIC, NULL);
 
 	/* Make sure we do NOT honor the locale for numeric input/output */
 	/* since the database wants teh standard decimal point */
 	setlocale(LC_NUMERIC, "C");
 
 	if (!ecpg_init(con, connection_name, lineno))
+	{
+		setlocale(LC_NUMERIC, locale);
 		return(false);
+	}
 
 	va_start(args, query);
 	if (create_statement(lineno, con, &stmt, query, args) == false)
+	{
+		setlocale(LC_NUMERIC, locale);
 		return (false);
+	}
 	va_end(args);
 
 	/* are we connected? */
 	if (con == NULL || con->connection == NULL)
 	{
+		free_statement(stmt);
 		ECPGlog("ECPGdo: not connected to %s\n", con->name);
 		register_error(ECPG_NOT_CONN, "Not connected in line %d.", lineno);
+		setlocale(LC_NUMERIC, locale);
 		return false;
 	}
 
 	status = ECPGexecute(stmt);
 	free_statement(stmt);
 
-	/* and reser value so our application is not affected */
+	/* and reset locale value so our application is not affected */
 	setlocale(LC_NUMERIC, locale);
 	return (status);
 }
@@ -1508,3 +1515,5 @@ ECPGprepared_statement(char *name)
 	for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
 	return (this) ? this->stmt->command : NULL;
 }
+
+#include "dynamic.c"
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 89676e7c34..0cc7699a6d 100644
--- a/src/interfaces/ecpg/preproc/ecpg_keywords.c
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -19,6 +19,7 @@
  */
 static ScanKeyword ScanKeywords[] = {
 	/* name					value			*/
+	{"allocate", SQL_ALLOCATE},
 	{"at", SQL_AT},
 	{"autocommit", SQL_AUTOCOMMIT},
 	{"bool", SQL_BOOL},
@@ -28,10 +29,12 @@ static ScanKeyword ScanKeywords[] = {
 	{"connection", SQL_CONNECTION},
 	{"continue", SQL_CONTINUE},
 	{"deallocate", SQL_DEALLOCATE},
+	{"descriptor", SQL_DESCRIPTOR},
 	{"disconnect", SQL_DISCONNECT},
 	{"enum", SQL_ENUM},
 	{"found", SQL_FOUND},
 	{"free", SQL_FREE},
+	{"get", SQL_GET},
 	{"go", SQL_GO},
 	{"goto", SQL_GOTO},
 	{"identified", SQL_IDENTIFIED},
@@ -46,12 +49,14 @@ static ScanKeyword ScanKeywords[] = {
 	{"section", SQL_SECTION},
 	{"short", SQL_SHORT},
 	{"signed", SQL_SIGNED},
+	{"sql",SQL_SQL}, // strange thing, used for into sql descriptor MYDESC;
 	{"sqlerror", SQL_SQLERROR},
 	{"sqlprint", SQL_SQLPRINT},
 	{"sqlwarning", SQL_SQLWARNING},
 	{"stop", SQL_STOP},
 	{"struct", SQL_STRUCT},
 	{"unsigned", SQL_UNSIGNED},
+	{"value", SQL_VALUE},
 	{"var", SQL_VAR},
 	{"whenever", SQL_WHENEVER},
 };
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index 682ead43ec..2a1da562a7 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -29,6 +29,7 @@ extern struct arguments *argsinsert;
 extern struct arguments *argsresult;
 extern struct when when_error, when_nf, when_warn;
 extern struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH];
+extern struct descriptor *descriptors;
 
 /* functions */
 
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 8abcec55e5..0c492febf0 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -23,6 +23,8 @@
 int	struct_level = 0;
 char	errortext[128];
 static char	*connection = NULL;
+static char *descriptor_name = NULL;
+static char *descriptor_index= NULL;
 static int      QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
 static int	FoundSort = 0;
 static int	initializer = 0;
@@ -38,6 +40,11 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
 
 struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
 
+/* variable lookup */
+
+static struct variable * find_variable(char * name);
+static void whenever_action(int mode);
+
 /*
  * Handle parsing errors and warnings
  */
@@ -80,6 +87,275 @@ output_simple_statement(char *cmd)
         free(cmd);
 }
 
+/*
+ * assignment handling function (descriptor)
+ */
+ 
+static struct assignment *assignments;
+
+static void push_assignment(char *var,char *value)
+{
+	struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment));
+	
+	new->next=assignments;
+	new->variable=mm_alloc(strlen(var)+1);
+	strcpy(new->variable,var);
+	new->value=mm_alloc(strlen(value)+1);
+	strcpy(new->value,value);
+	assignments=new;
+}
+
+static void drop_assignments(void)
+{	while (assignments)
+	{	struct assignment *old_head=assignments;
+		assignments=old_head->next;
+		free(old_head->variable);
+		free(old_head->value);
+		free(old_head);
+	}
+}
+
+/* XXX: these should be more accurate (consider ECPGdump_a_* ) */
+static void ECPGnumeric_lvalue(FILE *f,char *name)
+{	const struct variable *v=find_variable(name);
+	switch(v->type->typ)
+	{	case ECPGt_short:
+		case ECPGt_int: 
+		case ECPGt_long:
+		case ECPGt_unsigned_short:
+		case ECPGt_unsigned_int:
+		case ECPGt_unsigned_long:
+			fputs(name,yyout);
+			break;
+		default:
+			snprintf(errortext,sizeof errortext,"variable %s: numeric type needed"
+					,name);
+			mmerror(ET_ERROR,errortext);
+			break;
+	}
+}
+
+static void ECPGstring_buffer(FILE *f,char *name)
+{   const struct variable *v=find_variable(name);
+	switch(v->type->typ)
+	{	case ECPGt_varchar:
+			fprintf(yyout,"%s.arr",name);
+			break;
+			
+		case ECPGt_char:
+		case ECPGt_unsigned_char:
+			fputs(name,yyout);
+			break;
+			
+		default:
+			snprintf(errortext,sizeof errortext,"variable %s: character type needed"
+					,name);
+			mmerror(ET_ERROR,errortext);
+			break;
+	}
+}
+
+static void ECPGstring_length(FILE *f,char *name)
+{   const struct variable *v=find_variable(name);
+	switch(v->type->typ)
+	{	case ECPGt_varchar:
+		case ECPGt_char:
+		case ECPGt_unsigned_char:
+		    if (!v->type->size) 
+		    {	snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment",
+		    									v->name);
+		    	mmerror(ET_ERROR,errortext);
+		    }
+			fprintf(yyout,"%ld",v->type->size);
+			break;
+		default:
+			snprintf(errortext,sizeof errortext,"variable %s: character type needed"
+					,name);
+			mmerror(ET_ERROR,errortext);
+			break;
+	}
+}
+
+static void ECPGdata_assignment(char *variable,char *index_plus_1)
+{	const struct variable *v=find_variable(variable);
+	fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1);
+	switch(v->type->typ)
+	{	case ECPGt_short:
+		case ECPGt_int: /* use the same conversion as ecpglib does */
+		case ECPGt_long:
+			fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
+											,variable,index_plus_1);
+			break;
+		case ECPGt_unsigned_short:
+		case ECPGt_unsigned_int:
+		case ECPGt_unsigned_long:
+			fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n"
+											,variable,index_plus_1);
+			break;
+		case ECPGt_float:
+		case ECPGt_double:
+			fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n"
+											,variable,index_plus_1);
+			break;
+			
+		case ECPGt_bool:
+			fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n"
+											,variable,index_plus_1);
+			break;
+		
+		case ECPGt_varchar:
+			fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
+											,variable,index_plus_1,v->type->size);
+			fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n"
+											,variable,index_plus_1);
+			fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
+											,variable,v->type->size,variable,v->type->size);
+			fputs("\t\t\t}\n",yyout);											
+			break;
+			
+		case ECPGt_char:
+		case ECPGt_unsigned_char:
+		    if (!v->type->size) 
+		    {	snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment",
+		    									v->name);
+		    	mmerror(ET_ERROR,errortext);
+		    }
+			fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n"
+											,variable,index_plus_1,v->type->size);
+			fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n"
+				"\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n"
+											,index_plus_1,v->type->size,variable,v->type->size-1);
+			fputs("\t\t\t}\n",yyout);											
+			break;
+			
+		default:
+			snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment"
+					,v->type->typ);
+			mmerror(ET_ERROR,errortext);
+			break;
+	}
+}
+
+static void
+output_get_descr_header(char *desc_name)
+{	struct assignment *results;
+	fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
+													,yylineno,desc_name);
+	fputs("\tif (ECPGresult)\n\t{",yyout);
+	for (results=assignments;results!=NULL;results=results->next)
+	{	if (!strcasecmp(results->value,"count"))
+		{	fputs("\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fputs("=PQnfields(ECPGresult);\n",yyout);
+		}
+		else
+		{	snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
+			mmerror(ET_WARN,errortext);
+		}
+	}
+	drop_assignments();
+	fputs("}",yyout);
+	
+	whenever_action(2|1);
+}
+
+static void
+output_get_descr(char *desc_name)
+{	struct assignment *results;
+	int flags=0;
+	const int DATA_SEEN=1;
+	const int INDICATOR_SEEN=2;
+	
+	fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n"
+													,yylineno,desc_name);
+	fputs("\tif (ECPGresult)\n\t{",yyout);
+	fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno);
+	fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n"
+			"\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n"
+				,descriptor_index,descriptor_index,yylineno);
+	fputs("\t\telse\n\t\t{\n",yyout);
+	for (results=assignments;results!=NULL;results=results->next)
+	{	if (!strcasecmp(results->value,"type"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"datetime_interval_code"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"length"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"octet_length"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"returned_length")
+			|| !strcasecmp(results->value,"returned_octet_length"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"precision"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"scale"))
+		{	fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"nullable"))
+		{	mmerror(ET_WARN,"nullable is always 1");
+			fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=1;\n");
+		}
+		else if (!strcasecmp(results->value,"key_member"))
+		{	mmerror(ET_WARN,"key_member is always 0");
+			fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=0;\n");
+		}
+		else if (!strcasecmp(results->value,"name"))
+		{	fputs("\t\t\tstrncpy(",yyout);
+			ECPGstring_buffer(yyout,results->variable);
+			fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index);
+			ECPGstring_length(yyout,results->variable);
+			fputs(");\n",yyout);
+		}
+		else if (!strcasecmp(results->value,"indicator"))
+		{	flags|=INDICATOR_SEEN;
+		    fputs("\t\t\t",yyout);
+			ECPGnumeric_lvalue(yyout,results->variable);
+			fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index);
+		}
+		else if (!strcasecmp(results->value,"data"))
+		{	flags|=DATA_SEEN;
+		    ECPGdata_assignment(results->variable,descriptor_index);
+		}
+		else
+		{	snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value);
+			mmerror(ET_WARN,errortext);
+		}
+	}
+	if (flags==DATA_SEEN) /* no indicator */
+	{	fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n"
+					"\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n"
+				,descriptor_index,yylineno);
+	}
+	drop_assignments();
+	fputs("\t\t}\n\t}\n",yyout);
+	
+	whenever_action(2|1);
+}
+
 /*
  * store the whenever action here
  */
@@ -157,8 +433,6 @@ new_variable(const char * name, struct ECPGtype * type)
     return(p);
 }
 
-static struct variable * find_variable(char * name);
-
 static struct variable *
 find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
 {
@@ -401,6 +675,67 @@ check_indicator(struct ECPGtype *var)
 	}
 }
 
+/*
+ * descriptor name lookup
+ */
+ 
+static struct descriptor *descriptors;
+
+static void add_descriptor(char *name,char *connection)
+{
+	struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor));
+	
+	new->next=descriptors;
+	new->name=mm_alloc(strlen(name)+1);
+	strcpy(new->name,name);
+	if (connection) 
+	{	new->connection=mm_alloc(strlen(connection)+1);
+		strcpy(new->connection,connection);
+	}
+	else new->connection=connection;
+	descriptors=new;
+}
+
+static void drop_descriptor(char *name,char *connection)
+{	struct descriptor *i;
+	struct descriptor **lastptr=&descriptors;
+	for (i=descriptors;i;lastptr=&i->next,i=i->next)
+	{	if (!strcmp(name,i->name))
+		{	if ((!connection && !i->connection) 
+				|| (connection && i->connection 
+					&& !strcmp(connection,i->connection)))
+			{	*lastptr=i->next;
+				if (i->connection) free(i->connection);
+				free(i->name);
+				free(i);
+				return;
+			}
+		}
+	}
+	snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
+	mmerror(ET_WARN,errortext);
+}
+
+static struct descriptor *lookup_descriptor(char *name,char *connection)
+{	struct descriptor *i;
+	for (i=descriptors;i;i=i->next)
+	{	if (!strcmp(name,i->name))
+		{	if ((!connection && !i->connection) 
+				|| (connection && i->connection 
+					&& !strcmp(connection,i->connection)))
+			{	return i;
+			}
+		}
+	}
+	snprintf(errortext,sizeof errortext,"unknown descriptor %s",name);
+	mmerror(ET_WARN,errortext);
+	return NULL;
+}
+
+/*
+ * string concatenation
+ */
+
 static char *
 cat2_str(char *str1, char *str2)
 { 
@@ -522,6 +857,32 @@ output_statement(char * stmt, int mode)
 		free(connection);
 }
 
+static void
+output_statement_desc(char * stmt, int mode)
+{
+	int i, j=strlen(stmt);
+
+	fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"", 
+		connection ? connection : "NULL", descriptor_name);
+
+	/* do this char by char as we have to filter '\"' */
+	for (i = 0;i < j; i++) {
+		if (stmt[i] != '\"')
+			fputc(stmt[i], yyout);
+		else
+			fputs("\\\"", yyout);
+	}
+
+	fputs("\");", yyout);
+
+	mode |= 2;
+	whenever_action(mode);
+	free(stmt);
+	if (connection != NULL)
+		free(connection);
+	free(descriptor_name);
+}
+
 static struct typedefs *
 get_typedef(char *name)
 {
@@ -632,15 +993,16 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 }
 
 /* special embedded SQL token */
-%token		SQL_AT SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK 
+%token		SQL_ALLOCATE SQL_AT SQL_AUTOCOMMIT 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_DEALLOCATE SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM 
+%token		SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO
 %token		SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_LONG
 %token		SQL_OFF SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
-%token		SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
+%token		SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL 
+%token		SQL_SQLERROR SQL_SQLPRINT
 %token		SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
-%token		SQL_VAR SQL_WHENEVER
+%token		SQL_VALUE SQL_VAR SQL_WHENEVER
 
 /* C token */
 %token		S_ANYTHING S_AUTO S_CONST S_EXTERN
@@ -829,6 +1191,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
 %type  <str>	ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
 %type  <str>    struct_type s_struct declaration declarations variable_declarations
 %type  <str>    s_struct s_union union_type ECPGSetAutocommit on_off
+%type  <str>	ECPGAllocateDescr ECPGDeallocateDescr
+%type  <str>	ECPGGetDescriptor ECPGGetDescriptorHeader 
+%type  <str>	FetchDescriptorStmt
 
 %type  <type_enum> simple_type signed_type unsigned_type varchar_type
 
@@ -879,6 +1244,7 @@ stmt:  AlterTableStmt			{ output_statement($1, 0); }
 		| ExtendStmt 		{ output_statement($1, 0); }
 		| ExplainStmt		{ output_statement($1, 0); }
 		| FetchStmt		{ output_statement($1, 1); }
+		| FetchDescriptorStmt		{ output_statement_desc($1, 1); }
 		| GrantStmt		{ output_statement($1, 0); }
 		| IndexStmt		{ output_statement($1, 0); }
 		| ListenStmt		{ output_statement($1, 0); }
@@ -912,6 +1278,10 @@ stmt:  AlterTableStmt			{ output_statement($1, 0); }
 		| VariableShowStmt	{ output_statement($1, 0); }
 		| VariableResetStmt	{ output_statement($1, 0); }
 		| ConstraintsSetStmt	{ output_statement($1, 0); }
+		| ECPGAllocateDescr	{	fprintf(yyout,"ECPGallocate_desc(__LINE__, \"%s\");",$1);
+								whenever_action(0);
+								free($1);
+							}
 		| ECPGConnect		{
 						if (connection)
 							mmerror(ET_ERROR, "no at option for connect statement.\n");
@@ -932,6 +1302,10 @@ stmt:  AlterTableStmt			{ output_statement($1, 0); }
 						whenever_action(2);
 						free($1);
 					}
+		| ECPGDeallocateDescr	{	fprintf(yyout,"ECPGdeallocate_desc(__LINE__, \"%s\");",$1);
+									whenever_action(0);
+									free($1);
+								}
 		| ECPGDeclare		{
 						output_simple_statement($1);
 					}
@@ -952,6 +1326,14 @@ stmt:  AlterTableStmt			{ output_statement($1, 0); }
 						whenever_action(2);
 						free($1);
 					}
+		| ECPGGetDescriptor	{	
+						lookup_descriptor($1,connection);
+						output_get_descr($1);
+					}
+		| ECPGGetDescriptorHeader	{	
+						lookup_descriptor($1,connection);
+						output_get_descr_header($1);
+					}
 		| ECPGOpen		{	
 						struct cursor *ptr;
 						 
@@ -5014,6 +5396,78 @@ ECPGPrepare: SQL_PREPARE ident FROM execstring
 		$$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4);
 	}
 
+/*
+ * dynamic SQL: descriptor based access
+ * 	written by Christof Petig <christof.petig@wtal.de>
+ */
+
+/*
+ * deallocate a descriptor
+ */
+ECPGDeallocateDescr:	SQL_DEALLOCATE SQL_DESCRIPTOR ident	
+{	drop_descriptor($3,connection);
+	$$ = $3;
+}
+
+/*
+ * allocate a descriptor
+ */
+ECPGAllocateDescr:	SQL_ALLOCATE SQL_DESCRIPTOR ident	
+{   add_descriptor($3,connection);
+	$$ = $3;
+}
+
+/*
+ * read from descriptor
+ */
+
+ECPGGetDescHeaderItem: cvariable '=' ident  {
+		push_assignment($1,$3);
+}
+
+ECPGGetDescItem: cvariable '=' ident  {
+		push_assignment($1,$3);
+}
+	| cvariable '=' TYPE_P {
+		push_assignment($1,"type");
+}
+	| cvariable '=' PRECISION {
+		push_assignment($1,"precision");
+}
+	| cvariable '=' SQL_INDICATOR {
+		push_assignment($1,"indicator");
+}
+
+ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
+	| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem;
+ 
+ECPGGetDescItems: ECPGGetDescItem
+	| ECPGGetDescItems ',' ECPGGetDescItem;
+ 
+ECPGGetDescriptorHeader:	SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems
+{  $$ = $3; }
+
+ECPGGetDescriptor:	SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems
+{  $$ = $3; descriptor_index=$5; }
+	|	SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems
+{  $$ = $3; descriptor_index=$5; }
+
+/*
+ *  fetch [ in | from ] <portalname> into sql descriptor <name>
+ */
+
+FetchDescriptorStmt:	FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident
+  				{
+					$$ = cat_str(3, make_str("fetch"), $2, $3);
+					descriptor_name=$7;
+				}
+		|	FETCH name INTO SQL_SQL SQL_DESCRIPTOR ident
+  				{
+					$$ = cat2_str(make_str("fetch"), $2);
+					descriptor_name=$6;
+				}
+		;
+
 /*
  * for compatibility with ORACLE we will also allow the keyword RELEASE
  * after a transaction statement to disconnect from the database.
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index efc8c66923..4a8814fcdd 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -139,4 +139,18 @@ struct arguments
 	struct arguments *next;
 };
 
+struct descriptor
+{
+	char	*name;
+	char	*connection;
+	struct descriptor *next;
+};
+
+struct assignment
+{	
+	char 	*variable;
+	char	*value;
+	struct assignment *next;
+};
+
 enum errortype {ET_WARN, ET_ERROR, ET_FATAL};
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 03afc89b6d..9b945793e2 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -1,8 +1,8 @@
-all: stp.so test1 test2 test3 test4 test5 perftest
+all: stp.so test1 test2 test3 test4 test5 perftest dyntest
 
 #LDFLAGS=-g -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg -lpq -lcrypt
-#LDFLAGS=-g -I../include -I/usr/include/postgresql  -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
-LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
+LDFLAGS=-g -I../include -I/usr/include/postgresql  -L/usr/lib/postgresql -L../lib -lecpg -lpq -lcrypt
+#LDFLAGS=-g -I/usr/include/postgresql -lecpg -lpq -lcrypt
 
 #ECPG=/usr/local/pgsql/bin/ecpg
 ECPG=../preproc/ecpg -I../include
@@ -16,6 +16,7 @@ test3: test3.c
 test4: test4.c
 test5: test5.c
 perftest: perftest.c
+dyntest: dyntest.c
 
 .pgc.c:
 	$(ECPG) $? 
diff --git a/src/interfaces/ecpg/test/dyntest.pgc b/src/interfaces/ecpg/test/dyntest.pgc
new file mode 100644
index 0000000000..451d82ad90
--- /dev/null
+++ b/src/interfaces/ecpg/test/dyntest.pgc
@@ -0,0 +1,127 @@
+/* dynamic SQL test program
+ *
+ * Copyright (c) 2000, Christof Petig <christof.petig@wtal.de>
+ *
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.1 2000/02/16 16:18:29 meskes Exp $
+ */
+
+#include <stdio.h>
+
+exec sql include sql3types;
+exec sql include sqlca;
+
+void error()
+{  printf("#%d:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
+   exit(1);
+}
+
+int main(int argc,char **argv)
+{ exec sql begin declare section;
+  int COUNT;
+  int INTVAR;
+  int INDEX;
+  int INDICATOR;
+  int TYPE,LENGTH,OCTET_LENGTH,PRECISION,SCALE,NULLABLE,RETURNED_OCTET_LENGTH;
+  int DATETIME_INTERVAL_CODE;
+  char NAME[120];
+  char STRINGVAR[1024];
+  float FLOATVAR;
+  double DOUBLEVAR;
+  char QUERY[1024];
+  exec sql end declare section;
+  int done=0;
+  
+  snprintf(QUERY,sizeof QUERY,"select * from %s",argc>1?argv[1]:"pg_tables");
+
+  exec sql whenever sqlerror do error();
+  
+  exec sql allocate descriptor MYDESC;
+  
+  exec sql connect to test;
+  
+  exec sql prepare MYQUERY from :QUERY;
+  exec sql declare MYCURS cursor for MYQUERY;
+  
+  exec sql open MYCURS;
+  
+  while (1)
+  {  exec sql fetch in MYCURS into sql descriptor MYDESC;
+     
+     if (sqlca.sqlcode) break;
+     
+     exec sql get descriptor MYDESC :COUNT = count;
+     if (!done) 
+     {  printf("Count %d\n",COUNT);
+        done=1;
+     } 
+     
+     for (INDEX=1;INDEX<=COUNT;++INDEX)
+     {  exec sql get descriptor MYDESC value :INDEX 
+     		:TYPE = type,
+     		:LENGTH = length, :OCTET_LENGTH=octet_length,
+     		:RETURNED_OCTET_LENGTH=returned_octet_length,
+     		:PRECISION = precision, :SCALE=scale,
+     		:NULLABLE=nullable, :NAME=name,
+     		:INDICATOR=indicator;
+     	printf("%2d %s %d(%d)(%d,%d) %d,%d %d = "
+     			,INDEX,NAME,TYPE,LENGTH,PRECISION,SCALE
+     			,OCTET_LENGTH,RETURNED_OCTET_LENGTH,NULLABLE);
+     	if (INDICATOR==-1) printf("NULL\n");
+        else switch (TYPE)
+     	{  case SQL3_BOOLEAN: 
+     	        exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+     		printf("%s\n",INTVAR?"true":"false");
+     		break;
+     	   case SQL3_NUMERIC:
+     	   case SQL3_DECIMAL:
+     	        if (SCALE==0) 
+     	        {  exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+     	           printf("%d\n",INTVAR);
+     	        }
+     	        else
+     	        {  exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
+     	           printf("%.*f\n",SCALE,FLOATVAR);
+     	        }
+     	        break;
+     	   case SQL3_INTEGER:
+     	   case SQL3_SMALLINT: 
+     	        exec sql get descriptor MYDESC value :INDEX :INTVAR=data;
+     	        printf("%d\n",INTVAR);
+     	        break;
+     	   case SQL3_FLOAT:
+     	   case SQL3_REAL:
+     	        exec sql get descriptor MYDESC value :INDEX :FLOATVAR=data;
+     	        printf("%.*f\n",PRECISION,FLOATVAR);
+     	        break;
+     	   case SQL3_DOUBLE_PRECISION:
+     	        exec sql get descriptor MYDESC value :INDEX :DOUBLEVAR=data;
+     	        printf("%.*f\n",PRECISION,DOUBLEVAR);
+     	        break;
+     	   case SQL3_DATE_TIME_TIMESTAMP:
+     	   	exec sql get descriptor MYDESC value :INDEX 
+     	   		:DATETIME_INTERVAL_CODE=datetime_interval_code,
+     	   		:STRINGVAR=data;
+     	        printf("%d \"%s\"\n",DATETIME_INTERVAL_CODE,STRINGVAR);
+     	        break;
+     	   case SQL3_INTERVAL:
+     	        exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+     	        printf("\"%s\"\n",STRINGVAR);
+     	        break;
+     	   case SQL3_CHARACTER:
+     	   case SQL3_CHARACTER_VARYING:
+     	        exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+     	        printf("\"%s\"\n",STRINGVAR);
+     	        break;
+     	   default:
+     	        exec sql get descriptor MYDESC value :INDEX :STRINGVAR=data;
+     	        printf("<\"%s\">\n",STRINGVAR);
+     	        break;
+     	}
+     }
+  }
+  
+  exec sql close MYCURS;
+  
+  exec sql deallocate descriptor MYDESC;
+  return 0;
+}