提交 25ad1439 编写于 作者: M Marc G. Fournier

Major update of ecpg preprocessor

From: Michael Meskes <meskes@topsystem.de>
上级 30f737f6
......@@ -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
......
......@@ -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.
......@@ -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
......@@ -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
......
......@@ -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]);
......
......@@ -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);
......@@ -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; }
......
......@@ -13,6 +13,10 @@ static void yyerror(char *);
* Variables containing simple states.
*/
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 ';' {
/* 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);
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);
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);
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;
......
#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;
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;
......@@ -35,7 +57,7 @@ ECPGmake_simple_type(enum ECPGttype typ)
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;
......@@ -43,9 +65,9 @@ ECPGmake_varchar_type(enum ECPGttype typ, unsigned short siz)
}
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;
......@@ -54,9 +76,9 @@ ECPGmake_array_type(struct ECPGtype * typ, unsigned short siz)
}
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;
......@@ -78,25 +100,25 @@ ECPGmake_record_type(struct ECPGrecord_member * rm[])
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_simple(FILE * o, const char * name, enum ECPGttype typ,
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);
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);
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);
typ->u.element->size, typ->size, 0, prefix);
else if (typ->u.element->typ == ECPGt_array)
{
abort(); /* Array of array, */
......@@ -104,7 +126,7 @@ ECPGdump_a_type(FILE * o, const char * name, struct ECPGtype * typ)
else if (typ->u.element->typ == ECPGt_record)
{
/* Array of records. */
ECPGdump_a_record(o, name, typ->size, typ->u.element, 0);
ECPGdump_a_record(o, name, typ->size, typ->u.element, 0, prefix);
}
else
{
......@@ -113,7 +135,7 @@ ECPGdump_a_type(FILE * o, const char * name, struct ECPGtype * typ)
}
else if (typ->typ == ECPGt_record)
{
ECPGdump_a_record(o, name, 0, typ, 0);
ECPGdump_a_record(o, name, 0, typ, 0, prefix);
}
else
{
......@@ -125,68 +147,69 @@ ECPGdump_a_type(FILE * o, const char * name, struct ECPGtype * typ)
/* 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,
ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
short varcharsize,
unsigned short arrsiz,
const char * siz)
const char *siz,
const char *prefix)
{
switch (typ)
{
case ECPGt_char:
fprintf(o, "\n\tECPGt_char,&%s,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
"\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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,0,%d,%s, ", name, arrsiz,
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,%d,%d,sizeof(struct varchar_%s), ",
name,
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,%d,%d,%s, ",
name,
fprintf(o, "\n\tECPGt_varchar,&%s%s,%d,%d,%s, ",
prefix ? prefix : "", name,
varcharsize,
arrsiz, siz);
break;
......@@ -198,17 +221,15 @@ ECPGdump_a_simple(FILE * o, const char * name, enum ECPGttype typ,
/* 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;
struct ECPGrecord_member *p;
char obuf[BUFSIZ];
char buf[BUFSIZ];
const char * offset;
char pbuf[BUFSIZ];
const char *offset;
if (offsetarg == NULL)
{
......@@ -220,32 +241,37 @@ ECPGdump_a_record(FILE * o,
offset = offsetarg;
}
for (p = typ->u.members; *p; p++)
sprintf(pbuf, "%s%s.", prefix ? prefix : "", name);
prefix = pbuf;
for (p = typ->u.members; p; p=p->next)
{
if (IS_SIMPLE_TYPE((*p)->typ->typ))
#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,
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)
else if (p->typ->typ == ECPGt_array)
{
int i;
for (i = 0; i < (*p)->typ->size; i++)
for (i = 0; i < p->typ->size; i++)
{
if (IS_SIMPLE_TYPE((*p)->typ->u.element->typ))
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);
/* 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)
else if (p->typ->u.element->typ == ECPGt_array)
{
/* Array within an array. NOT implemented yet. */
/* Array within an array. NOT implemented. */
abort();
}
else if ((*p)->typ->u.element->typ == ECPGt_record)
else if (p->typ->u.element->typ == ECPGt_record)
{
/* Record within array within record. NOT implemented yet. */
abort();
......@@ -257,17 +283,19 @@ ECPGdump_a_record(FILE * o,
}
}
}
else if ((*p)->typ->typ == ECPGt_record)
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);
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);
}
......@@ -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 {
......
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);
......@@ -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)
......
......@@ -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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册