Major update of ecpg preprocessor

From: Michael Meskes <meskes@topsystem.de>
This commit is contained in:
Marc G. Fournier 1998-02-17 01:48:12 +00:00
parent 30f737f6b1
commit 25ad1439e1
13 changed files with 376 additions and 251 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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]);

View File

@ -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);

View File

@ -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; }

View File

@ -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;

View File

@ -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->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 <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 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);
}

View File

@ -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 {

View File

@ -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);

View File

@ -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)

View File

@ -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"