diff --git a/src/interfaces/Makefile b/src/interfaces/Makefile
index cf83ff0839d8878e09199c07250226f5c06e320b..5dac21202cf6d1e4cdb715cb7fc2662251c53056 100644
--- a/src/interfaces/Makefile
+++ b/src/interfaces/Makefile
@@ -7,7 +7,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/interfaces/Makefile,v 1.6 1998/02/12 02:14:14 scrappy Exp $
+#    $Header: /cvsroot/pgsql/src/interfaces/Makefile,v 1.7 1998/02/17 01:47:19 scrappy Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -16,7 +16,7 @@ include $(SRCDIR)/Makefile.global
 
 .DEFAULT all:
 	$(MAKE) -C libpq $@
-#	$(MAKE) -C ecpg $@
+	$(MAKE) -C ecpg $@
 ifeq ($(HAVE_Cplusplus), true)
 	$(MAKE) -C libpq++ $@
 else
diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 13701891d7432092f939ed9bc9e968b607fe6eaa..bee83ee51d3b9286609c2c65f37c54fb2ae0f02c 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -9,3 +9,17 @@ Wed Feb 11 10:58:13 CET 1998
 Thu Feb 12 14:45:07 CET 1998
 
 	- Changed parser to correctly handle local variables.
+        - Allow static and extern variable definitions.
+        - free() variable structure completely.
+
+Fri Feb 13 12:35:58 CET 1998
+
+      - ecpg can use structs to store data, but only if the complete
+        definition of the struct lies inside the sql declare section
+        and only simple types used.
+
+Fre Feb 13 14:12:41 CET 1998
+
+      - Structure now work completely.
+
+
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 24c1f15df6fc04d79559e00b5e7e541381525356..832cd66dab9ecbbbe1b8d01608d05e5d607b7dff 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -16,10 +16,6 @@ just -1 for them all.
     
 Missing library functions to_date et al.
     
-Possibility to define records or structs in the declare section in a way
-that the record can be filled from one row in the database. This is a
-simpler way to handle an entire row at a time.
-    
 Oracle has array operations that enhances speed. When implementing it in
 ecpg it is done for compatibility reasons only. For them to improve speed
 would require a lot more insight in the postgres internal mechanisms than I
@@ -44,5 +40,6 @@ could be realised in a script.
 
 Now comes my list (MM):
 
-Variable definitions containing static/volatile have to be possible.
+What do we do with enum data types?
 
+'signed' isn't understood so far
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index e19859eda7b186665c799bc063a32622f73d1ef1..d540b29d792e40136f9425ca7977ecc87d08a30a 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -47,7 +47,7 @@ $(shlib): ecpglib.o typename.o
 clean:
 	rm -f *.o *.a core a.out *~ $(shlib) libecpg.so
 
-install: libecpg.a
+install: libecpg.a $(shlib)
 	install -m 644 libecpg.a $(DESTDIR)$(LIBDIR)
 	install -m 644 $(shlib) $(DESTDIR)$(LIBDIR)
 	ln -sf $(shlib) $(DESTDIR)$(LIBDIR)/libecpg.so
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index e4a1a78812af11b8b20aaf3f7ea985dcae8c1ff6..a06c27b24eb3af3762363cec5fbc686df63037cc 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -51,12 +51,7 @@ main(int argc, char *const argv[])
 		{
 			char	   *filename, *ptr2ext;
 
-			filename = malloc(strlen(argv[fnr]) + 2);
-			if (filename == NULL)
-			{
-				perror("malloc");
-				continue;
-			}
+			filename = mm_alloc(strlen(argv[fnr]) + 2);
 
 			strcpy(filename, argv[fnr]);
 
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index e9f5d8fb14f5fa13a1e9e114b6fb72c54697a0df..9a3f9e12b6e8ec801ec4d0c16022d71433243e9b 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -11,3 +11,4 @@ extern FILE *yyin, *yyout;
 extern void lex_init(void);
 extern char * input_filename;
 extern int yyparse(void);
+extern void *mm_alloc(size_t);
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 4e81182b804c338850879f4729b5649498d9e24b..63e9f8d6e840714cde72aa509086c52aecbdd6a7 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -58,6 +58,14 @@ float			{ dbg(S_FLOAT); return S_FLOAT; }
 double			{ dbg(S_DOUBLE); return S_DOUBLE; }
 bool                    { dbg(S_BOOL); return S_BOOL; }
 
+static			{ dbg(S_STATIC); return S_STATIC; }
+extern			{ dbg(S_EXTERN); return S_EXTERN; }
+auto			{ dbg(S_AUTO); return S_AUTO; }
+const			{ dbg(S_CONST); return S_CONST; }
+register		{ dbg(S_REGISTER); return S_REGISTER; }
+
+struct			{ dbg(S_STRUCT); return S_STRUCT; }
+
 {string}		{ dbg(SQL_STRING); return SQL_STRING; }
 <SQL>{ws}		; 
 {symbol}		{ dbg(S_SYMBOL); return S_SYMBOL; }
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 827c5c40cf5a0062673ca1a9bd053f055d0c8559..79eec60af12ccb55fc2e48924e558dc8c100eeca 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -12,7 +12,11 @@ static void yyerror(char *);
 /*
  * Variables containing simple states.
  */
-int    debugging = 0;
+int	debugging = 0;
+static int	struct_level = 0;
+
+/* temporarily store record members while creating the data structure */
+struct ECPGrecord_member *record_member_list[128] = { NULL };
 
 /*
  * Handle the filename and line numbering.
@@ -86,7 +90,7 @@ remove_variables(int brace_level)
 {
     struct variable * p, *prev;
 
-    for (p = prev = allvariables; p; p = p->next)
+    for (p = prev = allvariables; p; p = p ? p->next : NULL)
     {
 	if (p->brace_level >= brace_level)
 	{
@@ -96,6 +100,8 @@ remove_variables(int brace_level)
 	    else
 		prev->next = p->next;
 
+	    ECPGfree_type(p->type);
+	    free(p->name);
 	    free(p);
 	    p = prev;
 	}
@@ -157,7 +163,7 @@ dump_variables(struct arguments * list)
     dump_variables(list->next);
 
     /* Then the current element. */
-    ECPGdump_a_type(yyout, list->variable->name, list->variable->type);
+    ECPGdump_a_type(yyout, list->variable->name, list->variable->type, NULL);
 
     /* Then release the list element. */
     free(list);
@@ -179,12 +185,12 @@ dump_variables(struct arguments * list)
 
 %token <tagname> S_SYMBOL S_LENGTH S_ANYTHING
 %token <tagname> S_VARCHAR S_VARCHAR2
-%token <tagname> S_EXTERN S_STATIC
+%token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT
 %token <tagname> S_UNSIGNED S_SIGNED
 %token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL
 %token <tagname> '[' ']' ';' ',' '{' '}'
 
-%type <type> type type_detailed varchar_type simple_type array_type
+%type <type> type type_detailed varchar_type simple_type array_type struct_type
 %type <symbolname> symbol
 %type <tagname> maybe_storage_clause varchar_tag
 %type <type_enum> simple_tag
@@ -227,8 +233,12 @@ variable_declarations : /* empty */
 
 /* Here is where we can enter support for typedef. */
 variable_declaration : type ';'	{ 
-    new_variable($<type>1.name, $<type>1.typ);
-    free($<type>1.name);
+    /* don't worry about our list when we're working on a struct */
+    if (struct_level == 0)
+    {
+	new_variable($<type>1.name, $<type>1.typ);
+	free($<type>1.name);
+    }
     fprintf(yyout, ";"); 
 }
 
@@ -244,12 +254,18 @@ symbol : S_SYMBOL {
 type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
 type_detailed : varchar_type { $<type>$ = $<type>1; }
 	      | simple_type { $<type>$ = $<type>1; }
-	      | array_type {$<type>$ = $<type>1; };
+	      | array_type {$<type>$ = $<type>1; }
+	      | struct_type {$<type>$ = $<type>1; };
 
 varchar_type : varchar_tag symbol index {
     fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2);
-    $<type>$.name = $<symbolname>2;
-    $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3);
+    if (struct_level == 0)
+    {
+	$<type>$.name = $<symbolname>2;
+	$<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3);
+    }
+    else
+	ECPGmake_record_member($<symbolname>2, ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3), &(record_member_list[struct_level-1]));
 }
 
 varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; }
@@ -257,14 +273,42 @@ varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; }
 
 simple_type : simple_tag symbol {
     fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
-    $<type>$.name = $<symbolname>2;
-    $<type>$.typ = ECPGmake_simple_type($<type_enum>1);
+    if (struct_level == 0)
+    {
+	$<type>$.name = $<symbolname>2;
+	$<type>$.typ = ECPGmake_simple_type($<type_enum>1);
+    }
+    else
+        ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1), &(record_member_list[struct_level-1]));
 }
 
 array_type : simple_tag symbol index {
     fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
-    $<type>$.name = $<symbolname>2;
-    $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3);
+    if (struct_level == 0)
+    {
+	$<type>$.name = $<symbolname>2;
+	$<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3);
+    }
+    else
+	ECPGmake_record_member($<symbolname>2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3), &(record_member_list[struct_level-1]));
+}
+
+s_struct : S_STRUCT symbol {
+    struct_level++;
+    fprintf(yyout, "struct %s {", $<symbolname>2);
+}
+
+struct_type : s_struct '{' variable_declarations '}' symbol {
+    struct_level--;
+    if (struct_level == 0)
+    {
+	$<type>$.name = $<symbolname>5;
+	$<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
+    }
+    else
+	ECPGmake_record_member($<symbolname>5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
+    fprintf(yyout, "} %s", $<symbolname>5);
+    record_member_list[struct_level] = NULL;
 }
 
 simple_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
@@ -281,6 +325,9 @@ simple_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
 
 maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
 		       | S_STATIC { fwrite(yytext, yyleng, 1, yyout); }
+		       | S_CONST { fwrite(yytext, yyleng, 1, yyout); }
+		       | S_REGISTER { fwrite(yytext, yyleng, 1, yyout); }
+		       | S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
                        | /* empty */ { };
   	 
 index : '[' length ']' {
@@ -369,13 +416,14 @@ canything : both_anything
 sqlanything : both_anything;
 
 both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2 
-	  | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE
+	  | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE | S_BOOL
 	  | SQL_OPEN | SQL_CONNECT
 	  | SQL_STRING
 	  | SQL_BEGIN | SQL_END 
 	  | SQL_DECLARE | SQL_SECTION 
 	  | SQL_INCLUDE 
 	  | S_SYMBOL
+	  | S_STATIC | S_EXTERN | S_AUTO | S_CONST | S_REGISTER | S_STRUCT
 	  | '[' | ']' | ','
 	  | S_ANYTHING;
 
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index e3ee2f003ab303e24a97073358f6b429cf32db39..ae6b0997da5a57569a3bcc97d1c7486fc9376296 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -1,274 +1,302 @@
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 
 #include "type.h"
 
+/* malloc + error check */
+void *mm_alloc(size_t size)
+{
+        void *ptr = malloc(size);
+
+        if (ptr == NULL)
+        {
+                fprintf(stderr, "Out of memory\n");
+                exit(1);
+        }
+
+        return (ptr);
+}
+
 /* Constructors
    Yes, I mostly write c++-code
-   */
+ */
 
 /* The NAME argument is copied. The type argument is preserved as a pointer. */
 struct ECPGrecord_member *
-ECPGmake_record_member(char * name, struct ECPGtype * type)
+ECPGmake_record_member(char *name, struct ECPGtype *type, struct ECPGrecord_member **start)
 {
-    struct ECPGrecord_member * ne = 
-	(struct ECPGrecord_member *)malloc(sizeof(struct ECPGrecord_member));
+        struct ECPGrecord_member *ptr, *ne =
+        (struct ECPGrecord_member *) mm_alloc(sizeof(struct ECPGrecord_member));
+
+        ne->name = strdup(name);
+        ne->typ = type;
+        ne->next = NULL;
 
-    ne->name = strdup(name);
-    ne->typ = type;
+        for (ptr = *start; ptr && ptr->next; ptr = ptr->next);
 
-    return ne;
+        if (ptr)
+                ptr->next=ne;
+        else
+                *start=ne;
+        return ne;
 }
 
 struct ECPGtype *
 ECPGmake_simple_type(enum ECPGttype typ)
 {
-    struct ECPGtype * ne = (struct ECPGtype *)malloc(sizeof(struct ECPGtype));
+        struct ECPGtype *ne = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
 
-    ne->typ = typ;
-    ne->size = 0;
-    ne->u.element = 0;
+        ne->typ = typ;
+        ne->size = 0;
+        ne->u.element = 0;
 
-    return ne;
+        return ne;
 }
 
 struct ECPGtype *
 ECPGmake_varchar_type(enum ECPGttype typ, unsigned short siz)
 {
-    struct ECPGtype * ne = ECPGmake_simple_type(typ);
+        struct ECPGtype *ne = ECPGmake_simple_type(typ);
 
-    ne->size = siz;
+        ne->size = siz;
 
-    return ne;
+        return ne;
 }
 
 struct ECPGtype *
-ECPGmake_array_type(struct ECPGtype * typ, unsigned short siz)
+ECPGmake_array_type(struct ECPGtype *typ, unsigned short siz)
 {
-    struct ECPGtype * ne = ECPGmake_simple_type(ECPGt_array);
+        struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array);
 
-    ne->size = siz;
-    ne->u.element = typ;
+        ne->size = siz;
+        ne->u.element = typ;
 
-    return ne;
+        return ne;
 }
 
 struct ECPGtype *
-ECPGmake_record_type(struct ECPGrecord_member * rm[])
+ECPGmake_record_type(struct ECPGrecord_member *rm)
 {
-    struct ECPGtype * ne = ECPGmake_simple_type(ECPGt_record);
+        struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_record);
 
-    ne->u.members = rm;
+        ne->u.members = rm;
 
-    return ne;
+        return ne;
 }
 
 
 /* Dump a type.
    The type is dumped as:
-	type-tag <comma> 		- enum ECPGttype
-	reference-to-variable <comma> 	- void *
-	size <comma>			- short size of this field (if varchar)
-	arrsize <comma>			- short number of elements in the arr
-	offset <comma>			- short offset to the next element
+   type-tag <comma>                - enum ECPGttype
+   reference-to-variable <comma>   - void *
+   size <comma>                    - short size of this field (if varchar)
+   arrsize <comma>                 - short number of elements in the arr
+   offset <comma>                  - short offset to the next element
    Where:
    type-tag is one of the simple types or varchar.
    reference-to-variable can be a reference to a struct element.
    arrsize is the size of the array in case of array fetches. Otherwise 0.
    size is the maxsize in case it is a varchar. Otherwise it is the size of
-   	the variable (required to do array fetches of records).
+   the variable (required to do array fetches of records).
  */
-void ECPGdump_a_simple(FILE * o, const char * name, enum ECPGttype typ, 
-		   short varcharsize,
-		   unsigned short arrsiz, const char * siz);
-void ECPGdump_a_record(FILE * o, const char * name, unsigned short arrsiz,
-		   struct ECPGtype * typ, const char * offset);
+void            ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
+                                                          short varcharsize,
+                                                          unsigned short arrsiz, const char *siz, const char *prefix);
+void            ECPGdump_a_record(FILE *o, const char *name, unsigned short arrsiz,
+                                                          struct ECPGtype *typ, const char *offset, const char *prefix);
 
 
 void
-ECPGdump_a_type(FILE * o, const char * name, struct ECPGtype * typ)
+ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype *typ, const char *prefix)
 {
-    if (IS_SIMPLE_TYPE(typ->typ))
-    {
-	ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0);
-    }
-    else if (typ->typ == ECPGt_array)
-    {
-	if (IS_SIMPLE_TYPE(typ->u.element->typ))
-	    ECPGdump_a_simple(o, name, typ->u.element->typ,
-			  typ->u.element->size, typ->size, 0);
-	else if (typ->u.element->typ == ECPGt_array)
-	{
-	    abort();		/* Array of array, */
-	}
-	else if (typ->u.element->typ == ECPGt_record)
-	{
-	    /* Array of records. */
-	    ECPGdump_a_record(o, name, typ->size, typ->u.element, 0);
-	}
-	else
-	{
-	    abort();
-	}
-    }
-    else if (typ->typ == ECPGt_record)
-    {
-	ECPGdump_a_record(o, name, 0, typ, 0);
-    }
-    else
-    {
-	abort();
-    }
+        if (IS_SIMPLE_TYPE(typ->typ))
+        {
+                ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix);
+        }
+        else if (typ->typ == ECPGt_array)
+        {
+                if (IS_SIMPLE_TYPE(typ->u.element->typ))
+                        ECPGdump_a_simple(o, name, typ->u.element->typ,
+                                                          typ->u.element->size, typ->size, 0, prefix);
+                else if (typ->u.element->typ == ECPGt_array)
+                {
+                        abort();                        /* Array of array, */
+                }
+                else if (typ->u.element->typ == ECPGt_record)
+                {
+                        /* Array of records. */
+                        ECPGdump_a_record(o, name, typ->size, typ->u.element, 0, prefix);
+                }
+                else
+                {
+                        abort();
+                }
+        }
+        else if (typ->typ == ECPGt_record)
+        {
+                ECPGdump_a_record(o, name, 0, typ, 0, prefix);
+        }
+        else
+        {
+                abort();
+        }
 }
 
 
 /* If siz is NULL, then the offset is 0, if not use siz as a
    string, it represents the offset needed if we are in an array of records. */
 void
-ECPGdump_a_simple(FILE * o, const char * name, enum ECPGttype typ,
-		  short varcharsize,
-		  unsigned short arrsiz,
-		  const char * siz)
+ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
+                                  short varcharsize,
+                                  unsigned short arrsiz,
+                                  const char *siz,
+                                  const char *prefix)
 {
-    switch (typ)
-    {
-    case ECPGt_char:
-	fprintf(o, "\n\tECPGt_char,&%s,0,%d,%s, ", name, arrsiz, 
-		siz == NULL ? "sizeof(char)" : siz);
-	break;
-    case ECPGt_unsigned_char:
-	fprintf(o, "\n\tECPGt_unsigned_char,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(unsigned char)" : siz);
-	break;
-    case ECPGt_short:
-	fprintf(o, "\n\tECPGt_short,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(short)" : siz);
-	break; 
-    case ECPGt_unsigned_short:
-	fprintf(o, 
-		"\n\tECPGt_unsigned_short,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(unsigned short)" : siz);
-	break;
-    case ECPGt_int:
-	fprintf(o, "\n\tECPGt_int,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(int)" : siz);
-	break;
-    case ECPGt_unsigned_int:
-	fprintf(o, "\n\tECPGt_unsigned_int,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(unsigned int)" : siz);
-	break;
-    case ECPGt_long:
-	fprintf(o, "\n\tECPGt_long,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(long)" : siz);
-	break;
-    case ECPGt_unsigned_long:
-	fprintf(o, "\n\tECPGt_unsigned_int,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(unsigned int)" : siz);
-	break;
-    case ECPGt_float:
-	fprintf(o, "\n\tECPGt_float,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(float)" : siz);
-	break;
-    case ECPGt_double:
-	fprintf(o, "\n\tECPGt_double,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(double)" : siz);
-	break;
-    case ECPGt_bool:
-	fprintf(o, "\n\tECPGt_bool,&%s,0,%d,%s, ", name, arrsiz,
-		siz == NULL ? "sizeof(bool)" : siz);
-	break;
-    case ECPGt_varchar:
-    case ECPGt_varchar2:
-	if (siz == NULL)
-	    fprintf(o, "\n\tECPGt_varchar,&%s,%d,%d,sizeof(struct varchar_%s), ", 
-		    name,
-		    varcharsize,
-		    arrsiz, name);
-	else
-	    fprintf(o, "\n\tECPGt_varchar,&%s,%d,%d,%s, ", 
-		    name, 
-		    varcharsize,
-		    arrsiz, siz);
-	break;
-    default:
-	abort();
-    }
+        switch (typ)
+        {
+                case ECPGt_char:
+                        fprintf(o, "\n\tECPGt_char,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(char)" : siz);
+                        break;
+                case ECPGt_unsigned_char:
+                        fprintf(o, "\n\tECPGt_unsigned_char,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(unsigned char)" : siz);
+                        break;
+                case ECPGt_short:
+                        fprintf(o, "\n\tECPGt_short,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(short)" : siz);
+                        break;
+                case ECPGt_unsigned_short:
+                        fprintf(o,
+                                  "\n\tECPGt_unsigned_short,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(unsigned short)" : siz);
+                        break;
+                case ECPGt_int:
+                        fprintf(o, "\n\tECPGt_int,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(int)" : siz);
+                        break;
+                case ECPGt_unsigned_int:
+                        fprintf(o, "\n\tECPGt_unsigned_int,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(unsigned int)" : siz);
+                        break;
+                case ECPGt_long:
+                        fprintf(o, "\n\tECPGt_long,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(long)" : siz);
+                        break;
+                case ECPGt_unsigned_long:
+                        fprintf(o, "\n\tECPGt_unsigned_int,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(unsigned int)" : siz);
+                        break;
+                case ECPGt_float:
+                        fprintf(o, "\n\tECPGt_float,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(float)" : siz);
+                        break;
+                case ECPGt_double:
+                        fprintf(o, "\n\tECPGt_double,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(double)" : siz);
+                        break;
+                case ECPGt_bool:
+                        fprintf(o, "\n\tECPGt_bool,&%s%s,0,%d,%s, ", prefix ? prefix : "", name, arrsiz,
+                                        siz == NULL ? "sizeof(bool)" : siz);
+                        break;
+                case ECPGt_varchar:
+                case ECPGt_varchar2:
+                        if (siz == NULL)
+                                fprintf(o, "\n\tECPGt_varchar,&%s%s,%d,%d,sizeof(struct varchar_%s), ",
+                                                prefix ? prefix : "", name,
+                                                varcharsize,
+                                                arrsiz, name);
+                        else
+                                fprintf(o, "\n\tECPGt_varchar,&%s%s,%d,%d,%s, ",
+                                                prefix ? prefix : "", name,
+                                                varcharsize,
+                                                arrsiz, siz);
+                        break;
+                default:
+                        abort();
+        }
 }
 
 
 /* Penetrate a record and dump the contents. */
 void
-ECPGdump_a_record(FILE * o,
-		  const char * name, unsigned short arrsiz,
-		  struct ECPGtype * typ, const char * offsetarg)
+ECPGdump_a_record(FILE *o, const char *name, unsigned short arrsiz, struct ECPGtype *typ, const char *offsetarg, const char *prefix)
 {
-    /* If offset is NULL, then this is the first recursive level. If not then 
-       we are in a record in a record and the offset is used as offset.
-     */
-    struct ECPGrecord_member ** p;
-    char obuf[BUFSIZ];
-    char buf[BUFSIZ];
-    const char * offset;
-
-    if (offsetarg == NULL)
-    {
-	sprintf(obuf, "sizeof(%s)", name);
-	offset = obuf;
-    }
-    else
-    {
-	offset = offsetarg;
-    }
-
-    for (p = typ->u.members; *p; p++)
-    {
-	if (IS_SIMPLE_TYPE((*p)->typ->typ))
-	{
-	    sprintf(buf, "%s.%s", name, (*p)->name);
-	    ECPGdump_a_simple(o, buf, (*p)->typ->typ, (*p)->typ->size,
-			  arrsiz, offset);
-	}
-	else if ((*p)->typ->typ == ECPGt_array)
-	{
-	    int i;
-
-	    for (i = 0; i < (*p)->typ->size; i++)
-	    {
-		if (IS_SIMPLE_TYPE((*p)->typ->u.element->typ))
-		{
-		    sprintf(buf, "%s.%s[%d]", name, (*p)->name, i);
-		    ECPGdump_a_simple(o, buf, (*p)->typ->typ, (*p)->typ->size,
-				      arrsiz, offset);
-		}
-		else if((*p)->typ->u.element->typ == ECPGt_array)
-		{
-		    /* Array within an array. NOT implemented yet. */
-		    abort();
-		}
-		else if ((*p)->typ->u.element->typ == ECPGt_record)
-		{
-		    /* Record within array within record. NOT implemented yet. */
-		    abort();
-		}
-		else	
-		{
-		    /* Unknown type */
-		    abort();
-		}
-	    }
-	}
-	else if ((*p)->typ->typ == ECPGt_record)
-	{
-	    /* Record within a record */
-	    sprintf(buf, "%s.%s", name, (*p)->name);
-	    ECPGdump_a_record(o, buf, arrsiz, (*p)->typ, offset);
-	}
-	else
-	{
-	    /* Unknown type */
-	    abort();
-	}
-    }
+        /* If offset is NULL, then this is the first recursive level. If not then
+           we are in a record in a record and the offset is used as offset.
+         */
+        struct ECPGrecord_member *p;
+        char            obuf[BUFSIZ];
+        char		pbuf[BUFSIZ];
+        const char *offset;
+
+        if (offsetarg == NULL)
+        {
+                sprintf(obuf, "sizeof(%s)", name);
+                offset = obuf;
+        }
+        else
+        {
+                offset = offsetarg;
+        }
+        
+       	sprintf(pbuf, "%s%s.", prefix ? prefix : "", name);
+       	prefix = pbuf;
+
+        for (p = typ->u.members; p; p=p->next)
+        {
+#if 0
+                if (IS_SIMPLE_TYPE(p->typ->typ))
+                {
+                        sprintf(buf, "%s.%s", name, p->name);
+                        ECPGdump_a_simple(o, buf, p->typ->typ, p->typ->size,
+                                                          arrsiz, offset);
+                }
+                else if (p->typ->typ == ECPGt_array)
+                {
+                        int                     i;
+
+                        for (i = 0; i < p->typ->size; i++)
+                        {
+                                if (IS_SIMPLE_TYPE(p->typ->u.element->typ))
+                                {
+                                        /* sprintf(buf, "%s.%s[%d]", name, p->name, i); */
+                                        sprintf(buf, "%s.%s", name, p->name);
+                                        ECPGdump_a_simple(o, buf, p->typ->u.element->typ, p->typ->u.element->size,
+                                                                          p->typ->u.element->size, offset);
+                                }
+                                else if (p->typ->u.element->typ == ECPGt_array)
+                                {
+                                        /* Array within an array. NOT implemented. */
+                                        abort();
+                                }
+                                else if (p->typ->u.element->typ == ECPGt_record)
+                                {
+                                        /* Record within array within record. NOT implemented yet. */
+                                        abort();
+                                }
+                                else
+                                {
+                                        /* Unknown type */
+                                        abort();
+                                }
+                        }
+                }
+                else if (p->typ->typ == ECPGt_record)
+                {
+                        /* Record within a record */
+                        sprintf(buf, "%s.%s", name, p->name);
+                        ECPGdump_a_record(o, buf, arrsiz, p->typ, offset);
+                }
+                else
+                {
+                        /* Unknown type */
+                        abort();
+                }
+#endif
+		ECPGdump_a_type(o, p->name, p->typ, prefix);
+        }
 }
 
 
@@ -276,11 +304,43 @@ ECPGdump_a_record(FILE * o,
    anyway. Lets implement that last! */
 
 void
-ECPGfree_record_member(struct ECPGrecord_member * rm)
+ECPGfree_record_member(struct ECPGrecord_member *rm)
 {
+        while (rm)
+        {
+                struct ECPGrecord_member *p = rm;
+
+                rm = rm->next;
+                free(p->name);
+                free(p);
+        }
 }
 
 void
-ECPGfree_type(struct ECPGtype * typ)
+ECPGfree_type(struct ECPGtype *typ)
 {
+        if (!IS_SIMPLE_TYPE(typ->typ))
+        {
+                if (typ->typ == ECPGt_array)
+                {
+                        if (IS_SIMPLE_TYPE(typ->u.element->typ))
+                                free(typ->u.element);
+                        else if (typ->u.element->typ == ECPGt_array)
+                                abort();                /* Array of array, */
+                        else if (typ->u.element->typ == ECPGt_record)
+                                /* Array of records. */
+                                ECPGfree_record_member(typ->u.members);
+                        else
+                                abort();
+                }
+                else if (typ->typ == ECPGt_record)
+                {
+                        ECPGfree_record_member(typ->u.members);
+                }
+                else
+                {
+                        abort();
+                }
+        }
+        free(typ);
 }
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index 6726683bd581d7ae7de7bbd8c1639eb08d4302b0..73fa38048362d824551f4847321e9f60db28e1a8 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -4,7 +4,9 @@ struct ECPGtype;
 struct ECPGrecord_member {
     char *		name;
     struct ECPGtype *	typ;
+    struct ECPGrecord_member * next;
 };
+
 struct ECPGtype {
     enum ECPGttype	typ;
     unsigned short	size;	/* For array it is the number of elements.
@@ -14,17 +16,17 @@ struct ECPGtype {
 	struct ECPGtype * element;	/* For an array this is the type of the 
 				 * element */
 
-	struct ECPGrecord_member ** members;
-				/* A pointer to an array of members. */
+	struct ECPGrecord_member * members;
+				/* A pointer to a list of members. */
     } u;
 };
 
 /* Everything is malloced. */
-struct ECPGrecord_member * ECPGmake_record_member(char *, struct ECPGtype *);
+struct ECPGrecord_member * ECPGmake_record_member(char *, struct ECPGtype *, struct ECPGrecord_member **);
 struct ECPGtype * ECPGmake_simple_type(enum ECPGttype);
 struct ECPGtype * ECPGmake_varchar_type(enum ECPGttype, unsigned short);
 struct ECPGtype * ECPGmake_array_type(struct ECPGtype *, unsigned short);
-struct ECPGtype * ECPGmake_record_type(struct ECPGrecord_member *[]);
+struct ECPGtype * ECPGmake_record_type(struct ECPGrecord_member *);
 
 /* Frees a type. */
 void ECPGfree_record_member(struct ECPGrecord_member *);
@@ -40,7 +42,7 @@ void ECPGfree_type(struct ECPGtype *);
    size is the maxsize in case it is a varchar. Otherwise it is the size of 
        the variable (required to do array fetches of records).
  */
-void ECPGdump_a_type(FILE *, const char * name, struct ECPGtype *);
+void ECPGdump_a_type(FILE *, const char * name, struct ECPGtype *, const char *);
 
 /* A simple struct to keep a variable and its type. */
 struct ECPGtemp_type {
diff --git a/src/interfaces/ecpg/test/mm.sql b/src/interfaces/ecpg/test/mm.sql
index 923825fabb121ed5ab7e04b3bd3f059f1b3202cc..4f3357b7e816a8a229a93eae22dd08b81be59c39 100644
--- a/src/interfaces/ecpg/test/mm.sql
+++ b/src/interfaces/ecpg/test/mm.sql
@@ -1,8 +1,8 @@
-create table meskes(name char8, born int4);
+create table meskes(name char8, born int4, age int2);
 
-insert into meskes(name, born) values ('Petra', 19661202);
-insert into meskes(name, born) values ('Michael', 19660117);
-insert into meskes(name, born) values ('Carsten', 19910103);
-insert into meskes(name, born) values ('Marc', 19930907);
-insert into meskes(name, born) values ('Chris', 19970923);
+insert into meskes(name, born) values ('Petra', 19661202, 31);
+insert into meskes(name, born) values ('Michael', 19660117, 32);
+insert into meskes(name, born) values ('Carsten', 19910103, 7);
+insert into meskes(name, born) values ('Marc', 19930907, 4);
+insert into meskes(name, born) values ('Chris', 19970923, 0);
 
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index 923c9d0c380ed0cadfb151f6d96cfd9aca64e109..37533515c3d86566480e183ffb28555d505b7580 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -18,8 +18,11 @@ int
 main ()
 {
 exec sql begin declare section;
-	varchar name[8];
-	long born;
+	struct personal_struct	{	varchar name[8];
+					struct birth_struct {	long born;
+								short age;
+							    } birth;
+				} personal;
 exec sql end declare section;
 	FILE *dbgs;
 
@@ -31,7 +34,7 @@ exec sql end declare section;
 		db_error ("connect");
 
 	exec sql declare cur cursor for 
-		select name, born from meskes;
+		select name, born, age from meskes;
 	if (SQLCODE) db_error ("declare");
 
 	exec sql open cur;
@@ -39,10 +42,10 @@ exec sql end declare section;
 		db_error ("open");
 
 	while (1) {
-		exec sql fetch in cur into :name, :born;
+		exec sql fetch in cur into :personal;
 		if (SQLCODE)
 			break;
-		printf ("%8.8s was born %d\n", name.arr, born);
+		printf ("%8.8s was born %d (age = %d)\n", personal.name.arr, personal.birth.born, personal.birth.age);
 	}
 
 	if (SQLCODE < 0)
diff --git a/src/man/ecpg.1 b/src/man/ecpg.1
index 00246dd44a1d416bc77c8a0bf4ae9fbd8779cb08..9d9db42d288dbf6b377d6bdd400437a6b68a952e 100644
--- a/src/man/ecpg.1
+++ b/src/man/ecpg.1
@@ -43,9 +43,6 @@ foo.bar.
 .BR "file1, file2, ..."
 The files to be processed.
 .SH "BUGS"
-This version of ecpg is not able to handle structures inside the sql declare
-blocks.
-.TP
 The return code is alway -1 in case of an error. You cannot see which error
 occured by examining the return code.
 .SH "RETURN VALUE"