diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index b1ec43d48e6123416a37fb1fb42aa01fc891d445..9684e30cc71cbbbc0d5b194c7c239cd4e8a81c62 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -1,6 +1,6 @@
 /* dynamic SQL support routines
  *
- * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.7 2003/11/29 19:52:08 pgsql Exp $
+ * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.8 2004/06/30 15:01:56 meskes Exp $
  */
 
 #define POSTGRES_ECPG_INTERNAL
@@ -110,6 +110,51 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
 	return (true);
 }
 
+static bool
+set_int_item(int lineno, int *target, const void *var, enum ECPGttype vartype)
+{
+	switch (vartype)
+	{
+		case ECPGt_short:
+			*target = *(short *) var;
+			break;
+		case ECPGt_int:
+			*target = *(int *) var;
+			break;
+		case ECPGt_long:
+			*target = *(long *) var;
+			break;
+		case ECPGt_unsigned_short:
+			*target = *(unsigned short *) var;
+			break;
+		case ECPGt_unsigned_int:
+			*target = *(unsigned int *) var;
+			break;
+		case ECPGt_unsigned_long:
+			*target = *(unsigned long *) var;
+			break;
+#ifdef HAVE_LONG_LONG_INT_64
+		case ECPGt_long_long:
+			*target = *(long long int *) var;
+			break;
+		case ECPGt_unsigned_long_long:
+			*target = *(unsigned long long int *) var;
+			break;
+#endif   /* HAVE_LONG_LONG_INT_64 */
+		case ECPGt_float:
+			*target = *(float *) var;
+			break;
+		case ECPGt_double:
+			*target = *(double *) var;
+			break;
+		default:
+			ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
+			return (false);
+	}
+
+	return true;
+}
+
 static bool
 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
 {
@@ -385,6 +430,124 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
 	return (true);
 }
 
+bool
+ECPGset_desc(int lineno, char *desc_name, int index,...)
+{
+	va_list		args;
+	struct descriptor *desc;
+	struct descriptor_item *desc_item, *last_di;
+
+	for (desc = all_descriptors; desc; desc = desc->next)
+	{
+		if (strcmp(desc_name, desc->name)==0)
+			break;
+	}
+
+	if (desc == NULL)
+	{
+		ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, desc_name);
+		return false;
+	}
+
+	for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
+	{
+		if (desc_item->num == index)
+			break;
+	}
+
+	if (desc_item == NULL)
+	{
+		desc_item = ECPGalloc(sizeof(*desc_item), lineno);
+		desc_item->num = index;
+		desc_item->next = desc->items;
+		desc->items = desc_item;
+	}
+
+	va_start(args, index);
+
+	do
+	{
+		enum ECPGdtype itemtype;
+		long		varcharsize;
+		long		offset;
+		long		arrsize;
+		enum ECPGttype vartype;
+		void	   *var;
+
+		itemtype = va_arg(args, enum ECPGdtype);
+
+		if (itemtype == ECPGd_EODT)
+			break;
+
+		vartype = va_arg(args, enum ECPGttype);
+		var = va_arg(args, void *);
+		varcharsize = va_arg(args, long);
+		arrsize = va_arg(args, long);
+		offset = va_arg(args, long);
+
+		switch (itemtype)
+		{
+			case ECPGd_data:
+			{
+				// FIXME: how to do this in general?
+				switch (vartype)
+				{
+					case ECPGt_char:
+						desc_item->data = strdup((char *)var);
+						break;
+					case ECPGt_int:
+					{
+						char buf[20];
+						snprintf(buf, 20, "%d", *(int *)var);
+						desc_item->data = strdup(buf);
+						break;
+					}
+					default:
+						abort();
+				}
+				break;
+			}
+
+			case ECPGd_indicator:
+				set_int_item(lineno, &desc_item->indicator, var, vartype);
+				break;
+
+			case ECPGd_length:
+				set_int_item(lineno, &desc_item->length, var, vartype);
+				break;
+
+			case ECPGd_precision:
+				set_int_item(lineno, &desc_item->precision, var, vartype);
+				break;
+
+			case ECPGd_scale:
+				set_int_item(lineno, &desc_item->scale, var, vartype);
+				break;
+
+			case ECPGd_type:
+				set_int_item(lineno, &desc_item->type, var, vartype);
+				break;
+
+			default:
+			{
+				char	type_str[20];
+				snprintf(type_str, sizeof(type_str), "%d", itemtype);
+				ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
+				return false;
+			}
+		}
+
+		/*if (itemtype == ECPGd_data)
+		{
+			free(desc_item->data);
+			desc_item->data = NULL;
+		}*/
+	}
+	while (true);
+
+	return true;
+}
+
 bool
 ECPGdeallocate_desc(int line, const char *name)
 {
@@ -425,6 +588,7 @@ ECPGallocate_desc(int line, const char *name)
 		ECPGfree(new);
 		return false;
 	}
+	new->items = NULL;
 	new->result = PQmakeEmptyPGresult(NULL, 0);
 	if (!new->result)
 	{
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index c91e96d3a1a85d64d347fc5f045e831cde889f6d..d99f9584458b2fcbdcefdabb12fa23cae5309a5a 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.34 2004/06/27 12:28:40 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.35 2004/06/30 15:01:56 meskes Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -1026,6 +1026,9 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
 					free(str);
 				}
 				break;
+				
+			case ECPGt_descriptor:
+				break;
 
 			default:
 				/* Not implemented yet */
@@ -1046,6 +1049,7 @@ ECPGexecute(struct statement * stmt)
 	PGresult   *results;
 	PGnotify   *notify;
 	struct variable *var;
+	int	   desc_counter = 0;
 
 	copiedquery = ECPGstrdup(stmt->command, stmt->lineno);
 
@@ -1056,64 +1060,116 @@ ECPGexecute(struct statement * stmt)
 	 * so on.
 	 */
 	var = stmt->inlist;
+
 	while (var)
 	{
 		char	   *newcopy = NULL;
-		const char *tobeinserted = NULL;
+		const char *tobeinserted; 
 		char	   *p;
-		bool		malloced = FALSE;
-		int			hostvarl = 0;
-
-		if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
-			return false;
+		bool	   malloced = FALSE;
+		int	   hostvarl = 0;
 
-		/*
-		 * Now tobeinserted points to an area that is to be inserted at
-		 * the first %s
-		 */
-		if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
-			return false;
-
-		strcpy(newcopy, copiedquery);
-		if ((p = next_insert(newcopy + hostvarl)) == NULL)
+		tobeinserted = NULL;
+		/* A descriptor is a special case since it contains many variables but is listed only once. */
+		if (var->type == ECPGt_descriptor)
 		{
-			/*
-			 * We have an argument but we dont have the matched up string
-			 * in the string
-			 */
-			ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
-			return false;
+			/* We create an additional variable list here, so the same logic applies. */
+			struct variable desc_inlist;
+			struct descriptor *desc;
+			struct descriptor_item *desc_item;
+			for (desc = all_descriptors; desc; desc = desc->next)
+			{
+				if (strcmp(var->pointer, desc->name) == 0)
+					break;
+			}
+			
+			if (desc == NULL)
+			{
+				ECPGraise(stmt->lineno, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, var->pointer);
+				return false;
+			}
+			
+			desc_counter++;
+			for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
+			{
+				if (desc_item->num == desc_counter)
+				{
+					desc_inlist.type = ECPGt_char;
+					desc_inlist.value = desc_item->data;
+					desc_inlist.pointer = &(desc_item->data);
+					desc_inlist.varcharsize = strlen(desc_item->data);
+					desc_inlist.arrsize = 1;
+					desc_inlist.offset = 0;
+					desc_inlist.ind_type = ECPGt_NO_INDICATOR;
+					desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
+					desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
+
+					if (!ECPGstore_input(stmt, &desc_inlist, &tobeinserted, &malloced))
+						return false;
+					
+					break;
+				}
+			}
+
+			if (!desc_item) /* no more entries found in descriptor */
+				desc_counter = 0;
 		}
 		else
 		{
-			strcpy(p, tobeinserted);
-			hostvarl = strlen(newcopy);
-
+			if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced))
+				return false;
+		}
+		if (tobeinserted)
+		{
 			/*
-			 * The strange thing in the second argument is the rest of the
-			 * string from the old string
+			 * Now tobeinserted points to an area that is to be inserted at
+			 * the first %s
 			 */
-			strcat(newcopy,
-				   copiedquery
-				   + (p - newcopy)
-				   + sizeof("?") - 1 /* don't count the '\0' */ );
-		}
+			if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno)))
+				return false;
 
-		/*
-		 * Now everything is safely copied to the newcopy. Lets free the
-		 * oldcopy and let the copiedquery get the var->value from the
-		 * newcopy.
-		 */
-		if (malloced)
-		{
-			ECPGfree((char *) tobeinserted);
-			tobeinserted = NULL;
-		}
+			strcpy(newcopy, copiedquery);
+			if ((p = next_insert(newcopy + hostvarl)) == NULL)
+			{
+				/*
+				 * We have an argument but we dont have the matched up string
+				 * in the string
+				 */
+				ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
+				return false;
+			}
+			else
+			{
+				strcpy(p, tobeinserted);
+				hostvarl = strlen(newcopy);
+
+				/*
+				 * The strange thing in the second argument is the rest of the
+				 * string from the old string
+				 */
+				strcat(newcopy,
+					   copiedquery
+					   + (p - newcopy)
+					   + sizeof("?") - 1 /* don't count the '\0' */ );
+			}
 
-		ECPGfree(copiedquery);
-		copiedquery = newcopy;
+			/*
+			 * Now everything is safely copied to the newcopy. Lets free the
+			 * oldcopy and let the copiedquery get the var->value from the
+			 * newcopy.
+			 */
+			if (malloced)
+			{
+				ECPGfree((char *) tobeinserted);
+				tobeinserted = NULL;
+			}
 
-		var = var->next;
+			ECPGfree(copiedquery);
+			copiedquery = newcopy;
+		}
+		
+		if (desc_counter == 0)
+	 		var = var->next;
 	}
 
 	/* Check if there are unmatched things left. */
diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h
index b265247f38cf2baa81db7d4810187f16134bb880..c644ff292da06c62ac3ccf5d96dd23a4fa7ec3c4 100644
--- a/src/interfaces/ecpg/ecpglib/extern.h
+++ b/src/interfaces/ecpg/ecpglib/extern.h
@@ -7,39 +7,42 @@
 
 enum COMPAT_MODE
 {
-	ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE
+  ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE
 };
 
 #define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE)
 
 enum ARRAY_TYPE
 {
-	ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE
+  ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE
 };
 
 /* Here are some methods used by the lib. */
 
 /* Returns a pointer to a string containing a simple type name. */
-void		ECPGadd_mem(void *ptr, int lineno);
-
-bool ECPGget_data(const PGresult *, int, int, int, enum ECPGttype type,
-			 enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool);
-struct connection *ECPGget_connection(const char *);
-char	   *ECPGalloc(long, int);
-char	   *ECPGrealloc(void *, long, int);
-void		ECPGfree(void *);
-bool		ECPGinit(const struct connection *, const char *, const int);
-char	   *ECPGstrdup(const char *, int);
-const char *ECPGtype_name(enum ECPGttype);
-unsigned int ECPGDynamicType(Oid);
-void		ECPGfree_auto_mem(void);
-void		ECPGclear_auto_mem(void);
+void ECPGadd_mem (void *ptr, int lineno);
+
+bool ECPGget_data (const PGresult *, int, int, int, enum ECPGttype type,
+		   enum ECPGttype, char *, char *, long, long, long,
+		   enum ARRAY_TYPE, enum COMPAT_MODE, bool);
+struct connection *ECPGget_connection (const char *);
+char *ECPGalloc (long, int);
+char *ECPGrealloc (void *, long, int);
+void ECPGfree (void *);
+bool ECPGinit (const struct connection *, const char *, const int);
+char *ECPGstrdup (const char *, int);
+const char *ECPGtype_name (enum ECPGttype);
+unsigned int ECPGDynamicType (Oid);
+void ECPGfree_auto_mem (void);
+void ECPGclear_auto_mem (void);
+
+struct descriptor *ecpggetdescp (int, char *);
 
 /* A generic varchar type. */
 struct ECPGgeneric_varchar
 {
-	int			len;
-	char		arr[1];
+  int len;
+  char arr[1];
 };
 
 /*
@@ -48,64 +51,79 @@ struct ECPGgeneric_varchar
 
 struct ECPGtype_information_cache
 {
-	struct ECPGtype_information_cache *next;
-	int			oid;
-	bool		isarray;
+  struct ECPGtype_information_cache *next;
+  int oid;
+  bool isarray;
 };
 
 /* structure to store one statement */
 struct statement
 {
-	int			lineno;
-	char	   *command;
-	struct connection *connection;
-	enum COMPAT_MODE compat;
-	bool		force_indicator;
-	struct variable *inlist;
-	struct variable *outlist;
+  int lineno;
+  char *command;
+  struct connection *connection;
+  enum COMPAT_MODE compat;
+  bool force_indicator;
+  struct variable *inlist;
+  struct variable *outlist;
 };
 
 /* structure to store connections */
 struct connection
 {
-	char	   *name;
-	PGconn	   *connection;
-	bool		committed;
-	int			autocommit;
-	struct ECPGtype_information_cache *cache_head;
-	struct connection *next;
+  char *name;
+  PGconn *connection;
+  bool committed;
+  int autocommit;
+  struct ECPGtype_information_cache *cache_head;
+  struct connection *next;
 };
 
 /* structure to store descriptors */
 struct descriptor
 {
-	char	   *name;
-	PGresult   *result;
-	struct descriptor *next;
+  char *name;
+  PGresult *result;
+  struct descriptor *next;
+  int count;
+  struct descriptor_item *items;
+};
+
+extern struct descriptor *all_descriptors;
+
+struct descriptor_item
+{
+  int num;
+  char *data;
+  int indicator;
+  int length;
+  int precision;
+  int scale;
+  int type;
+  struct descriptor_item *next;
 };
 
 struct variable
 {
-	enum ECPGttype type;
-	void	   *value;
-	void	   *pointer;
-	long		varcharsize;
-	long		arrsize;
-	long		offset;
-	enum ECPGttype ind_type;
-	void	   *ind_value;
-	void	   *ind_pointer;
-	long		ind_varcharsize;
-	long		ind_arrsize;
-	long		ind_offset;
-	struct variable *next;
+  enum ECPGttype type;
+  void *value;
+  void *pointer;
+  long varcharsize;
+  long arrsize;
+  long offset;
+  enum ECPGttype ind_type;
+  void *ind_value;
+  void *ind_pointer;
+  long ind_varcharsize;
+  long ind_arrsize;
+  long ind_offset;
+  struct variable *next;
 };
 
-PGresult  **
-			ECPGdescriptor_lvalue(int line, const char *descriptor);
+PGresult **ECPGdescriptor_lvalue (int line, const char *descriptor);
 
-bool ECPGstore_result(const PGresult *results, int act_field,
-				 const struct statement * stmt, struct variable * var);
+bool ECPGstore_result (const PGresult * results, int act_field,
+		       const struct statement *stmt, struct variable *var);
 
 /* SQLSTATE values generated or processed by ecpglib (intentionally
  * not exported -- users should refer to the codes directly) */
@@ -133,4 +151,4 @@ bool ECPGstore_result(const PGresult *results, int act_field,
 #define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR	"YE000"
 #define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY	"YE001"
 
-#endif   /* _ECPG_LIB_EXTERN_H */
+#endif /* _ECPG_LIB_EXTERN_H */
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index b76cd4d19c2bf48da8b22db3c6135e1560d16c4f..9f3e3aa1502f41bdbc5d34ce8d5fcd1ad1a5ed68 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -76,6 +76,8 @@ void		ECPGraise(int line, int code, const char *sqlstate, const char *str);
 void		ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
 bool		ECPGget_desc_header(int, char *, int *);
 bool		ECPGget_desc(int, char *, int,...);
+bool		ECPGset_desc_header(int, char *, int *);
+bool		ECPGset_desc(int, char *, int,...);
 
 void		ECPGset_noind_null(enum ECPGttype, void *);
 bool		ECPGis_noind_null(enum ECPGttype, void *);
diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c
index 742002b4c0f8f90ff08016f9afd945d71ca30a23..6861a91dc7fb8fc0443c65983b8503172f74c582 100644
--- a/src/interfaces/ecpg/preproc/descriptor.c
+++ b/src/interfaces/ecpg/preproc/descriptor.c
@@ -58,9 +58,7 @@ ECPGnumeric_lvalue(FILE *f, char *name)
 			fputs(name, yyout);
 			break;
 		default:
-			snprintf(errortext, sizeof errortext, "variable %s: numeric type needed"
-					 ,name);
-			mmerror(PARSE_ERROR, ET_ERROR, errortext);
+			mmerror(PARSE_ERROR, ET_ERROR, "variable %s: numeric type needed", name);
 			break;
 	}
 }
@@ -120,8 +118,7 @@ drop_descriptor(char *name, char *connection)
 			}
 		}
 	}
-	snprintf(errortext, sizeof errortext, "unknown descriptor %s", name);
-	mmerror(PARSE_ERROR, ET_WARNING, errortext);
+	mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
 }
 
 struct descriptor
@@ -143,8 +140,7 @@ lookup_descriptor(char *name, char *connection)
 				return i;
 		}
 	}
-	snprintf(errortext, sizeof errortext, "unknown descriptor %s", name);
-	mmerror(PARSE_ERROR, ET_WARNING, errortext);
+	mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor %s", name);
 	return NULL;
 }
 
@@ -153,16 +149,13 @@ output_get_descr_header(char *desc_name)
 {
 	struct assignment *results;
 
-	fprintf(yyout, "{ ECPGget_desc_header(%d, %s, &(", yylineno, desc_name);
+	fprintf(yyout, "{ ECPGget_desc_header(__LINE__, %s, &(", desc_name);
 	for (results = assignments; results != NULL; results = results->next)
 	{
 		if (results->value == ECPGd_count)
 			ECPGnumeric_lvalue(yyout, results->variable);
 		else
-		{
-			snprintf(errortext, sizeof errortext, "unknown descriptor header item '%d'", results->value);
-			mmerror(PARSE_ERROR, ET_WARNING, errortext);
-		}
+			mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value);
 	}
 
 	drop_assignments();
@@ -175,7 +168,7 @@ output_get_descr(char *desc_name, char *index)
 {
 	struct assignment *results;
 
-	fprintf(yyout, "{ ECPGget_desc(%d, %s, %s,", yylineno, desc_name, index);
+	fprintf(yyout, "{ ECPGget_desc(__LINE__, %s, %s,", desc_name, index);
 	for (results = assignments; results != NULL; results = results->next)
 	{
 		const struct variable *v = find_variable(results->variable);
@@ -200,6 +193,116 @@ output_get_descr(char *desc_name, char *index)
 	whenever_action(2 | 1);
 }
 
+void
+output_set_descr_header(char *desc_name)
+{
+	struct assignment *results;
+
+	fprintf(yyout, "{ ECPGset_desc_header(__LINE__, %s, &(", desc_name);
+	for (results = assignments; results != NULL; results = results->next)
+	{
+		if (results->value == ECPGd_count)
+			ECPGnumeric_lvalue(yyout, results->variable);
+		else
+			mmerror(PARSE_ERROR, ET_WARNING, "unknown descriptor header item '%d'", results->value);
+	}
+
+	drop_assignments();
+	fprintf(yyout, "));\n");
+	whenever_action(3);
+}
+
+static const char *
+descriptor_item_name(enum ECPGdtype itemcode)
+{
+	switch (itemcode)
+	{
+		case ECPGd_cardinality:
+			return "CARDINALITY";
+		case ECPGd_count:
+			return "COUNT";
+		case ECPGd_data:
+			return "DATA";
+		case ECPGd_di_code:
+			return "DATETIME_INTERVAL_CODE";
+		case ECPGd_di_precision:
+			return "DATETIME_INTERVAL_PRECISION";
+		case ECPGd_indicator:
+			return "INDICATOR";
+		case ECPGd_key_member:
+			return "KEY_MEMBER";
+		case ECPGd_length:
+			return "LENGTH";
+		case ECPGd_name:
+			return "NAME";
+		case ECPGd_nullable:
+			return "NULLABLE";
+		case ECPGd_octet:
+			return "OCTET_LENGTH";
+		case ECPGd_precision:
+			return "PRECISION";
+		case ECPGd_ret_length:
+			return "RETURNED_LENGTH";
+		case ECPGd_ret_octet:
+			return "RETURNED_OCTET_LENGTH";
+		case ECPGd_scale:
+			return "SCALE";
+		case ECPGd_type:
+			return "TYPE";
+		default:
+			return NULL;
+	}
+}
+
+void
+output_set_descr(char *desc_name, char *index)
+{
+	struct assignment *results;
+
+	fprintf(yyout, "{ ECPGset_desc(__LINE__, %s, %s,", desc_name, index);
+	for (results = assignments; results != NULL; results = results->next)
+	{
+		const struct variable *v = find_variable(results->variable);
+
+		switch (results->value)
+		{
+			case ECPGd_cardinality:
+			case ECPGd_di_code:
+			case ECPGd_di_precision:
+			case ECPGd_precision:
+			case ECPGd_scale:
+				mmerror(PARSE_ERROR, ET_FATAL, "descriptor item %s is not implemented",
+						descriptor_item_name(results->value));
+				break;
+
+			case ECPGd_key_member:
+			case ECPGd_name:
+			case ECPGd_nullable:
+			case ECPGd_octet:
+			case ECPGd_ret_length:
+			case ECPGd_ret_octet:
+				mmerror(PARSE_ERROR, ET_FATAL, "descriptor item %s cannot be set",
+						descriptor_item_name(results->value));
+				break;
+
+			case ECPGd_data:
+			case ECPGd_indicator:
+			case ECPGd_length:
+			case ECPGd_type:
+				fprintf(yyout, "%s,", get_dtype(results->value));
+				ECPGdump_a_type(yyout, v->name, v->type, NULL, NULL, NULL, NULL, make_str("0"), NULL, NULL);
+				break;
+
+			default:
+				;
+		}
+	}
+	drop_assignments();
+	fputs("ECPGd_EODT);\n", yyout);
+
+	whenever_action(2 | 1);
+}
+
 /* I consider dynamic allocation overkill since at most two descriptor
    variables are possible per statement. (input and output descriptor)
    And descriptors are no normal variables, so they don't belong into
@@ -211,11 +314,10 @@ struct variable *
 descriptor_variable(const char *name, int input)
 {
 	static char descriptor_names[2][MAX_DESCRIPTOR_NAMELEN];
-	static const struct ECPGtype descriptor_type =
-	{ECPGt_descriptor, 0};
-	static const struct variable varspace[2] =
-	{{descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL},
-	{descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL}
+	static const struct ECPGtype descriptor_type = { ECPGt_descriptor, 0 };
+	static const struct variable varspace[2] = {
+		{ descriptor_names[0], (struct ECPGtype *) & descriptor_type, 0, NULL },
+		{ descriptor_names[1], (struct ECPGtype *) & descriptor_type, 0, NULL }
 	};
 
 	strncpy(descriptor_names[input], name, MAX_DESCRIPTOR_NAMELEN);
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index 3d1088a20715ef57002cda9bbdecc0b2f4d6e481..6f9518f7e619b481833695c04be90c8e8429e37d 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -25,8 +25,7 @@ extern char *descriptor_name;
 extern char *connection;
 extern char *input_filename;
 extern char *yytext,
-		   *token_start,
-			errortext[128];
+		   *token_start;
 
 #ifdef YYDEBUG
 extern int	yydebug;
@@ -63,11 +62,13 @@ extern int	yylex(void);
 extern void yyerror(char *);
 extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
 extern char *mm_strdup(const char *);
-extern void mmerror(int, enum errortype, char *);
+extern void mmerror(int, enum errortype, char *, ...);
 extern ScanKeyword *ScanECPGKeywordLookup(char *);
 extern ScanKeyword *ScanCKeywordLookup(char *);
 extern void output_get_descr_header(char *);
 extern void output_get_descr(char *, char *);
+extern void output_set_descr_header(char *);
+extern void output_set_descr(char *, char *);
 extern void push_assignment(char *, enum ECPGdtype);
 extern struct variable *find_variable(char *);
 extern void whenever_action(int);
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index a6d9d755438424187fd75e0b38f3d428b3e6c473..e4ab68634f4cd762f843b792017954d1cc3e5110 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.128 2004/05/05 15:03:04 meskes Exp $
+ *	  $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.129 2004/06/30 15:01:57 meskes Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1164,10 +1164,7 @@ parse_include(void)
 		}
 	}
 	if (!yyin)
-	{
-		snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
-		mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
-  	}
+		mmerror(NO_INCLUDE_FILE, ET_FATAL, "Cannot open include file %s in line %d\n", yytext, yylineno);
 
 	input_filename = mm_strdup(inc_file);
 	yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index b4cf02e6e266f94f085424f9aed6b846f0000c36..ee9f25bad1f810090536137de0b4b1089a7b9f2f 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.289 2004/06/27 12:28:42 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.290 2004/06/30 15:01:57 meskes Exp $ */
 
 /* Copyright comment */
 %{
@@ -12,7 +12,6 @@
 int struct_level = 0;
 int braces_open; /* brace level counter */
 int ecpg_informix_var = 0;
-char	errortext[128];
 char	*connection = NULL;
 char	*input_filename = NULL;
 
@@ -52,19 +51,37 @@ static struct inf_compat_val
  * Handle parsing errors and warnings
  */
 void
-mmerror(int error_code, enum errortype type, char * error)
+mmerror(int error_code, enum errortype type, char * error, ...)
 {
+	va_list ap;
+	
+	fprintf(stderr, "%s:%d: ", input_filename, yylineno);
+	
+	switch(type)
+	{
+		case ET_WARNING:
+			fprintf(stderr, "WARNING: ");
+			break;
+		case ET_ERROR:
+		case ET_FATAL:
+			fprintf(stderr, "ERROR: ");
+			break;
+	}
+
+	va_start(ap, error);
+	vfprintf(stderr, error, ap);
+	va_end(ap);
+	
+	fprintf(stderr, "\n");
+	
 	switch(type)
 	{
 		case ET_WARNING:
-			fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error);
 			break;
 		case ET_ERROR:
-			fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
 			ret_value = error_code;
 			break;
 		case ET_FATAL:
-			fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
 			exit(error_code);
 	}
 }
@@ -261,8 +278,7 @@ add_additional_variables(char *name, bool insert)
 
 	if (ptr == NULL)
 	{
-		snprintf(errortext, sizeof(errortext), "trying to access an undeclared cursor %s\n", name);
-		mmerror(PARSE_ERROR, ET_ERROR, errortext);
+		mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor %s\n", name);
 		return NULL;
 	}
 	if (insert)
@@ -540,14 +556,14 @@ add_additional_variables(char *name, bool insert)
 %type  <str>	col_name_keyword func_name_keyword precision opt_scale
 %type  <str>	ECPGTypeName using_list ECPGColLabelCommon UsingConst
 %type  <str>	inf_val_list inf_col_list using_descriptor into_descriptor 
-%type  <str>	ecpg_into_using prepared_name struct_union_type_with_symbol
+%type  <str>	prepared_name struct_union_type_with_symbol
 %type  <str>	ECPGunreserved ECPGunreserved_interval cvariable
 %type  <str>	AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt
-%type  <str>	DropTableSpaceStmt indirection indirection_el
+%type  <str>	DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader
 
 %type  <struct_union> s_struct_union_symbol
 
-%type  <descriptor> ECPGGetDescriptor 
+%type  <descriptor> ECPGGetDescriptor ECPGSetDescriptor
 
 %type  <type_enum> simple_type signed_type unsigned_type
 
@@ -811,6 +827,19 @@ stmt:  AlterDatabaseSetStmt		{ output_statement($1, 0, connection); }
 			whenever_action(2);
 			free($1);
 		}
+		| ECPGSetDescriptor
+		{
+			lookup_descriptor($1.name, connection);
+			output_set_descr($1.name, $1.str);
+			free($1.name);
+			free($1.str);
+		}
+		| ECPGSetDescriptorHeader
+		{
+			lookup_descriptor($1, connection);
+			output_set_descr_header($1);
+			free($1);
+		}
 		| ECPGTypedef
 		{
 			if (connection)
@@ -1925,22 +1954,22 @@ TruncateStmt:  TRUNCATE opt_table qualified_name
  * embedded SQL implementations. So we accept their syntax as well and 
  * translate it to the PGSQL syntax. */
  
-FetchStmt: FETCH fetch_direction from_in name ecpg_into_using
+FetchStmt: FETCH fetch_direction from_in name ecpg_into
 			{
 				add_additional_variables($4, false);
 				$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
 			}
-		| FETCH fetch_direction name ecpg_into_using
+		| FETCH fetch_direction name ecpg_into
 			{
 				add_additional_variables($3, false);
 				$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
 			}
-		| FETCH from_in name ecpg_into_using
+		| FETCH from_in name ecpg_into
 			{
 			        add_additional_variables($3, false);
 				$$ = cat_str(3, make_str("fetch"), $2, $3);
 			}
-		| FETCH name ecpg_into_using
+		| FETCH name ecpg_into
 			{
 			        add_additional_variables($2, false);
 				$$ = cat2_str(make_str("fetch"), $2);
@@ -2895,11 +2924,8 @@ DeclareCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
 			for (ptr = cur; ptr != NULL; ptr = ptr->next)
 			{
 				if (strcmp($2, ptr->name) == 0)
-				{
-						/* re-definition is a bug */
-					snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
-					mmerror(PARSE_ERROR, ET_ERROR, errortext);
-				}
+					/* re-definition is a bug */
+					mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
 			}
 
 			this = (struct cursor *) mm_alloc(sizeof(struct cursor));
@@ -2987,7 +3013,7 @@ into_clause:  INTO OptTempTableName
 			FoundInto = 1;
 			$$= cat2_str(make_str("into"), $2);
 		}
-		| ecpg_into_using		{ $$ = EMPTY; }
+		| ecpg_into			{ $$ = EMPTY; }
 		| /*EMPTY*/			{ $$ = EMPTY; }
 		;
 
@@ -4246,11 +4272,7 @@ connection_target: database_name opt_server opt_port
 		{
 			/* old style: dbname[@server][:port] */
 			if (strlen($2) > 0 && *($2) != '@')
-			{
-				snprintf(errortext, sizeof(errortext),
-						 "Expected '@', found '%s'", $2);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "Expected '@', found '%s'", $2);
 
 			$$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
 		}
@@ -4258,24 +4280,15 @@ connection_target: database_name opt_server opt_port
 		{
 			/* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
 			if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
 
 			if (strncmp($3, "//", strlen("//")) != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "Expected '://', found '%s'", $3);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "Expected '://', found '%s'", $3);
 
 			if (strncmp($1, "unix", strlen("unix")) == 0 &&
 				strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
 				strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
 
 			$$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6),	$7, make_str("\"")));
 		}
@@ -4295,16 +4308,10 @@ connection_target: database_name opt_server opt_port
 db_prefix: ident cvariable
 		{
 			if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "Expected 'postgresql', found '%s'", $2);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "Expected 'postgresql', found '%s'", $2);
 
 			if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "Illegal connection type %s", $1);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "Illegal connection type %s", $1);
 
 			$$ = make3_str($1, make_str(":"), $2);
 		}
@@ -4313,10 +4320,7 @@ db_prefix: ident cvariable
 server: Op server_name
 		{
 			if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "Expected '@' or '://', found '%s'", $1);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "Expected '@' or '://', found '%s'", $1);
 
 			$$ = make2_str($1, $2);
 		}
@@ -4421,10 +4425,7 @@ opt_options: Op ColId
 				mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
 
 			if (strcmp($1, "?") != 0)
-			{
-				snprintf(errortext, sizeof(errortext), "unrecognised token '%s'", $1);
-				mmerror(PARSE_ERROR, ET_ERROR, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_ERROR, "unrecognised token '%s'", $1);
 
 			$$ = make2_str(make_str("?"), $2);
 		}
@@ -4443,11 +4444,8 @@ ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
 			for (ptr = cur; ptr != NULL; ptr = ptr->next)
 			{
 				if (strcmp($2, ptr->name) == 0)
-				{
-						/* re-definition is a bug */
-					snprintf(errortext, sizeof(errortext), "cursor %s already defined", $2);
-					mmerror(PARSE_ERROR, ET_ERROR, errortext);
-				}
+					/* re-definition is a bug */
+					mmerror(PARSE_ERROR, ET_ERROR, "cursor %s already defined", $2);
 			}
 
 			this = (struct cursor *) mm_alloc(sizeof(struct cursor));
@@ -4595,11 +4593,8 @@ type_declaration: S_TYPEDEF
 			for (ptr = types; ptr != NULL; ptr = ptr->next)
 			{
 				if (strcmp($5, ptr->name) == 0)
-				{
 			        	/* re-definition is a bug */
-					snprintf(errortext, sizeof(errortext), "Type %s already defined", $5);
-					mmerror(PARSE_ERROR, ET_ERROR, errortext);
-				}
+					mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $5);
 			}
 			adjust_array($3.type_enum, &dimension, &length, $3.type_dimension, $3.type_index, *$4?1:0, true);
 
@@ -4912,11 +4907,8 @@ struct_union_type_with_symbol: s_struct_union_symbol
 			for (ptr = types; ptr != NULL; ptr = ptr->next)
                         {
                                 if (strcmp(su_type.type_str, ptr->name) == 0)
-                                {
                                         /* re-definition is a bug */
-                                        snprintf(errortext, sizeof(errortext), "Type %s already defined", su_type.type_str);
-                                        mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                                }
+                                        mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", su_type.type_str);
                         }
 
                         this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
@@ -5215,28 +5207,25 @@ opt_ecpg_using: /*EMPTY*/		{ $$ = EMPTY; }
 		;
 
 ecpg_using:	USING using_list 	{ $$ = EMPTY; }
+		| using_descriptor      { $$ = $1; }
 		;
 
 using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
 		{
-			add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator);
+			add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
 			$$ = EMPTY;
 		}
 		;
 
 into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
 		{
-			add_variable_to_head(&argsresult, descriptor_variable($4,0), &no_indicator);
+			add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
 			$$ = EMPTY;
 		}
 		;
 		
 opt_sql: /*EMPTY*/ | SQL_SQL;
 
-ecpg_into_using: ecpg_into		{ $$ = EMPTY; }
-		| using_descriptor	{ $$ = $1; }
-		;
-
 ecpg_into: INTO into_list		{ $$ = EMPTY; }
 		| into_descriptor	{ $$ = $1; }
 		;
@@ -5295,8 +5284,19 @@ opt_output:	SQL_OUTPUT	{ $$ = make_str("output"); }
 /*
  * dynamic SQL: descriptor based access
  *	written by Christof Petig <christof.petig@wtal.de>
+ *		and Peter Eisentraut <peter.eisentraut@credativ.de>
  */
 
+/*
+ * allocate a descriptor
+ */
+ECPGAllocateDescr:     SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
+               {
+                       add_descriptor($3,connection);
+                       $$ = $3;
+               };
+
+ 
 /*
  * deallocate a descriptor
  */
@@ -5308,63 +5308,85 @@ ECPGDeallocateDescr:	DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
 		;
 
 /*
- * allocate a descriptor
+ * manipulate a descriptor header
  */
-ECPGAllocateDescr:	SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
-		{
-			add_descriptor($3,connection);
-			$$ = $3;
-		};
 
-/*
- * read from descriptor
- */
+ECPGGetDescriptorHeader: GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
+			{  $$ = $3; }
+		;
 
-ECPGGetDescHeaderItem: cvariable '=' desc_header_item
+ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
+		| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
+		;
+
+ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item
 			{ push_assignment($1, $3); }
 		;
 
-desc_header_item:	SQL_COUNT			{ $$ = ECPGd_count; }
+
+ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
+			{ $$ = $3; }
+
+ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
+		| ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
+		;
+
+ECPGSetDescHeaderItem: desc_header_item '=' CVARIABLE
+			{ push_assignment($3, $1); }
 		;
 
-ECPGGetDescItem: cvariable '=' descriptor_item	{ push_assignment($1, $3); };
 
-descriptor_item:	SQL_CARDINALITY		{ $$ = ECPGd_cardinality; }
-		| SQL_DATA						{ $$ = ECPGd_data; }
-		| SQL_DATETIME_INTERVAL_CODE	{ $$ = ECPGd_di_code; }
-		| SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; }
-		| SQL_INDICATOR					{ $$ = ECPGd_indicator; }
-		| SQL_KEY_MEMBER				{ $$ = ECPGd_key_member; }
-		| SQL_LENGTH					{ $$ = ECPGd_length; }
-		| SQL_NAME						{ $$ = ECPGd_name; }
-		| SQL_NULLABLE					{ $$ = ECPGd_nullable; }
-		| SQL_OCTET_LENGTH				{ $$ = ECPGd_octet; }
-		| PRECISION						{ $$ = ECPGd_precision; }
-		| SQL_RETURNED_LENGTH			{ $$ = ECPGd_length; }
-		| SQL_RETURNED_OCTET_LENGTH		{ $$ = ECPGd_ret_octet; }
-		| SQL_SCALE						{ $$ = ECPGd_scale; }
-		| TYPE_P						{ $$ = ECPGd_type; }
+desc_header_item:	SQL_COUNT			{ $$ = ECPGd_count; }
 		;
 
-ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
-		| ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
+/*
+ * manipulate a descriptor
+ */
+
+ECPGGetDescriptor:	GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGGetDescItems
+			{  $$.str = $5; $$.name = $3; }
+		|	GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems
+			{  $$.str = $5; $$.name = $3; }
 		;
 
 ECPGGetDescItems: ECPGGetDescItem
 		| ECPGGetDescItems ',' ECPGGetDescItem
 		;
 
-ECPGGetDescriptorHeader:	GET SQL_DESCRIPTOR quoted_ident_stringvar
-								ECPGGetDescHeaderItems
-			{  $$ = $3; }
-		;
+ECPGGetDescItem: CVARIABLE '=' descriptor_item	{ push_assignment($1, $3); };
+
 
-ECPGGetDescriptor:	GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE cvariable ECPGGetDescItems
+ECPGSetDescriptor:	SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE CVARIABLE ECPGSetDescItems
 			{  $$.str = $5; $$.name = $3; }
-		|	GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems
+		|	SET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGSetDescItems
 			{  $$.str = $5; $$.name = $3; }
 		;
 
+ECPGSetDescItems: ECPGSetDescItem
+		| ECPGSetDescItems ',' ECPGSetDescItem
+		;
+
+ECPGSetDescItem: descriptor_item '=' CVARIABLE		{ push_assignment($3, $1); };
+
+
+descriptor_item:	SQL_CARDINALITY			{ $$ = ECPGd_cardinality; }
+		| SQL_DATA				{ $$ = ECPGd_data; }
+		| SQL_DATETIME_INTERVAL_CODE		{ $$ = ECPGd_di_code; }
+		| SQL_DATETIME_INTERVAL_PRECISION 	{ $$ = ECPGd_di_precision; }
+		| SQL_INDICATOR				{ $$ = ECPGd_indicator; }
+		| SQL_KEY_MEMBER			{ $$ = ECPGd_key_member; }
+		| SQL_LENGTH				{ $$ = ECPGd_length; }
+		| SQL_NAME				{ $$ = ECPGd_name; }
+		| SQL_NULLABLE				{ $$ = ECPGd_nullable; }
+		| SQL_OCTET_LENGTH			{ $$ = ECPGd_octet; }
+		| PRECISION				{ $$ = ECPGd_precision; }
+		| SQL_RETURNED_LENGTH			{ $$ = ECPGd_length; }
+		| SQL_RETURNED_OCTET_LENGTH		{ $$ = ECPGd_ret_octet; }
+		| SQL_SCALE				{ $$ = ECPGd_scale; }
+		| TYPE_P				{ $$ = ECPGd_type; }
+		;
+
+
 /*
  * for compatibility with ORACLE we will also allow the keyword RELEASE
  * after a transaction statement to disconnect from the database.
@@ -5431,11 +5453,8 @@ ECPGTypedef: TYPE_P
 				for (ptr = types; ptr != NULL; ptr = ptr->next)
 				{
 					if (strcmp($3, ptr->name) == 0)
-					{
 						/* re-definition is a bug */
-						snprintf(errortext, sizeof(errortext), "Type %s already defined", $3);
-						mmerror(PARSE_ERROR, ET_ERROR, errortext);
-					}
+						mmerror(PARSE_ERROR, ET_ERROR, "Type %s already defined", $3);
 				}
 
 				adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false);
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 70db72ebab27e28367b726865daed9a4e4a1d68e..77caff9ac2ab58765d1d1536fc4867fc883e0706 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -195,8 +195,7 @@ get_type(enum ECPGttype type)
 			return ("ECPGt_timestamp");
 			break;
 		default:
-			sprintf(errortext, "illegal variable type %d\n", type);
-			yyerror(errortext);
+			mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type);
 	}
 
 	return NULL;
@@ -538,8 +537,7 @@ ECPGfree_type(struct ECPGtype * type)
 				ECPGfree_struct_member(type->u.members);
 				break;
 			default:
-				sprintf(errortext, "illegal variable type %d\n", type->type);
-				yyerror(errortext);
+				mmerror(PARSE_ERROR, ET_ERROR, "illegal variable type %d\n", type->type);
 				break;
 		}
 	}
@@ -598,8 +596,7 @@ get_dtype(enum ECPGdtype type)
 		case ECPGd_cardinality:
 			return ("ECPGd_cardinality");
 		default:
-			sprintf(errortext, "illegal descriptor item %d\n", type);
-			yyerror(errortext);
+			mmerror(PARSE_ERROR, ET_ERROR, "illegal descriptor item %d\n", type);
 	}
 
 	return NULL;
diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c
index f13f7375cb0f0a84e14d4f3692e8535e1d8092de..081ed27ca3af5b3c2204d7ec152ba2062dcb5092 100644
--- a/src/interfaces/ecpg/preproc/variable.c
+++ b/src/interfaces/ecpg/preproc/variable.c
@@ -84,10 +84,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in
 					case '\0':	/* found the end, but this time it has to
 								 * be an array element */
 						if (members->type->type != ECPGt_array)
-						{
-							snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name);
-							mmerror(PARSE_ERROR, ET_FATAL, errortext);
-						}
+							mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
 
 						switch (members->type->u.element->type)
 						{
@@ -110,8 +107,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member * members, in
 							return (find_struct_member(name, end, members->type->u.members, brace_level));
 						break;
 					default:
-						snprintf(errortext, sizeof(errortext), "incorrectly formed variable %s", name);
-						mmerror(PARSE_ERROR, ET_FATAL, errortext);
+						mmerror(PARSE_ERROR, ET_FATAL, "incorrectly formed variable %s", name);
 						break;
 				}
 			}
@@ -134,16 +130,10 @@ find_struct(char *name, char *next, char *end)
 	if (c == '-')
 	{
 		if (p->type->type != ECPGt_array)
-		{
-			snprintf(errortext, sizeof(errortext), "variable %s is not a pointer", name);
-			mmerror(PARSE_ERROR, ET_FATAL, errortext);
-		}
+			mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer", name);
 
 		if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
-		{
-			snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
-			mmerror(PARSE_ERROR, ET_FATAL, errortext);
-		}
+			mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
 
 		/* restore the name, we will need it later */
 		*next = c;
@@ -155,10 +145,7 @@ find_struct(char *name, char *next, char *end)
 		if (next == end)
 		{
 			if (p->type->type != ECPGt_struct && p->type->type != ECPGt_union)
-			{
-				snprintf(errortext, sizeof(errortext), "variable %s is neither a structure nor a union", name);
-				mmerror(PARSE_ERROR, ET_FATAL, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_FATAL, "variable %s is neither a structure nor a union", name);
 
 			/* restore the name, we will need it later */
 			*next = c;
@@ -168,16 +155,10 @@ find_struct(char *name, char *next, char *end)
 		else
 		{
 			if (p->type->type != ECPGt_array)
-			{
-				snprintf(errortext, sizeof(errortext), "variable %s is not an array", name);
-				mmerror(PARSE_ERROR, ET_FATAL, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not an array", name);
 
 			if (p->type->u.element->type != ECPGt_struct && p->type->u.element->type != ECPGt_union)
-			{
-				snprintf(errortext, sizeof(errortext), "variable %s is not a pointer to a structure or a union", name);
-				mmerror(PARSE_ERROR, ET_FATAL, errortext);
-			}
+				mmerror(PARSE_ERROR, ET_FATAL, "variable %s is not a pointer to a structure or a union", name);
 
 			/* restore the name, we will need it later */
 			*next = c;
@@ -243,10 +224,8 @@ find_variable(char *name)
 				*next = '\0';
 				p = find_simple(name);
 				if (p == NULL)
-				{
-					snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
-					mmerror(PARSE_ERROR, ET_FATAL, errortext);
-				}			   
+					mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
+
 				*next = c;
 				switch (p->type->u.element->type)
 				{
@@ -267,10 +246,7 @@ find_variable(char *name)
 		p = find_simple(name);
 
 	if (p == NULL)
-	{
-		snprintf(errortext, sizeof(errortext), "The variable %s is not declared", name);
-		mmerror(PARSE_ERROR, ET_FATAL, errortext);
-	}
+		mmerror(PARSE_ERROR, ET_FATAL, "The variable %s is not declared", name);
 
 	return (p);
 }
@@ -490,10 +466,7 @@ get_typedef(char *name)
 
 	for (this = types; this && strcmp(this->name, name); this = this->next);
 	if (!this)
-	{
-		snprintf(errortext, sizeof(errortext), "invalid datatype '%s'", name);
-		mmerror(PARSE_ERROR, ET_FATAL, errortext);
-	}
+		mmerror(PARSE_ERROR, ET_FATAL, "invalid datatype '%s'", name);
 
 	return (this);
 }
@@ -521,10 +494,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
 	}
 
 	if (pointer_len > 2)
-	{
-		snprintf(errortext, sizeof(errortext), "No multilevel (more than 2) pointer supported %d", pointer_len);
-		mmerror(PARSE_ERROR, ET_FATAL, errortext);
-	}
+		mmerror(PARSE_ERROR, ET_FATAL, "No multilevel (more than 2) pointer supported %d", pointer_len);
 
 	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char)
 		mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
diff --git a/src/interfaces/ecpg/test/test_desc.pgc b/src/interfaces/ecpg/test/test_desc.pgc
new file mode 100644
index 0000000000000000000000000000000000000000..edfa699cdcb597e9c7a3f8b506c2dcbd2519a872
--- /dev/null
+++ b/src/interfaces/ecpg/test/test_desc.pgc
@@ -0,0 +1,69 @@
+EXEC SQL WHENEVER SQLERROR SQLPRINT;
+
+int
+main()
+{
+	EXEC SQL BEGIN DECLARE SECTION;
+	char *stmt1 = "INSERT INTO test1 VALUES (?, ?)";
+	char *stmt2 = "SELECT * from test1 where a = ? and b = ?";
+
+	int val1 = 1;
+	char val2[] = "one", val2output[] = "AAA";
+	int val1output = 2, val2i = 0;
+	int val2null = 1;
+	EXEC SQL END DECLARE SECTION;
+	FILE *dbgs;
+
+        if ((dbgs = fopen("log", "w")) != NULL)
+                ECPGdebug(1, dbgs);
+
+	EXEC SQL ALLOCATE DESCRIPTOR indesc;
+	EXEC SQL ALLOCATE DESCRIPTOR outdesc;
+
+	EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1;
+	EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2;
+
+	EXEC SQL CONNECT TO mm;
+
+	EXEC SQL CREATE TABLE test1 (a int, b text);
+	EXEC SQL PREPARE foo1 FROM :stmt1;
+	EXEC SQL PREPARE foo2 FROM :stmt2;
+
+	EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc;
+
+	//EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = 2;
+	EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1output;
+	EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2null, DATA = :val2;
+	
+	EXEC SQL EXECUTE foo1 USING DESCRIPTOR indesc;
+
+	EXEC SQL SET DESCRIPTOR indesc VALUE 1 DATA = :val1;
+	EXEC SQL SET DESCRIPTOR indesc VALUE 2 INDICATOR = :val2i, DATA = :val2;
+
+	EXEC SQL EXECUTE foo2 USING DESCRIPTOR indesc INTO DESCRIPTOR outdesc;
+	
+	EXEC SQL GET DESCRIPTOR outdesc VALUE 1 :val2output = DATA;
+	printf("output = %s\n", val2output);
+	
+	EXEC SQL DECLARE c CURSOR FOR foo2;
+	EXEC SQL OPEN c USING DESCRIPTOR indesc;
+
+	EXEC SQL FETCH next FROM c INTO :val1output, :val2output;
+	printf("val1=%d val2=%s\n", val1output, val2output);
+
+	EXEC SQL CLOSE c;
+	
+	EXEC SQL SELECT * INTO :val1output, :val2output FROM test1 where a = 2;
+	printf("val1=%d val2=%s\n", val1output, val2output);
+	
+	EXEC SQL DROP TABLE test1;
+	EXEC SQL DISCONNECT;
+
+	EXEC SQL DEALLOCATE DESCRIPTOR indesc;
+	EXEC SQL DEALLOCATE DESCRIPTOR outdesc;
+
+	if (dbgs != NULL)
+		fclose(dbgs);
+			
+	return 0;
+}