aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-02-17 01:48:12 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-02-17 01:48:12 +0000
commit25ad1439e100f3ec8917b322789d838ae7b64e5e (patch)
tree466616915031bc0b7aa2ad030587e5d9f742c624
parent30f737f6b1fc7f4d2ff685230ef97add5f457810 (diff)
downloadpostgresql-25ad1439e100f3ec8917b322789d838ae7b64e5e.tar.gz
postgresql-25ad1439e100f3ec8917b322789d838ae7b64e5e.zip
Major update of ecpg preprocessor
From: Michael Meskes <meskes@topsystem.de>
-rw-r--r--src/interfaces/Makefile4
-rw-r--r--src/interfaces/ecpg/ChangeLog14
-rw-r--r--src/interfaces/ecpg/TODO7
-rw-r--r--src/interfaces/ecpg/lib/Makefile.in2
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c7
-rw-r--r--src/interfaces/ecpg/preproc/extern.h1
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l8
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y78
-rw-r--r--src/interfaces/ecpg/preproc/type.c472
-rw-r--r--src/interfaces/ecpg/preproc/type.h12
-rw-r--r--src/interfaces/ecpg/test/mm.sql12
-rw-r--r--src/interfaces/ecpg/test/test2.pgc13
-rw-r--r--src/man/ecpg.13
13 files changed, 379 insertions, 254 deletions
diff --git a/src/interfaces/Makefile b/src/interfaces/Makefile
index cf83ff0839d..5dac21202cf 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 13701891d74..bee83ee51d3 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 24c1f15df6f..832cd66dab9 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 e19859eda7b..d540b29d792 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 e4a1a78812a..a06c27b24eb 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 e9f5d8fb14f..9a3f9e12b6e 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 4e81182b804..63e9f8d6e84 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 827c5c40cf5..79eec60af12 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 e3ee2f003ab..ae6b0997da5 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 6726683bd58..73fa3804836 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 923825fabb1..4f3357b7e81 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 923c9d0c380..37533515c3d 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 00246dd44a1..9d9db42d288 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"