From 25ad1439e100f3ec8917b322789d838ae7b64e5e Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Tue, 17 Feb 1998 01:48:12 +0000 Subject: [PATCH] Major update of ecpg preprocessor From: Michael Meskes --- src/interfaces/Makefile | 4 +- src/interfaces/ecpg/ChangeLog | 14 + src/interfaces/ecpg/TODO | 7 +- src/interfaces/ecpg/lib/Makefile.in | 2 +- src/interfaces/ecpg/preproc/ecpg.c | 7 +- src/interfaces/ecpg/preproc/extern.h | 1 + src/interfaces/ecpg/preproc/pgc.l | 8 + src/interfaces/ecpg/preproc/preproc.y | 78 ++++- src/interfaces/ecpg/preproc/type.c | 466 +++++++++++++++----------- src/interfaces/ecpg/preproc/type.h | 12 +- src/interfaces/ecpg/test/mm.sql | 12 +- src/interfaces/ecpg/test/test2.pgc | 13 +- src/man/ecpg.1 | 3 - 13 files changed, 376 insertions(+), 251 deletions(-) diff --git a/src/interfaces/Makefile b/src/interfaces/Makefile index cf83ff0839..5dac21202c 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 13701891d7..bee83ee51d 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 24c1f15df6..832cd66dab 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 e19859eda7..d540b29d79 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 e4a1a78812..a06c27b24e 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 e9f5d8fb14..9a3f9e12b6 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 4e81182b80..63e9f8d6e8 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; } {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 827c5c40cf..79eec60af1 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 S_SYMBOL S_LENGTH S_ANYTHING %token S_VARCHAR S_VARCHAR2 -%token S_EXTERN S_STATIC +%token S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT %token S_UNSIGNED S_SIGNED %token S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL %token '[' ']' ';' ',' '{' '}' -%type type type_detailed varchar_type simple_type array_type +%type type type_detailed varchar_type simple_type array_type struct_type %type symbol %type maybe_storage_clause varchar_tag %type simple_tag @@ -227,8 +233,12 @@ variable_declarations : /* empty */ /* Here is where we can enter support for typedef. */ variable_declaration : type ';' { - new_variable($1.name, $1.typ); - free($1.name); + /* don't worry about our list when we're working on a struct */ + if (struct_level == 0) + { + new_variable($1.name, $1.typ); + free($1.name); + } fprintf(yyout, ";"); } @@ -244,12 +254,18 @@ symbol : S_SYMBOL { type : maybe_storage_clause type_detailed { $$ = $2; }; type_detailed : varchar_type { $$ = $1; } | simple_type { $$ = $1; } - | array_type {$$ = $1; }; + | array_type {$$ = $1; } + | struct_type {$$ = $1; }; varchar_type : varchar_tag symbol index { fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $3, $2); - $$.name = $2; - $$.typ = ECPGmake_varchar_type(ECPGt_varchar, $3); + if (struct_level == 0) + { + $$.name = $2; + $$.typ = ECPGmake_varchar_type(ECPGt_varchar, $3); + } + else + ECPGmake_record_member($2, ECPGmake_varchar_type(ECPGt_varchar, $3), &(record_member_list[struct_level-1])); } varchar_tag : S_VARCHAR { $$ = $1; } @@ -257,14 +273,42 @@ varchar_tag : S_VARCHAR { $$ = $1; } simple_type : simple_tag symbol { fprintf(yyout, "%s %s", ECPGtype_name($1), $2); - $$.name = $2; - $$.typ = ECPGmake_simple_type($1); + if (struct_level == 0) + { + $$.name = $2; + $$.typ = ECPGmake_simple_type($1); + } + else + ECPGmake_record_member($2, ECPGmake_simple_type($1), &(record_member_list[struct_level-1])); } array_type : simple_tag symbol index { fprintf(yyout, "%s %s [%d]", ECPGtype_name($1), $2, $3); - $$.name = $2; - $$.typ = ECPGmake_array_type(ECPGmake_simple_type($1), $3); + if (struct_level == 0) + { + $$.name = $2; + $$.typ = ECPGmake_array_type(ECPGmake_simple_type($1), $3); + } + else + ECPGmake_record_member($2, ECPGmake_array_type(ECPGmake_simple_type($1), $3), &(record_member_list[struct_level-1])); +} + +s_struct : S_STRUCT symbol { + struct_level++; + fprintf(yyout, "struct %s {", $2); +} + +struct_type : s_struct '{' variable_declarations '}' symbol { + struct_level--; + if (struct_level == 0) + { + $$.name = $5; + $$.typ = ECPGmake_record_type(record_member_list[struct_level]); + } + else + ECPGmake_record_member($5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); + fprintf(yyout, "} %s", $5); + record_member_list[struct_level] = NULL; } simple_tag : S_CHAR { $$ = ECPGt_char; } @@ -281,6 +325,9 @@ simple_tag : S_CHAR { $$ = 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 e3ee2f003a..ae6b0997da 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -1,274 +1,302 @@ #include #include +#include #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->name = strdup(name); + ne->typ = type; + ne->next = NULL; - return ne; + for (ptr = *start; ptr && ptr->next; ptr = ptr->next); + + 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 - enum ECPGttype - reference-to-variable - void * - size - short size of this field (if varchar) - arrsize - short number of elements in the arr - offset - short offset to the next element + type-tag - enum ECPGttype + reference-to-variable - void * + size - short size of this field (if varchar) + arrsize - short number of elements in the arr + offset - 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 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; - } + 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++) - { - 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 (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); - 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(); - } - } + 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 6726683bd5..73fa380483 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 923825fabb..4f3357b7e8 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 923c9d0c38..37533515c3 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 00246dd44a..9d9db42d28 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"