From b3b35e98b67d51d6e21dd06e5342c3c46074fa4f Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Thu, 17 Feb 2000 19:48:58 +0000 Subject: [PATCH] *** empty log message *** --- src/interfaces/ecpg/TODO | 5 +- src/interfaces/ecpg/lib/README.dynSQL | 20 + src/interfaces/ecpg/lib/dynamic.c | 17 +- src/interfaces/ecpg/preproc/Makefile | 3 +- src/interfaces/ecpg/preproc/descriptor.c | 400 ++++++++++++++++ src/interfaces/ecpg/preproc/ecpg.c | 4 + src/interfaces/ecpg/preproc/extern.h | 26 +- src/interfaces/ecpg/preproc/preproc.y | 761 ++----------------------------- src/interfaces/ecpg/preproc/type.c | 1 + src/interfaces/ecpg/preproc/variable.c | 358 +++++++++++++++ src/interfaces/ecpg/test/Makefile | 2 +- src/interfaces/ecpg/test/dyntest.pgc | 4 +- src/interfaces/ecpg/test/test4.pgc | 7 +- 13 files changed, 855 insertions(+), 753 deletions(-) create mode 100644 src/interfaces/ecpg/lib/README.dynSQL create mode 100644 src/interfaces/ecpg/preproc/descriptor.c create mode 100644 src/interfaces/ecpg/preproc/variable.c diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO index 747a87ac3f..8be5f3f5fb 100644 --- a/src/interfaces/ecpg/TODO +++ b/src/interfaces/ecpg/TODO @@ -23,8 +23,9 @@ indicator-error? Add a semantic check level, e.g. check if a table really exists. +It would be nice if there was a alternative library using SPI functions +instead of libpq so we can write backend functions using ecpg. + Missing statements: - exec sql ifdef - - exec sql allocate - - exec sql deallocate - SQLSTATE diff --git a/src/interfaces/ecpg/lib/README.dynSQL b/src/interfaces/ecpg/lib/README.dynSQL new file mode 100644 index 0000000000..fedcf80402 --- /dev/null +++ b/src/interfaces/ecpg/lib/README.dynSQL @@ -0,0 +1,20 @@ +descriptor statements have the following shortcomings + +- up to now the only reasonable statement is + FETCH ... INTO SQL DESCRIPTOR + no input variables allowed! + + Reason: to fully support dynamic SQL the frontend/backend communication + should change to recognize input parameters. + Since this is not likely to happen in the near future and you + can cover the same functionality with the existing infrastructure + I'll leave the work to someone else. + +- string buffer overflow does not always generate warnings + (beware: terminating 0 may be missing because strncpy is used) + :var=data sets sqlwarn accordingly (but not indicator) + +- char variables pointing to NULL are not allocated on demand + +- string truncation does not show up in indicator + diff --git a/src/interfaces/ecpg/lib/dynamic.c b/src/interfaces/ecpg/lib/dynamic.c index ec8e927d64..752c02cfc0 100644 --- a/src/interfaces/ecpg/lib/dynamic.c +++ b/src/interfaces/ecpg/lib/dynamic.c @@ -2,26 +2,11 @@ * * Copyright (c) 2000, Christof Petig * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.1 2000/02/16 16:18:12 meskes Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/dynamic.c,v 1.2 2000/02/17 19:48:41 meskes Exp $ */ /* I borrowed the include files from ecpglib.c, maybe we don't need all of them */ -#if 0 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#endif #include static struct descriptor diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 129ec03d63..72240e2efc 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -10,8 +10,7 @@ CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ -DINCLUDE_PATH=\"$(HEADERDIR)\" -g OBJ=preproc.o pgc.o type.o ecpg.o ecpg_keywords.o \ - keywords.o c_keywords.o ../lib/typename.o -#../../../backend/parser/scansup.o + keywords.o c_keywords.o ../lib/typename.o descriptor.o variable.o all:: ecpg diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c new file mode 100644 index 0000000000..c2b09fa076 --- /dev/null +++ b/src/interfaces/ecpg/preproc/descriptor.c @@ -0,0 +1,400 @@ +/* + * functions needed for descriptor handling + */ + +#include "postgres.h" +#include "extern.h" + +/* + * assignment handling function (descriptor) + */ + +struct assignment *assignments; + +void push_assignment(char *var,char *value) +{ + struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment)); + + new->next=assignments; + new->variable=mm_alloc(strlen(var)+1); + strcpy(new->variable,var); + new->value=mm_alloc(strlen(value)+1); + strcpy(new->value,value); + assignments=new; +} + +static void +drop_assignments(void) +{ while (assignments) + { struct assignment *old_head=assignments; + + assignments=old_head->next; + free(old_head->variable); + free(old_head->value); + free(old_head); + } +} + +/* XXX: these should be more accurate (consider ECPGdump_a_* ) */ +static void ECPGnumeric_lvalue(FILE *f,char *name) +{ const struct variable *v=find_variable(name); + + switch(v->type->typ) + { + case ECPGt_short: + case ECPGt_int: + case ECPGt_long: + case ECPGt_unsigned_short: + case ECPGt_unsigned_int: + case ECPGt_unsigned_long: + fputs(name,yyout); + break; + default: + snprintf(errortext,sizeof errortext,"variable %s: numeric type needed" + ,name); + mmerror(ET_ERROR,errortext); + break; + } +} + +static void ECPGstring_buffer(FILE *f,char *name) +{ + const struct variable *v=find_variable(name); + + switch(v->type->typ) + { + case ECPGt_varchar: + fprintf(yyout,"%s.arr",name); + break; + + case ECPGt_char: + case ECPGt_unsigned_char: + fputs(name,yyout); + break; + + default: + snprintf(errortext,sizeof errortext,"variable %s: character type needed" + ,name); + mmerror(ET_ERROR,errortext); + break; + } +} + +static void ECPGstring_length(FILE *f,char *name) +{ + const struct variable *v=find_variable(name); + + switch(v->type->typ) + { case ECPGt_varchar: + case ECPGt_char: + case ECPGt_unsigned_char: + if (!v->type->size) + { snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment", + v->name); + mmerror(ET_ERROR,errortext); + } + fprintf(yyout,"%ld",v->type->size); + break; + default: + snprintf(errortext,sizeof errortext,"variable %s: character type needed" + ,name); + mmerror(ET_ERROR,errortext); + break; + } +} + +static void ECPGdata_assignment(char *variable,char *index_plus_1) +{ + const struct variable *v=find_variable(variable); + + fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1); + switch(v->type->typ) + { + case ECPGt_short: + case ECPGt_int: /* use the same conversion as ecpglib does */ + case ECPGt_long: + fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" + ,variable,index_plus_1); + break; + case ECPGt_unsigned_short: + case ECPGt_unsigned_int: + case ECPGt_unsigned_long: + fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" + ,variable,index_plus_1); + break; + case ECPGt_float: + case ECPGt_double: + fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n" + ,variable,index_plus_1); + break; + + case ECPGt_bool: + fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n" + ,variable,index_plus_1); + break; + + case ECPGt_varchar: + fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" + ,variable,index_plus_1,v->type->size); + fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n" + ,variable,index_plus_1); + fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" + ,variable,v->type->size,variable,v->type->size); + fputs("\t\t\t}\n",yyout); + break; + + case ECPGt_char: + case ECPGt_unsigned_char: + if (!v->type->size) + { + snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment", + v->name); + mmerror(ET_ERROR,errortext); + } + fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" + ,variable,index_plus_1,v->type->size); + fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n" + "\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" + ,index_plus_1,v->type->size,variable,v->type->size-1); + fputs("\t\t\t}\n",yyout); + break; + + default: + snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment" + ,v->type->typ); + mmerror(ET_ERROR,errortext); + break; + } +} + +void +output_get_descr_header(char *desc_name) +{ + struct assignment *results; + + fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" ,yylineno,desc_name); + fputs("\tif (ECPGresult)\n\t{",yyout); + for (results=assignments;results!=NULL;results=results->next) + { + if (!strcasecmp(results->value,"count")) + { + fputs("\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fputs("=PQnfields(ECPGresult);\n",yyout); + } + else + { snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); + mmerror(ET_WARN,errortext); + } + } + drop_assignments(); + fputs("}",yyout); + + whenever_action(2|1); +} + +void +output_get_descr(char *desc_name) +{ + struct assignment *results; + int flags=0; + const int DATA_SEEN=1; + const int INDICATOR_SEEN=2; + + fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" + ,yylineno,desc_name); + fputs("\tif (ECPGresult)\n\t{",yyout); + fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno); + fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n" + "\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n" + ,descriptor_index,descriptor_index,yylineno); + fputs("\t\telse\n\t\t{\n",yyout); + for (results=assignments;results!=NULL;results=results->next) + { + if (!strcasecmp(results->value,"type")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); + } + else if (!strcasecmp(results->value,"datetime_interval_code")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); + } + else if (!strcasecmp(results->value,"length")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index); + } + else if (!strcasecmp(results->value,"octet_length")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index); + } + else if (!strcasecmp(results->value,"returned_length") + || !strcasecmp(results->value,"returned_octet_length")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index); + } + else if (!strcasecmp(results->value,"precision")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index); + } + else if (!strcasecmp(results->value,"scale")) + { + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index); + } + else if (!strcasecmp(results->value,"nullable")) + { + mmerror(ET_WARN,"nullable is always 1"); + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=1;\n"); + } + else if (!strcasecmp(results->value,"key_member")) + { + mmerror(ET_WARN,"key_member is always 0"); + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=0;\n"); + } + else if (!strcasecmp(results->value,"name")) + { + fputs("\t\t\tstrncpy(",yyout); + ECPGstring_buffer(yyout,results->variable); + fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index); + ECPGstring_length(yyout,results->variable); + fputs(");\n",yyout); + } + else if (!strcasecmp(results->value,"indicator")) + { + flags|=INDICATOR_SEEN; + fputs("\t\t\t",yyout); + ECPGnumeric_lvalue(yyout,results->variable); + fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index); + } + else if (!strcasecmp(results->value,"data")) + { + flags|=DATA_SEEN; + ECPGdata_assignment(results->variable,descriptor_index); + } + else + { + snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); + mmerror(ET_WARN,errortext); + } + } + if (flags==DATA_SEEN) /* no indicator */ + { + fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n" + "\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n" + ,descriptor_index,yylineno); + } + drop_assignments(); + fputs("\t\t}\n\t}\n",yyout); + + whenever_action(2|1); +} + +/* + * descriptor name lookup + */ + +static struct descriptor *descriptors; + +void add_descriptor(char *name,char *connection) +{ + struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor)); + + new->next=descriptors; + new->name=mm_alloc(strlen(name)+1); + strcpy(new->name,name); + if (connection) + { new->connection=mm_alloc(strlen(connection)+1); + strcpy(new->connection,connection); + } + else new->connection=connection; + descriptors=new; +} + +void drop_descriptor(char *name,char *connection) +{ + struct descriptor *i; + struct descriptor **lastptr=&descriptors; + + for (i=descriptors;i;lastptr=&i->next,i=i->next) + { + if (!strcmp(name,i->name)) + { + if ((!connection && !i->connection) + || (connection && i->connection + && !strcmp(connection,i->connection))) + { + *lastptr=i->next; + if (i->connection) free(i->connection); + free(i->name); + free(i); + return; + } + } + } + snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); + mmerror(ET_WARN,errortext); +} + +struct descriptor *lookup_descriptor(char *name,char *connection) +{ + struct descriptor *i; + + for (i=descriptors;i;i=i->next) + { + if (!strcmp(name,i->name)) + { + if ((!connection && !i->connection) + || (connection && i->connection + && !strcmp(connection,i->connection))) + { + return i; + } + } + } + snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); + mmerror(ET_WARN,errortext); + return NULL; +} + +void +output_statement_desc(char * stmt, int mode) +{ + int i, j=strlen(stmt); + + fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"", + connection ? connection : "NULL", descriptor_name); + + /* do this char by char as we have to filter '\"' */ + for (i = 0;i < j; i++) { + if (stmt[i] != '\"') + fputc(stmt[i], yyout); + else + fputs("\\\"", yyout); + } + + fputs("\");", yyout); + + mode |= 2; + whenever_action(mode); + free(stmt); + if (connection != NULL) + free(connection); + free(descriptor_name); +} diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index 2da1761c6d..1c14fbbc0c 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -241,6 +241,10 @@ main(int argc, char *const argv[]) /* and structure member lists */ memset(struct_member_list, 0, sizeof(struct_member_list)); + + /* finally the actual connection */ + connection = NULL; + /* initialize lex */ lex_init(); diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index 2a1da562a7..cbee29e0a5 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -18,6 +18,9 @@ extern int yylineno, yyleng; extern FILE *yyin, *yyout; +extern char *descriptor_index; +extern char *descriptor_name; +extern char *connection; extern struct _include_path *include_paths; extern struct cursor *cur; @@ -42,9 +45,26 @@ extern void yyerror(char *); extern void *mm_alloc(size_t), *mm_realloc(void *, size_t); extern char *mm_strdup(const char *); extern void mmerror(enum errortype, char * ); -ScanKeyword *ScanECPGKeywordLookup(char *); -ScanKeyword *ScanCKeywordLookup(char *); - +extern ScanKeyword *ScanECPGKeywordLookup(char *); +extern ScanKeyword *ScanCKeywordLookup(char *); +extern void output_get_descr_header(char *); +extern void output_get_descr(char *); +extern void push_assignment(char *, char *); +extern struct variable * find_variable(char *); +extern void whenever_action(int); +extern void add_descriptor(char *,char *); +extern void drop_descriptor(char *,char *); +extern struct descriptor *lookup_descriptor(char *,char *); +extern void output_statement_desc(char *, int); +extern void add_variable(struct arguments ** , struct variable * , struct variable *); +extern void dump_variables(struct arguments *, int); +extern struct typedefs *get_typedef(char *); +extern void adjust_array(enum ECPGttype, int *, int *, int, int, bool); +extern void reset_variables(void); +extern void check_indicator(struct ECPGtype *); +extern void remove_variables(int); +extern struct variable *new_variable(const char *, struct ECPGtype *); + /* return codes */ #define OK 0 diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 0c492febf0..41354d8712 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -22,9 +22,10 @@ */ int struct_level = 0; char errortext[128]; -static char *connection = NULL; -static char *descriptor_name = NULL; -static char *descriptor_index= NULL; +char *descriptor_index= NULL; +char *connection = NULL; +char *descriptor_name = NULL; + static int QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0; static int FoundSort = 0; static int initializer = 0; @@ -40,11 +41,6 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}}; -/* variable lookup */ - -static struct variable * find_variable(char * name); -static void whenever_action(int mode); - /* * Handle parsing errors and warnings */ @@ -88,275 +84,6 @@ output_simple_statement(char *cmd) } /* - * assignment handling function (descriptor) - */ - -static struct assignment *assignments; - -static void push_assignment(char *var,char *value) -{ - struct assignment *new=(struct assignment *)mm_alloc(sizeof(struct assignment)); - - new->next=assignments; - new->variable=mm_alloc(strlen(var)+1); - strcpy(new->variable,var); - new->value=mm_alloc(strlen(value)+1); - strcpy(new->value,value); - assignments=new; -} - -static void drop_assignments(void) -{ while (assignments) - { struct assignment *old_head=assignments; - assignments=old_head->next; - free(old_head->variable); - free(old_head->value); - free(old_head); - } -} - -/* XXX: these should be more accurate (consider ECPGdump_a_* ) */ -static void ECPGnumeric_lvalue(FILE *f,char *name) -{ const struct variable *v=find_variable(name); - switch(v->type->typ) - { case ECPGt_short: - case ECPGt_int: - case ECPGt_long: - case ECPGt_unsigned_short: - case ECPGt_unsigned_int: - case ECPGt_unsigned_long: - fputs(name,yyout); - break; - default: - snprintf(errortext,sizeof errortext,"variable %s: numeric type needed" - ,name); - mmerror(ET_ERROR,errortext); - break; - } -} - -static void ECPGstring_buffer(FILE *f,char *name) -{ const struct variable *v=find_variable(name); - switch(v->type->typ) - { case ECPGt_varchar: - fprintf(yyout,"%s.arr",name); - break; - - case ECPGt_char: - case ECPGt_unsigned_char: - fputs(name,yyout); - break; - - default: - snprintf(errortext,sizeof errortext,"variable %s: character type needed" - ,name); - mmerror(ET_ERROR,errortext); - break; - } -} - -static void ECPGstring_length(FILE *f,char *name) -{ const struct variable *v=find_variable(name); - switch(v->type->typ) - { case ECPGt_varchar: - case ECPGt_char: - case ECPGt_unsigned_char: - if (!v->type->size) - { snprintf(errortext,sizeof errortext,"zero length char variable %s for assignment", - v->name); - mmerror(ET_ERROR,errortext); - } - fprintf(yyout,"%ld",v->type->size); - break; - default: - snprintf(errortext,sizeof errortext,"variable %s: character type needed" - ,name); - mmerror(ET_ERROR,errortext); - break; - } -} - -static void ECPGdata_assignment(char *variable,char *index_plus_1) -{ const struct variable *v=find_variable(variable); - fprintf(yyout,"\t\t\tif (!PQgetisnull(ECPGresult,0,(%s)-1))\n",index_plus_1); - switch(v->type->typ) - { case ECPGt_short: - case ECPGt_int: /* use the same conversion as ecpglib does */ - case ECPGt_long: - fprintf(yyout,"\t\t\t\t%s=strtol(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" - ,variable,index_plus_1); - break; - case ECPGt_unsigned_short: - case ECPGt_unsigned_int: - case ECPGt_unsigned_long: - fprintf(yyout,"\t\t\t\t%s=strtoul(PQgetvalue(ECPGresult,0,(%s)-1),NULL,10);\n" - ,variable,index_plus_1); - break; - case ECPGt_float: - case ECPGt_double: - fprintf(yyout,"\t\t\t\t%s=strtod(PQgetvalue(ECPGresult,0,(%s)-1),NULL);\n" - ,variable,index_plus_1); - break; - - case ECPGt_bool: - fprintf(yyout,"\t\t\t\t%s=PQgetvalue(ECPGresult,0,(%s)-1)[0]=='t';\n" - ,variable,index_plus_1); - break; - - case ECPGt_varchar: - fprintf(yyout,"\t\t\t{\tstrncpy(%s.arr,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" - ,variable,index_plus_1,v->type->size); - fprintf(yyout,"\t\t\t\t%s.len=strlen(PQgetvalue(ECPGresult,0,(%s)-1)\n" - ,variable,index_plus_1); - fprintf(yyout,"\t\t\t\tif (%s.len>%ld) { %s.len=%ld; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" - ,variable,v->type->size,variable,v->type->size); - fputs("\t\t\t}\n",yyout); - break; - - case ECPGt_char: - case ECPGt_unsigned_char: - if (!v->type->size) - { snprintf(errortext,sizeof errortext,"zero length char variable %s for DATA assignment", - v->name); - mmerror(ET_ERROR,errortext); - } - fprintf(yyout,"\t\t\t{\tstrncpy(%s,PQgetvalue(ECPGresult,0,(%s)-1),%ld);\n" - ,variable,index_plus_1,v->type->size); - fprintf(yyout,"\t\t\t\tif (strlen(PQgetvalue(ECPGresult,0,(%s)-1))>=%ld)\n" - "\t\t\t\t{ %s[%ld]=0; sqlca.sqlwarn[0]=sqlca.sqlwarn[1]='W'; }\n" - ,index_plus_1,v->type->size,variable,v->type->size-1); - fputs("\t\t\t}\n",yyout); - break; - - default: - snprintf(errortext,sizeof errortext,"unknown variable type %d for DATA assignment" - ,v->type->typ); - mmerror(ET_ERROR,errortext); - break; - } -} - -static void -output_get_descr_header(char *desc_name) -{ struct assignment *results; - fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" - ,yylineno,desc_name); - fputs("\tif (ECPGresult)\n\t{",yyout); - for (results=assignments;results!=NULL;results=results->next) - { if (!strcasecmp(results->value,"count")) - { fputs("\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fputs("=PQnfields(ECPGresult);\n",yyout); - } - else - { snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); - mmerror(ET_WARN,errortext); - } - } - drop_assignments(); - fputs("}",yyout); - - whenever_action(2|1); -} - -static void -output_get_descr(char *desc_name) -{ struct assignment *results; - int flags=0; - const int DATA_SEEN=1; - const int INDICATOR_SEEN=2; - - fprintf(yyout,"{\tPGresult *ECPGresult=ECPGresultByDescriptor(%d, \"%s\");\n" - ,yylineno,desc_name); - fputs("\tif (ECPGresult)\n\t{",yyout); - fprintf(yyout,"\tif (PQntuples(ECPGresult)<1) ECPGraise(%d,ECPG_NOT_FOUND);\n",yylineno); - fprintf(yyout,"\t\telse if (%s<1 || %s>PQnfields(ECPGresult))\n" - "\t\t\tECPGraise(%d,ECPG_INVALID_DESCRIPTOR_INDEX);\n" - ,descriptor_index,descriptor_index,yylineno); - fputs("\t\telse\n\t\t{\n",yyout); - for (results=assignments;results!=NULL;results=results->next) - { if (!strcasecmp(results->value,"type")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=ECPGDynamicType(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); - } - else if (!strcasecmp(results->value,"datetime_interval_code")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=ECPGDynamicType_DDT(PQftype(ECPGresult,(%s)-1));\n",descriptor_index); - } - else if (!strcasecmp(results->value,"length")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)-VARHDRSZ;\n",descriptor_index); - } - else if (!strcasecmp(results->value,"octet_length")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=PQfsize(ECPGresult,(%s)-1);\n",descriptor_index); - } - else if (!strcasecmp(results->value,"returned_length") - || !strcasecmp(results->value,"returned_octet_length")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=PQgetlength(ECPGresult,0,(%s)-1);\n",descriptor_index); - } - else if (!strcasecmp(results->value,"precision")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=PQfmod(ECPGresult,(%s)-1)>>16;\n",descriptor_index); - } - else if (!strcasecmp(results->value,"scale")) - { fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=(PQfmod(ECPGresult,(%s)-1)-VARHDRSZ)&0xffff;\n",descriptor_index); - } - else if (!strcasecmp(results->value,"nullable")) - { mmerror(ET_WARN,"nullable is always 1"); - fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=1;\n"); - } - else if (!strcasecmp(results->value,"key_member")) - { mmerror(ET_WARN,"key_member is always 0"); - fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=0;\n"); - } - else if (!strcasecmp(results->value,"name")) - { fputs("\t\t\tstrncpy(",yyout); - ECPGstring_buffer(yyout,results->variable); - fprintf(yyout,",PQfname(ECPGresult,(%s)-1),",descriptor_index); - ECPGstring_length(yyout,results->variable); - fputs(");\n",yyout); - } - else if (!strcasecmp(results->value,"indicator")) - { flags|=INDICATOR_SEEN; - fputs("\t\t\t",yyout); - ECPGnumeric_lvalue(yyout,results->variable); - fprintf(yyout,"=-PQgetisnull(ECPGresult,0,(%s)-1);\n",descriptor_index); - } - else if (!strcasecmp(results->value,"data")) - { flags|=DATA_SEEN; - ECPGdata_assignment(results->variable,descriptor_index); - } - else - { snprintf(errortext,sizeof errortext,"unknown descriptor header item '%s'",results->value); - mmerror(ET_WARN,errortext); - } - } - if (flags==DATA_SEEN) /* no indicator */ - { fprintf(yyout,"\t\t\tif (PQgetisnull(ECPGresult,0,(%s)-1))\n" - "\t\t\t\tECPGraise(%d,ECPG_MISSING_INDICATOR);\n" - ,descriptor_index,yylineno); - } - drop_assignments(); - fputs("\t\t}\n\t}\n",yyout); - - whenever_action(2|1); -} - -/* * store the whenever action here */ struct when when_error, when_nf, when_warn; @@ -381,7 +108,7 @@ print_action(struct when *w) } } -static void +void whenever_action(int mode) { if ((mode&1) == 1 && when_nf.code != W_NOTHING) @@ -416,322 +143,6 @@ whenever_action(int mode) */ int braces_open; -static struct variable * allvariables = NULL; - -static struct variable * -new_variable(const char * name, struct ECPGtype * type) -{ - struct variable * p = (struct variable*) mm_alloc(sizeof(struct variable)); - - p->name = mm_strdup(name); - p->type = type; - p->brace_level = braces_open; - - p->next = allvariables; - allvariables = p; - - return(p); -} - -static struct variable * -find_struct_member(char *name, char *str, struct ECPGstruct_member *members) -{ - char *next = strchr(++str, '.'), c = '\0'; - - if (next != NULL) - { - c = *next; - *next = '\0'; - } - - for (; members; members = members->next) - { - if (strcmp(members->name, str) == 0) - { - if (c == '\0') - { - /* found the end */ - switch (members->typ->typ) - { - case ECPGt_array: - return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size))); - case ECPGt_struct: - case ECPGt_union: - return(new_variable(name, ECPGmake_struct_type(members->typ->u.members, members->typ->typ))); - default: - return(new_variable(name, ECPGmake_simple_type(members->typ->typ, members->typ->size))); - } - } - else - { - *next = c; - if (c == '-') - { - next++; - return(find_struct_member(name, next, members->typ->u.element->u.members)); - } - else return(find_struct_member(name, next, members->typ->u.members)); - } - } - } - - return(NULL); -} - -static struct variable * -find_struct(char * name, char *next) -{ - struct variable * p; - char c = *next; - - /* first get the mother structure entry */ - *next = '\0'; - p = find_variable(name); - - if (c == '-') - { - if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) - { - sprintf(errortext, "variable %s is not a pointer", name); - mmerror(ET_FATAL, errortext); - } - - if (p->type->u.element->typ != ECPGt_struct && p->type->u.element->typ != ECPGt_union) - { - sprintf(errortext, "variable %s is not a pointer to a structure or a union", name); - mmerror(ET_FATAL, errortext); - } - - /* restore the name, we will need it later on */ - *next = c; - next++; - - return find_struct_member(name, next, p->type->u.element->u.members); - } - else - { - if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) - { - sprintf(errortext, "variable %s is neither a structure nor a union", name); - mmerror(ET_FATAL, errortext); - } - - /* restore the name, we will need it later on */ - *next = c; - - return find_struct_member(name, next, p->type->u.members); - } -} - -static struct variable * -find_simple(char * name) -{ - struct variable * p; - - for (p = allvariables; p; p = p->next) - { - if (strcmp(p->name, name) == 0) - return p; - } - - return(NULL); -} - -/* Note that this function will end the program in case of an unknown */ -/* variable */ -static struct variable * -find_variable(char * name) -{ - char * next; - struct variable * p; - - if ((next = strchr(name, '.')) != NULL) - p = find_struct(name, next); - else if ((next = strstr(name, "->")) != NULL) - p = find_struct(name, next); - else - p = find_simple(name); - - if (p == NULL) - { - sprintf(errortext, "The variable %s is not declared", name); - mmerror(ET_FATAL, errortext); - } - - return(p); -} - -static void -remove_variables(int brace_level) -{ - struct variable * p, *prev; - - for (p = prev = allvariables; p; p = p ? p->next : NULL) - { - if (p->brace_level >= brace_level) - { - /* remove it */ - if (p == allvariables) - prev = allvariables = p->next; - else - prev->next = p->next; - - ECPGfree_type(p->type); - free(p->name); - free(p); - p = prev; - } - else - prev = p; - } -} - - -/* - * Here are the variables that need to be handled on every request. - * These are of two kinds: input and output. - * I will make two lists for them. - */ - -struct arguments * argsinsert = NULL; -struct arguments * argsresult = NULL; - -static void -reset_variables(void) -{ - argsinsert = NULL; - argsresult = NULL; -} - - -/* Add a variable to a request. */ -static void -add_variable(struct arguments ** list, struct variable * var, struct variable * ind) -{ - struct arguments * p = (struct arguments *)mm_alloc(sizeof(struct arguments)); - p->variable = var; - p->indicator = ind; - p->next = *list; - *list = p; -} - - -/* Dump out a list of all the variable on this list. - This is a recursive function that works from the end of the list and - deletes the list as we go on. - */ -static void -dump_variables(struct arguments * list, int mode) -{ - if (list == NULL) - { - return; - } - - /* The list is build up from the beginning so lets first dump the - end of the list: - */ - - dump_variables(list->next, mode); - - /* Then the current element and its indicator */ - ECPGdump_a_type(yyout, list->variable->name, list->variable->type, - (list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->name : NULL, - (list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL); - - /* Then release the list element. */ - if (mode != 0) - free(list); -} - -static void -check_indicator(struct ECPGtype *var) -{ - /* make sure this is a valid indicator variable */ - switch (var->typ) - { - struct ECPGstruct_member *p; - - case ECPGt_short: - case ECPGt_int: - case ECPGt_long: - case ECPGt_unsigned_short: - case ECPGt_unsigned_int: - case ECPGt_unsigned_long: - break; - - case ECPGt_struct: - case ECPGt_union: - for (p = var->u.members; p; p = p->next) - check_indicator(p->typ); - break; - - case ECPGt_array: - check_indicator(var->u.element); - break; - default: - mmerror(ET_ERROR, "indicator variable must be integer type"); - break; - } -} - -/* - * descriptor name lookup - */ - -static struct descriptor *descriptors; - -static void add_descriptor(char *name,char *connection) -{ - struct descriptor *new=(struct descriptor *)mm_alloc(sizeof(struct descriptor)); - - new->next=descriptors; - new->name=mm_alloc(strlen(name)+1); - strcpy(new->name,name); - if (connection) - { new->connection=mm_alloc(strlen(connection)+1); - strcpy(new->connection,connection); - } - else new->connection=connection; - descriptors=new; -} - -static void drop_descriptor(char *name,char *connection) -{ struct descriptor *i; - struct descriptor **lastptr=&descriptors; - for (i=descriptors;i;lastptr=&i->next,i=i->next) - { if (!strcmp(name,i->name)) - { if ((!connection && !i->connection) - || (connection && i->connection - && !strcmp(connection,i->connection))) - { *lastptr=i->next; - if (i->connection) free(i->connection); - free(i->name); - free(i); - return; - } - } - } - snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); - mmerror(ET_WARN,errortext); -} - -static struct descriptor *lookup_descriptor(char *name,char *connection) -{ struct descriptor *i; - for (i=descriptors;i;i=i->next) - { if (!strcmp(name,i->name)) - { if ((!connection && !i->connection) - || (connection && i->connection - && !strcmp(connection,i->connection))) - { return i; - } - } - } - snprintf(errortext,sizeof errortext,"unknown descriptor %s",name); - mmerror(ET_WARN,errortext); - return NULL; -} - /* * string concatenation */ @@ -857,128 +268,6 @@ output_statement(char * stmt, int mode) free(connection); } -static void -output_statement_desc(char * stmt, int mode) -{ - int i, j=strlen(stmt); - - fprintf(yyout, "{ ECPGdo_descriptor(__LINE__, %s, \"%s\", \"", - connection ? connection : "NULL", descriptor_name); - - /* do this char by char as we have to filter '\"' */ - for (i = 0;i < j; i++) { - if (stmt[i] != '\"') - fputc(stmt[i], yyout); - else - fputs("\\\"", yyout); - } - - fputs("\");", yyout); - - mode |= 2; - whenever_action(mode); - free(stmt); - if (connection != NULL) - free(connection); - free(descriptor_name); -} - -static struct typedefs * -get_typedef(char *name) -{ - struct typedefs *this; - - for (this = types; this && strcmp(this->name, name); this = this->next); - if (!this) - { - sprintf(errortext, "invalid datatype '%s'", name); - mmerror(ET_FATAL, errortext); - } - - return(this); -} - -static void -adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer) -{ - if (type_index >= 0) - { - if (*length >= 0) - mmerror(ET_FATAL, "No multi-dimensional array support"); - - *length = type_index; - } - - if (type_dimension >= 0) - { - if (*dimension >= 0 && *length >= 0) - mmerror(ET_FATAL, "No multi-dimensional array support"); - - if (*dimension >= 0) - *length = *dimension; - - *dimension = type_dimension; - } - - if (*length >= 0 && *dimension >= 0 && pointer) - mmerror(ET_FATAL, "No multi-dimensional array support"); - - switch (type_enum) - { - case ECPGt_struct: - case ECPGt_union: - /* pointer has to get dimension 0 */ - if (pointer) - { - *length = *dimension; - *dimension = 0; - } - - if (*length >= 0) - mmerror(ET_FATAL, "No multi-dimensional array support for structures"); - - break; - case ECPGt_varchar: - /* pointer has to get dimension 0 */ - if (pointer) - *dimension = 0; - - /* one index is the string length */ - if (*length < 0) - { - *length = *dimension; - *dimension = -1; - } - - break; - case ECPGt_char: - case ECPGt_unsigned_char: - /* pointer has to get length 0 */ - if (pointer) - *length=0; - - /* one index is the string length */ - if (*length < 0) - { - *length = (*dimension < 0) ? 1 : *dimension; - *dimension = -1; - } - - break; - default: - /* a pointer has dimension = 0 */ - if (pointer) { - *length = *dimension; - *dimension = 0; - } - - if (*length >= 0) - mmerror(ET_FATAL, "No multi-dimensional array support for simple data types"); - - break; - } -} - %} %union { @@ -1244,7 +533,7 @@ stmt: AlterTableStmt { output_statement($1, 0); } | ExtendStmt { output_statement($1, 0); } | ExplainStmt { output_statement($1, 0); } | FetchStmt { output_statement($1, 1); } - | FetchDescriptorStmt { output_statement_desc($1, 1); } + | FetchDescriptorStmt { output_statement_desc($1, 1); } | GrantStmt { output_statement($1, 0); } | IndexStmt { output_statement($1, 0); } | ListenStmt { output_statement($1, 0); } @@ -4645,6 +3934,7 @@ ColId: ident { $$ = $1; } | INITIALLY { $$ = make_str("initially"); } | INSENSITIVE { $$ = make_str("insensitive"); } | INSTEAD { $$ = make_str("instead"); } + | INTERVAL { $$ = make_str("interval"); } | ISNULL { $$ = make_str("isnull"); } | ISOLATION { $$ = make_str("isolation"); } | KEY { $$ = make_str("key"); } @@ -5445,18 +4735,41 @@ ECPGGetDescItems: ECPGGetDescItem | ECPGGetDescItems ',' ECPGGetDescItem; ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR ident ECPGGetDescHeaderItems -{ $$ = $3; } + { $$ = $3; } ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR ident SQL_VALUE cvariable ECPGGetDescItems -{ $$ = $3; descriptor_index=$5; } + { $$ = $3; descriptor_index = $5; } | SQL_GET SQL_DESCRIPTOR ident SQL_VALUE Iconst ECPGGetDescItems -{ $$ = $3; descriptor_index=$5; } + { $$ = $3; descriptor_index = $5; } -/* - * fetch [ in | from ] into sql descriptor - */ +/***************************************************************************** + * + * QUERY: + * fetch [forward | backward] [ # | all ] [ in ] + * fetch [ forward | backward | absolute | relative ] + * [ # | all | next | prior ] [ [ in | from ] ] + * + * Have to seperate the descriptor version since we have to + * call a different output function + * + *****************************************************************************/ -FetchDescriptorStmt: FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident +FetchDescriptorStmt: FETCH direction fetch_how_many from_in name INTO SQL_SQL SQL_DESCRIPTOR ident + { + $$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5); + descriptor_name=$9; + } + | FETCH fetch_how_many from_in name INTO SQL_SQL SQL_DESCRIPTOR ident + { + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + descriptor_name=$8; + } + | FETCH direction from_in name INTO SQL_SQL SQL_DESCRIPTOR ident + { + $$ = cat_str(4, make_str("fetch"), $2, $3, $4); + descriptor_name=$8; + } + | FETCH from_in name INTO SQL_SQL SQL_DESCRIPTOR ident { $$ = cat_str(3, make_str("fetch"), $2, $3); descriptor_name=$7; diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 461eddc6e7..039939fe03 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -2,6 +2,7 @@ #include #include +#include "postgres.h" #include "extern.h" /* malloc + error check */ diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c new file mode 100644 index 0000000000..df458dcc07 --- /dev/null +++ b/src/interfaces/ecpg/preproc/variable.c @@ -0,0 +1,358 @@ +#include "postgres.h" + +#include "extern.h" + +struct variable * allvariables = NULL; + +struct variable * +new_variable(const char * name, struct ECPGtype * type) +{ + struct variable * p = (struct variable*) mm_alloc(sizeof(struct variable)); + + p->name = mm_strdup(name); + p->type = type; + p->brace_level = braces_open; + + p->next = allvariables; + allvariables = p; + + return(p); +} + +static struct variable * +find_struct_member(char *name, char *str, struct ECPGstruct_member *members) +{ + char *next = strchr(++str, '.'), c = '\0'; + + if (next != NULL) + { + c = *next; + *next = '\0'; + } + + for (; members; members = members->next) + { + if (strcmp(members->name, str) == 0) + { + if (c == '\0') + { + /* found the end */ + switch (members->typ->typ) + { + case ECPGt_array: + return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size))); + case ECPGt_struct: + case ECPGt_union: + return(new_variable(name, ECPGmake_struct_type(members->typ->u.members, members->typ->typ))); + default: + return(new_variable(name, ECPGmake_simple_type(members->typ->typ, members->typ->size))); + } + } + else + { + *next = c; + if (c == '-') + { + next++; + return(find_struct_member(name, next, members->typ->u.element->u.members)); + } + else return(find_struct_member(name, next, members->typ->u.members)); + } + } + } + + return(NULL); +} + +static struct variable * +find_struct(char * name, char *next) +{ + struct variable * p; + char c = *next; + + /* first get the mother structure entry */ + *next = '\0'; + p = find_variable(name); + + if (c == '-') + { + if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) + { + sprintf(errortext, "variable %s is not a pointer", name); + mmerror(ET_FATAL, errortext); + } + + if (p->type->u.element->typ != ECPGt_struct && p->type->u.element->typ != ECPGt_union) + { + sprintf(errortext, "variable %s is not a pointer to a structure or a union", name); + mmerror(ET_FATAL, errortext); + } + + /* restore the name, we will need it later on */ + *next = c; + next++; + + return find_struct_member(name, next, p->type->u.element->u.members); + } + else + { + if (p->type->typ != ECPGt_struct && p->type->typ != ECPGt_union) + { + sprintf(errortext, "variable %s is neither a structure nor a union", name); + mmerror(ET_FATAL, errortext); + } + + /* restore the name, we will need it later on */ + *next = c; + + return find_struct_member(name, next, p->type->u.members); + } +} + +static struct variable * +find_simple(char * name) +{ + struct variable * p; + + for (p = allvariables; p; p = p->next) + { + if (strcmp(p->name, name) == 0) + return p; + } + + return(NULL); +} + +/* Note that this function will end the program in case of an unknown */ +/* variable */ +struct variable * +find_variable(char * name) +{ + char * next; + struct variable * p; + + if ((next = strchr(name, '.')) != NULL) + p = find_struct(name, next); + else if ((next = strstr(name, "->")) != NULL) + p = find_struct(name, next); + else + p = find_simple(name); + + if (p == NULL) + { + sprintf(errortext, "The variable %s is not declared", name); + mmerror(ET_FATAL, errortext); + } + + return(p); +} + +void +remove_variables(int brace_level) +{ + struct variable * p, *prev; + + for (p = prev = allvariables; p; p = p ? p->next : NULL) + { + if (p->brace_level >= brace_level) + { + /* remove it */ + if (p == allvariables) + prev = allvariables = p->next; + else + prev->next = p->next; + + ECPGfree_type(p->type); + free(p->name); + free(p); + p = prev; + } + else + prev = p; + } +} + + +/* + * Here are the variables that need to be handled on every request. + * These are of two kinds: input and output. + * I will make two lists for them. + */ + +struct arguments * argsinsert = NULL; +struct arguments * argsresult = NULL; + +void +reset_variables(void) +{ + argsinsert = NULL; + argsresult = NULL; +} + + +/* Add a variable to a request. */ +void +add_variable(struct arguments ** list, struct variable * var, struct variable * ind) +{ + struct arguments * p = (struct arguments *)mm_alloc(sizeof(struct arguments)); + p->variable = var; + p->indicator = ind; + p->next = *list; + *list = p; +} + + +/* Dump out a list of all the variable on this list. + This is a recursive function that works from the end of the list and + deletes the list as we go on. + */ +void +dump_variables(struct arguments * list, int mode) +{ + if (list == NULL) + { + return; + } + + /* The list is build up from the beginning so lets first dump the + end of the list: + */ + + dump_variables(list->next, mode); + + /* Then the current element and its indicator */ + ECPGdump_a_type(yyout, list->variable->name, list->variable->type, + (list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->name : NULL, + (list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL); + + /* Then release the list element. */ + if (mode != 0) + free(list); +} + +void +check_indicator(struct ECPGtype *var) +{ + /* make sure this is a valid indicator variable */ + switch (var->typ) + { + struct ECPGstruct_member *p; + + case ECPGt_short: + case ECPGt_int: + case ECPGt_long: + case ECPGt_unsigned_short: + case ECPGt_unsigned_int: + case ECPGt_unsigned_long: + break; + + case ECPGt_struct: + case ECPGt_union: + for (p = var->u.members; p; p = p->next) + check_indicator(p->typ); + break; + + case ECPGt_array: + check_indicator(var->u.element); + break; + default: + mmerror(ET_ERROR, "indicator variable must be integer type"); + break; + } +} + +struct typedefs * +get_typedef(char *name) +{ + struct typedefs *this; + + for (this = types; this && strcmp(this->name, name); this = this->next); + if (!this) + { + sprintf(errortext, "invalid datatype '%s'", name); + mmerror(ET_FATAL, errortext); + } + + return(this); +} + +void +adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer) +{ + if (type_index >= 0) + { + if (*length >= 0) + mmerror(ET_FATAL, "No multi-dimensional array support"); + + *length = type_index; + } + + if (type_dimension >= 0) + { + if (*dimension >= 0 && *length >= 0) + mmerror(ET_FATAL, "No multi-dimensional array support"); + + if (*dimension >= 0) + *length = *dimension; + + *dimension = type_dimension; + } + + if (*length >= 0 && *dimension >= 0 && pointer) + mmerror(ET_FATAL, "No multi-dimensional array support"); + + switch (type_enum) + { + case ECPGt_struct: + case ECPGt_union: + /* pointer has to get dimension 0 */ + if (pointer) + { + *length = *dimension; + *dimension = 0; + } + + if (*length >= 0) + mmerror(ET_FATAL, "No multi-dimensional array support for structures"); + + break; + case ECPGt_varchar: + /* pointer has to get dimension 0 */ + if (pointer) + *dimension = 0; + + /* one index is the string length */ + if (*length < 0) + { + *length = *dimension; + *dimension = -1; + } + + break; + case ECPGt_char: + case ECPGt_unsigned_char: + /* pointer has to get length 0 */ + if (pointer) + *length=0; + + /* one index is the string length */ + if (*length < 0) + { + *length = (*dimension < 0) ? 1 : *dimension; + *dimension = -1; + } + + break; + default: + /* a pointer has dimension = 0 */ + if (pointer) { + *length = *dimension; + *dimension = 0; + } + + if (*length >= 0) + mmerror(ET_FATAL, "No multi-dimensional array support for simple data types"); + + break; + } +} diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile index 9b945793e2..50217b52ae 100644 --- a/src/interfaces/ecpg/test/Makefile +++ b/src/interfaces/ecpg/test/Makefile @@ -27,4 +27,4 @@ stp.so: stp.c clean: - -/bin/rm test1 test2 test3 test4 test5 perftest *.c log stp.o stp.so + -/bin/rm test1 test2 test3 test4 test5 perftest *.c log stp.o stp.so dyntest diff --git a/src/interfaces/ecpg/test/dyntest.pgc b/src/interfaces/ecpg/test/dyntest.pgc index 451d82ad90..6317ba5fe0 100644 --- a/src/interfaces/ecpg/test/dyntest.pgc +++ b/src/interfaces/ecpg/test/dyntest.pgc @@ -2,7 +2,7 @@ * * Copyright (c) 2000, Christof Petig * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.1 2000/02/16 16:18:29 meskes Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.2 2000/02/17 19:48:58 meskes Exp $ */ #include @@ -37,7 +37,7 @@ int main(int argc,char **argv) exec sql allocate descriptor MYDESC; - exec sql connect to test; + exec sql connect to mm; exec sql prepare MYQUERY from :QUERY; exec sql declare MYCURS cursor for MYQUERY; diff --git a/src/interfaces/ecpg/test/test4.pgc b/src/interfaces/ecpg/test/test4.pgc index d482221870..dbbf49d7f0 100644 --- a/src/interfaces/ecpg/test/test4.pgc +++ b/src/interfaces/ecpg/test/test4.pgc @@ -43,12 +43,13 @@ EXEC SQL END DECLARE SECTION; printf("Found f=%f\n", f); - EXEC SQL SELECT i - INTO :i + EXEC SQL SELECT a + INTO :a FROM test WHERE f = :f; - printf("Found i=%d\n", i); + for (i = 0; i < 10; i++) + printf("Found a[%d] = %d\n", i, a[i]); EXEC SQL DROP TABLE test; -- 2.11.0