From 7500a961f169455b95a97b59bf8a3544ec851fd0 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" <scrappy@hub.org> Date: Fri, 24 Apr 1998 12:10:20 +0000 Subject: [PATCH] From: Michael Meskes <meskes@topsystem.de> + Thu Apr 23 09:27:16 CEST 1998 + + - Also allow call in whenever statement with the same functionality + as do. + + Thu Apr 23 12:29:28 CEST 1998 + + - Also rewrote variable declaration part. It is now possible to + declare more than one variable per line. + - Set version to 2.1.0 + + Fri Apr 24 13:50:15 CEST 1998 + + - Fixed some bugs. + - Set version to 2.1.1 --- src/interfaces/ecpg/ChangeLog | 16 + src/interfaces/ecpg/TODO | 7 +- src/interfaces/ecpg/lib/Makefile.in | 16 +- src/interfaces/ecpg/preproc/Makefile | 4 +- src/interfaces/ecpg/preproc/ecpg.c | 7 +- src/interfaces/ecpg/preproc/ecpg_keywords.c | 1 + src/interfaces/ecpg/preproc/extern.h | 15 +- src/interfaces/ecpg/preproc/pgc.l | 38 +- src/interfaces/ecpg/preproc/preproc.y | 469 ++++++++++---------- src/interfaces/ecpg/preproc/type.c | 14 +- src/interfaces/ecpg/preproc/type.h | 6 + src/interfaces/ecpg/test/perftest.pgc | 2 + src/interfaces/ecpg/test/test2.pgc | 4 +- 13 files changed, 341 insertions(+), 258 deletions(-) diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index e06e4ffa73..f316bc33c5 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -121,8 +121,24 @@ Mon Apr 20 16:13:25 CEST 1998 Mon Apr 20 16:39:23 CEST 1998 - Cursor is opened when the open command is issued, not at declare time. + - Set version to 2.0.0 Tue Apr 21 12:53:49 CEST 1998 - Set indicator to amount of data really written (truncation). +Thu Apr 23 09:27:16 CEST 1998 + + - Also allow call in whenever statement with the same functionality + as do. + +Thu Apr 23 12:29:28 CEST 1998 + + - Also rewrote variable declaration part. It is now possible to + declare more than one variable per line. + - Set version to 2.1.0 + +Fri Apr 24 13:50:15 CEST 1998 + + - Fixed some bugs. + - Set version to 2.1.1 diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO index c74c273274..f092d1b2bd 100644 --- a/src/interfaces/ecpg/TODO +++ b/src/interfaces/ecpg/TODO @@ -35,8 +35,6 @@ There is no exec sql prepare statement. The complete structure definition has to be listed inside the declare section for ecpg to be able to understand it. -Each variable has to be defined on a line on its own. - There is no way yet to fill a complete array with one call except arrays of [unsigned] char which are considered strings. @@ -54,4 +52,7 @@ exec sql disconnect {current|default|all|connectionname|connection_hostvar}; | CURRENT commit release|commit work release auch disconnect -It is not neccessary to check for sql not found after all commands. +It is not neccessary to check for "not found" after all commands. + +It would be nice to be able to specify parts of a structure like :foo.bar or +:foo->bar. diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in index 926b3b5469..037d7f8d32 100644 --- a/src/interfaces/ecpg/lib/Makefile.in +++ b/src/interfaces/ecpg/lib/Makefile.in @@ -21,7 +21,6 @@ ifeq ($(PORTNAME), linux) install-shlib-dep := install-shlib shlib := libecpg.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) LDFLAGS_SL = -shared -soname libecpg.so.$(SO_MAJOR_VERSION) - CFLAGS += $(CFLAGS_SL) endif endif ifeq ($(PORTNAME), bsd) @@ -47,12 +46,12 @@ endif all: libecpg.a $(shlib) -$(shlib): ecpglib.o typename.o - $(LD) $(LDFLAGS_SL) -o $@ ecpglib.o typename.o +$(shlib): ecpglib.sho typename.sho + $(LD) $(LDFLAGS_SL) -o $@ ecpglib.sho typename.sho ln -sf $@ libecpg.so clean: - rm -f *.o *.a core a.out *~ $(shlib) libecpg.so + rm -f *.o *.sho *.a core a.out *~ $(shlib) libecpg.so dep depend: @@ -70,6 +69,11 @@ uninstall:: libecpg.a : libecpg.a(ecpglib.o) libecpg.a(typename.o) ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h - $(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c ecpglib.c + $(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@ typename.o : typename.c ../include/ecpgtype.h - $(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c typename.c + $(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@ + +ecpglib.sho : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h + $(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@ +typename.sho : typename.c ../include/ecpgtype.h + $(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@ diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 73596c05fd..8fcb985265 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -2,8 +2,8 @@ SRCDIR= ../../.. include $(SRCDIR)/Makefile.global MAJOR_VERSION=2 -MINOR_VERSION=0 -PATCHLEVEL=0 +MINOR_VERSION=1 +PATCHLEVEL=1 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \ diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index e156468f2b..853088d4ac 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -27,7 +27,7 @@ static void usage(char *progname) { fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); - fprintf(stderr, "Usage: %s: [-v] [-d] [-I include path] [ -o output file name] file1 [file2] ...\n", progname); + fprintf(stderr, "Usage: %s: [-v] [-I include path] [ -o output file name] file1 [file2] ...\n", progname); } static void @@ -51,7 +51,7 @@ main(int argc, char *const argv[]) add_include_path("/usr/local/include"); add_include_path("."); - while ((c = getopt(argc, argv, "vdo:I:")) != EOF) + while ((c = getopt(argc, argv, "vo:I:")) != EOF) { switch (c) { @@ -62,9 +62,6 @@ main(int argc, char *const argv[]) else out_option = 1; break; - case 'd': - debugging = 1; - break; case 'I': add_include_path(optarg); break; diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c index 6fea8a46bb..8047ddad8d 100644 --- a/src/interfaces/ecpg/preproc/ecpg_keywords.c +++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c @@ -21,6 +21,7 @@ */ static ScanKeyword ScanKeywords[] = { /* name value */ + {"call", SQL_CALL}, {"connect", SQL_CONNECT}, {"continue", SQL_CONTINUE}, {"found", SQL_FOUND}, diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index 96c7bc0ed3..7b59e14cd5 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -2,8 +2,7 @@ /* variables */ -extern int debugging, - braces_open; +extern int braces_open; extern char *yytext; extern int yylineno, yyleng; @@ -23,6 +22,18 @@ struct cursor { char *name; extern struct cursor *cur; +/* This is a linked list of the variable names and types. */ +struct variable +{ + char * name; + struct ECPGtype * type; + int brace_level; + struct variable * next; +}; + +extern struct ECPGtype ecpg_no_indicator; +extern struct variable no_indicator; + /* functions */ extern void lex_init(void); diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 669da63a06..a2b6770bd8 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -70,6 +70,7 @@ struct _yy_buffer { YY_BUFFER_STATE buffer; %x xb %x xc %x xd +%x xdc %x xh %x xm %x xq @@ -261,7 +262,7 @@ sql [sS][qQ][lL] <xd>{xdstop} { BEGIN(SQL); yylval.str = strdup(literal); - return (IDENT); + return (CSTRING); } <xd>{xdinside} { if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1)) @@ -269,7 +270,22 @@ sql [sS][qQ][lL] memcpy(literal+llen, yytext, yyleng+1); llen += yyleng; } - +<C>{xdstart} { + BEGIN(xdc); + llen = 0; + *literal = '\0'; + } +<xdc>{xdstop} { + BEGIN(C); + yylval.str = strdup(literal); + return (CSTRING); + } +<xdc>{xdinside} { + if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1)) + yyerror("ERROR: quoted string parse buffer exceeded"); + memcpy(literal+llen, yytext, yyleng+1); + llen += yyleng; + } <xm>{space}* { /* ignore */ } <xm>{xmstop} { @@ -283,7 +299,7 @@ sql [sS][qQ][lL] <SQL>{self}/-[\.0-9] { return (yytext[0]); } -<SQL>{self} { return (yytext[0]); } +<SQL>{self} { return (yytext[0]); } <SQL>{operator}/-[\.0-9] { yylval.str = strdup((char*)yytext); return (Op); @@ -379,6 +395,10 @@ sql [sS][qQ][lL] return (FCONST); } +<SQL>:{identifier} { + yylval.str = strdup((char*)yytext+1); + return(CVARIABLE); + } <SQL>{identifier} { int i; ScanKeyword *keyword; @@ -423,12 +443,14 @@ sql [sS][qQ][lL] } } <C>";" { return(';'); } +<C>"," { return(','); } +<C>"*" { return('*'); } <C>{space} { ECHO; } -\{ { return('{'); } -\} { return('}'); } -\[ { return('['); } -\] { return(']'); } -\= { return('='); } +<C>\{ { return('{'); } +<C>\} { return('}'); } +<C>\[ { return('['); } +<C>\] { return(']'); } +<C>\= { return('='); } <C>{other} { return (S_ANYTHING); } <C>{exec}{space}{sql}{space}{include} { BEGIN(incl); } <incl>{space} /* eat the whitespace */ diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 6eb4a88acd..41537eadda 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -12,9 +12,10 @@ * Variables containing simple states. */ static int struct_level = 0; -static char *do_str = NULL, errortext[128]; -static int do_length = 0; +static char errortext[128]; static int QueryIsRule = 0; +static enum ECPGttype actual_type[128]; +static char *actual_storage[128]; /* temporarily store record members while creating the data structure */ struct ECPGrecord_member *record_member_list[128] = { NULL }; @@ -22,6 +23,9 @@ struct ECPGrecord_member *record_member_list[128] = { NULL }; /* keep a list of cursors */ struct cursor *cur = NULL; +struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}}; +struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; + /* * Handle the filename and line numbering. */ @@ -82,15 +86,6 @@ whenever_action() */ int braces_open; -/* This is a linked list of the variable names and types. */ -struct variable -{ - char * name; - struct ECPGtype * type; - int brace_level; - struct variable * next; -}; - static struct variable * allvariables = NULL; static struct variable * @@ -105,7 +100,7 @@ find_variable(char * name) return p; } - sprintf(errorstring, "The variable :%s is not declared", name); + sprintf(errorstring, "The variable %s is not declared", name); yyerror(errorstring); free (errorstring); @@ -167,9 +162,6 @@ struct arguments { static struct arguments * argsinsert = NULL; static struct arguments * argsresult = NULL; -static struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}}; -static struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; - static void reset_variables(void) { @@ -209,7 +201,9 @@ dump_variables(struct arguments * list) dump_variables(list->next); /* Then the current element and its indicator */ - ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->indicator->name, list->indicator->type, NULL, NULL); + 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. */ free(list); @@ -360,7 +354,15 @@ make_name(void) static void output_statement(const char * stmt) { - fprintf(yyout, "ECPGdo(__LINE__, \"%s\", ", stmt); + int i, j=strlen(stmt); + + fputs("ECPGdo(__LINE__, \"", yyout); + + /* do this char by char as we have to filter '\"' */ + for (i = 0;i < j; i++) + if (stmt[i] != '\"') + fputc(stmt[i], yyout); + fputs("\", ", yyout); /* dump variables to C file*/ dump_variables(argsinsert); @@ -375,14 +377,14 @@ output_statement(const char * stmt) double dval; int ival; char * str; - struct ECPGtemp_type type; struct when action; + struct index index; int tagname; enum ECPGttype type_enum; } /* special embedded SQL token */ -%token SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO +%token SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO %token SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN %token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START %token SQL_STOP SQL_WHENEVER @@ -449,7 +451,7 @@ output_statement(const char * stmt) %token USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL /* Special keywords, not in the query language - see the "lex" file */ -%token <str> IDENT SCONST Op +%token <str> IDENT SCONST Op CSTRING CVARIABLE %token <ival> ICONST PARAM %token <dval> FCONST @@ -538,11 +540,18 @@ output_statement(const char * stmt) %type <str> GrantStmt privileges operation_commalist operation %type <str> ECPGWhenever ECPGConnect db_name ECPGOpen open_opts -%type <str> indicator ECPGExecute c_expr +%type <str> indicator ECPGExecute c_expr variable_list dotext +%type <str> storage_clause opt_initializer vartext c_anything blockstart +%type <str> blockend variable_list variable var_anything sql_anything +%type <str> opt_pointer ecpg_ident cvariable identlist + %type <str> stmt symbol +%type <type_enum> simple_type type struct_type + %type <action> action +%type <index> opt_index %% prog: statements; @@ -551,9 +560,9 @@ statements: /* empty */ statement: ecpgstart stmt SQL_SEMI | ECPGDeclaration - | c_anything - | blockstart - | blockend + | c_anything { fputs($1, yyout); } + | blockstart { fputs($1, yyout); } + | blockend { fputs($1, yyout); } stmt: AddAttrStmt { output_statement($1); } | AlterUserStmt { output_statement($1); } @@ -1332,7 +1341,7 @@ TriggerFuncArg: Iconst $$ = make_name(); } | Sconst { $$ = $1; } - | IDENT { $$ = $1; } + | ecpg_ident { $$ = $1; } ; DropTrigStmt: DROP TRIGGER name ON relation_name @@ -1829,7 +1838,7 @@ OptStmtMulti: OptStmtMulti OptimizableStmt ';' event_object: relation_name '.' attr_name { - $$ = make3_str($1, ",", $3); + $$ = cat3_str($1, ".", $3); } | relation_name { @@ -2243,7 +2252,7 @@ sortby: ColId OptUseOp } | ColId '.' ColId OptUseOp { - $$ = make4_str($1, ".", $3, $4); + $$ = make2_str(cat3_str($1, ".", $3), $4); } | Iconst OptUseOp { @@ -2292,7 +2301,7 @@ groupby: ColId } | ColId '.' ColId { - $$ = make3_str($1, ",", $3); + $$ = cat3_str($1, ",", $3); } | Iconst { @@ -2383,7 +2392,7 @@ join_using: ColId } | ColId '.' ColId { - $$ = make3_str($1, ".", $3); + $$ = cat3_str($1, ".", $3); } | Iconst { @@ -2455,7 +2464,7 @@ Generic: generic } ; -generic: IDENT { $$ = $1; } +generic: ecpg_ident { $$ = $1; } | TYPE_P { $$ = "type"; } ; @@ -3409,20 +3418,20 @@ not_in_expr_nodes: AexprConst attr: relation_name '.' attrs { - $$ = make3_str($1, ".", $3); + $$ = cat3_str($1, ".", $3); } | ParamNo '.' attrs { - $$ = make3_str($1, ".", $3); + $$ = cat3_str($1, ".", $3); } ; attrs: attr_name { $$ = $1; } | attrs '.' attr_name - { $$ = make3_str($1, ".", $3); } + { $$ = cat3_str($1, ".", $3); } | attrs '.' '*' - { $$ = make2_str($1, ".*"); } + { $$ = cat2_str($1, ".*"); } ; @@ -3449,7 +3458,7 @@ res_target_el: ColId opt_indirection '=' a_expr_or_null } | relation_name '.' '*' { - $$ = make2_str($1, ".*"); + $$ = cat2_str($1, ".*"); } ; @@ -3475,7 +3484,7 @@ res_target_el2: a_expr_or_null AS ColLabel } | relation_name '.' '*' { - $$ = make2_str($1, ".*"); + $$ = cat2_str($1, ".*"); } | '*' { @@ -3505,9 +3514,9 @@ relation_name: SpecialRuleRelation ; database_name: ColId { $$ = $1; }; -access_method: IDENT { $$ = $1; }; +access_method: ecpg_ident { $$ = $1; }; attr_name: ColId { $$ = $1; }; -class: IDENT { $$ = $1; }; +class: ecpg_ident { $$ = $1; }; index_name: ColId { $$ = $1; }; /* Functions @@ -3518,7 +3527,7 @@ name: ColId { $$ = $1; }; func_name: ColId { $$ = $1; }; file_name: Sconst { $$ = $1; }; -recipe_name: IDENT { $$ = $1; }; +recipe_name: ecpg_ident { $$ = $1; }; /* Constants * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24 @@ -3569,7 +3578,7 @@ Sconst: SCONST { $$[strlen($1)+2]='\0'; $$[strlen($1)+1]='\''; } -UserId: IDENT { $$ = $1;}; +UserId: ecpg_ident { $$ = $1;}; /* Column and type identifier * Does not include explicit datetime types @@ -3591,7 +3600,7 @@ TypeId: ColId * list due to shift/reduce conflicts in yacc. If so, move * down to the ColLabel entity. - thomas 1997-11-06 */ -ColId: IDENT { $$ = $1; } +ColId: ecpg_ident { $$ = $1; } | datetime { $$ = $1; } | ACTION { $$ = "action"; } | CACHE { $$ = "cache"; } @@ -3688,169 +3697,139 @@ sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI { output_line_number(); } -variable_declarations : /* empty */ - | variable_declarations variable_declaration; +variable_declarations: /* empty */ + | declaration variable_declarations; -/* Here is where we can enter support for typedef. */ -variable_declaration: type initializer ';' { - /* 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((void *)$<type>1.name); - } - fputs(";", yyout); -} +declaration: storage_clause type + { + actual_storage[struct_level] = $1; + actual_type[struct_level] = $2; + if ($2 != ECPGt_varchar && $2 != ECPGt_record) + fprintf(yyout, "%s %s", $1, ECPGtype_name($2)); + } + variable_list ';' { fputc(';', yyout); } -initializer : /*empty */ - | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext; +storage_clause : S_EXTERN { $$ = "extern"; } + | S_STATIC { $$ = "static"; } + | S_SIGNED { $$ = "signed"; } + | S_CONST { $$ = "const"; } + | S_REGISTER { $$ = "register"; } + | S_AUTO { $$ = "auto"; } + | /* empty */ { $$ = "" ; } -type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; }; -type_detailed : varchar_type { $<type>$ = $<type>1; } - | simple_type { $<type>$ = $<type>1; } - | string_type { $<type>$ = $<type>1; } -/* | array_type {$<type>$ = $<type>1; } - | pointer_type {$<type>$ = $<type>1; }*/ - | struct_type {$<type>$ = $<type>1; }; +type: simple_type + | struct_type -varchar_type : varchar_tag symbol index { - if ($<ival>3 > 0L) - fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $<ival>3, $2); - else - fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $2, $2); - if (struct_level == 0) - { - $<type>$.name = $2; - $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<ival>3); - } - else - ECPGmake_record_member($2, ECPGmake_varchar_type(ECPGt_varchar, $<ival>3), &(record_member_list[struct_level-1])); -} +struct_type: s_struct '{' variable_declarations '}' + { + struct_level--; + $$ = actual_type[struct_level] = ECPGt_record; + } -varchar_tag: S_VARCHAR /*| S_VARCHAR2 */; +s_struct : S_STRUCT symbol + { + struct_level++; + fprintf(yyout, "struct %s {", $2); + } -simple_type : simple_tag symbol { - fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2); - if (struct_level == 0) - { - $<type>$.name = $2; - $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1); - } - else - ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1])); -} +simple_type: S_SHORT { $$ = ECPGt_short; } + | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; } + | S_INT { $$ = ECPGt_int; } + | S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; } + | S_LONG { $$ = ECPGt_long; } + | S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; } + | S_FLOAT { $$ = ECPGt_float; } + | S_DOUBLE { $$ = ECPGt_double; } + | S_BOOL { $$ = ECPGt_bool; }; + | S_CHAR { $$ = ECPGt_char; } + | S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; } + | S_VARCHAR { $$ = ECPGt_varchar; } -string_type : char_tag symbol index { - if ($<ival>3 > 0L) - fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $2, $<ival>3); - else - fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2); - if (struct_level == 0) - { - $<type>$.name = $2; - $<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<ival>3); - } - else - ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, $<ival>3), &(record_member_list[struct_level-1])); -} - | char_tag '*' symbol { - fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $3); - if (struct_level == 0) - { - $<type>$.name = $3; - $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 0); - } - else - ECPGmake_record_member($3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1])); -} - | char_tag symbol { - fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2); - if (struct_level == 0) - { - $<type>$.name = $2; - $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1); - } - else - ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1])); -} +variable_list: variable + | variable_list ',' + { + if (actual_type[struct_level] != ECPGt_varchar) + fputs(", ", yyout); + else + fputs(";\n ", yyout); + } variable -char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; } - | S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; } +variable: opt_pointer symbol opt_index opt_initializer + { + int length = $3.ival; -/* -array_type : simple_tag symbol index { - if ($<ival>3 > 0) - fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $2, $<ival>3); - else - fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2); - if (struct_level == 0) - { - $<type>$.name = $2; - $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3); - } - else - ECPGmake_record_member($2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3), &(record_member_list[struct_level-1])); -} + /* pointer has to get length 0 */ + if (strlen($1) > 0) + length = 0; -pointer_type : simple_tag '*' symbol { - fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $3); - if (struct_level == 0) - { - $<type>$.name = $3; - $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0); - } - else - ECPGmake_record_member($3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1])); -} -*/ + switch (actual_type[struct_level]) + { + case ECPGt_record: + if (struct_level == 0) + new_variable($2, ECPGmake_record_type(record_member_list[struct_level])); + else + ECPGmake_record_member($2, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); -s_struct : S_STRUCT symbol { - struct_level++; - fprintf(yyout, "struct %s {", $2); -} + record_member_list[struct_level] = NULL; + fprintf(yyout, "} %s%s%s%s", $1, $2, $3.str, $4); -struct_type : s_struct '{' variable_declarations '}' symbol { - struct_level--; - if (struct_level == 0) - { - $<type>$.name = $5; - $<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]); - } - else - ECPGmake_record_member($5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); - fprintf(yyout, "} %s", $5); - record_member_list[struct_level] = NULL; -} + break; + case ECPGt_varchar: + if (strlen($4) != 0) + yyerror("varchar initilization impossible"); -simple_tag : S_SHORT { $<type_enum>$ = ECPGt_short; } - | S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; } - | S_INT { $<type_enum>$ = ECPGt_int; } - | S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; } - | S_LONG { $<type_enum>$ = ECPGt_long; } - | S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; } - | S_FLOAT { $<type_enum>$ = ECPGt_float; } - | S_DOUBLE { $<type_enum>$ = ECPGt_double; } - | S_BOOL { $<type_enum>$ = ECPGt_bool; }; + if (struct_level == 0) + new_variable($2, ECPGmake_varchar_type(actual_type[struct_level], length)); + else + ECPGmake_record_member($2, ECPGmake_varchar_type(actual_type[struct_level], length), &(record_member_list[struct_level-1])); + + if (length > 0) + fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s", actual_storage[struct_level], $2, length, $2); + else + fprintf(yyout, "%s struct varchar_%s { int len; char arr[]; } %s", actual_storage[struct_level], $2, $2); -maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); } - | S_STATIC { fwrite(yytext, yyleng, 1, yyout); } - | S_SIGNED { 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 : '[' Iconst ']' { $<ival>$ = atol($2); } - | '[' ']' { $<ival>$ = 0L; } + break; + + default: + if (struct_level == 0) + new_variable($2, ECPGmake_simple_type(actual_type[struct_level], length)); + else + ECPGmake_record_member($2, ECPGmake_simple_type(actual_type[struct_level], length), &(record_member_list[struct_level-1])); + + fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4); + + break; + } + } + +opt_initializer: /* empty */ { $$ = ""; } + | '=' vartext { $$ = cat2_str("=", $2); } + +opt_pointer: /* empty */ { $$ = ""; } + | '*' { $$ = "*"; } + +opt_index: '[' Iconst ']' { + $$.ival = atol($2); + $$.str = cat3_str("[", $2, "]"); + } + | '[' ']' + { + $$.ival = 0; + $$.str = "[]"; + } + | /* empty */ { + $$.ival = 1; + $$.str = ""; + } /* * the exec sql connect statement: connect to the given database */ -ECPGConnect : SQL_CONNECT db_name { $$ = $2; } +ECPGConnect: SQL_CONNECT db_name { $$ = $2; } -db_name : database_name { $$ = $1; } - | ':' name { /* check if we have a char variable */ - struct variable *p = find_variable($2); +db_name: database_name { $$ = $1; } + | cvariable { /* check if we have a char variable */ + struct variable *p = find_variable($1); enum ECPGttype typ = p->type->typ; /* if array see what's inside */ @@ -3859,13 +3838,13 @@ db_name : database_name { $$ = $1; } if (typ != ECPGt_char && typ != ECPGt_unsigned_char) yyerror("invalid datatype"); - $$ = $2; + $$ = $1; } /* * execute a given string as sql command */ -ECPGExecute : EXECUTE SQL_IMMEDIATE ':' name { $$ = $4; }; +ECPGExecute : EXECUTE SQL_IMMEDIATE cvariable { $$ = $3; }; /* * open is an open cursor, at the moment this has to be removed @@ -3890,12 +3869,15 @@ ECPGOpen: SQL_OPEN name open_opts { }; open_opts: /* empty */ { $$ = ""; } - | USING ':' name { + | USING cvariable { yyerror ("open cursor with variables not implemented yet"); } /* - * whenever statement: decide what to do in case of error/no dat + * whenever statement: decide what to do in case of error/no data found + * according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION + * and SQLWARNING + */ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { when_error.code = $<action>3.code; @@ -3933,17 +3915,15 @@ action : SQL_CONTINUE { $<action>$.command = $3; $<action>$.str = make2_str("goto ", $3); } - | DO name '(' { - do_str = (char *) mm_alloc(do_length = strlen($2) + 4); - sprintf(do_str, "%s (", $2); -} dotext ')' { - do_str[strlen(do_str)+1]='\0'; - do_str[strlen(do_str)]=')'; + | DO name '(' dotext ')' { $<action>$.code = W_DO; - $<action>$.command = do_str; - $<action>$.str = make2_str("do ", do_str); - do_str = NULL; - do_length = 0; + $<action>$.command = cat4_str($2, "(", $4, ")"); + $<action>$.str = make2_str("do", $<action>$.command); +} + | SQL_CALL name '(' dotext ')' { + $<action>$.code = W_DO; + $<action>$.command = cat4_str($2, "(", $4, ")"); + $<action>$.str = make2_str("call", $<action>$.command); } /* some other stuff for ecpg */ @@ -4231,59 +4211,94 @@ into_list : coutputvariable | into_list ',' coutputvariable; ecpgstart: SQL_START { reset_variables();} -dotext: /* empty */ - | dotext sql_anything { - if (strlen(do_str) + yyleng + 1 >= do_length) - do_str = mm_realloc(do_str, do_length += yyleng); +dotext: /* empty */ { $$ = ""; } + | dotext sql_anything { $$ = cat2_str($1, $2); } - strcat(do_str, yytext); +vartext: var_anything { $$ = $1; } + | vartext var_anything { $$ = cat2_str($1, $2); } + +coutputvariable : cvariable indicator { + add_variable(&argsresult, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); } -vartext: both_anything { fwrite(yytext, yyleng, 1, yyout); } - | vartext both_anything { fwrite(yytext, yyleng, 1, yyout); } - -coutputvariable : ':' name indicator { - add_variable(&argsresult, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); +cinputvariable : cvariable indicator { + add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); } -cinputvariable : ':' name indicator { - add_variable(&argsinsert, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); +civariableonly : cvariable name { + add_variable(&argsinsert, find_variable($1), &no_indicator); } -civariableonly : ':' name { - add_variable(&argsinsert, find_variable($2), &no_indicator); -} +cvariable: CVARIABLE { $$ = $1; } + | CVARIABLE '.' identlist { $$ = $1; } + | CVARIABLE '-' '>' identlist { $$ = $1; } + +identlist: IDENT { $$ = $1; } + | IDENT '.' identlist { $$ = $1; } + | IDENT '-' '>' identlist { $$ = $1; } indicator: /* empty */ { $$ = NULL; } - | ':' name { check_indicator((find_variable($2))->type); $$ = $2; } - | SQL_INDICATOR ':' name { check_indicator((find_variable($3))->type); $$ = $3; } + | cvariable { check_indicator((find_variable($1))->type); $$ = $1; } + | SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; } | SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; } +ecpg_ident: IDENT { $$ = $1; } + | CSTRING { $$ = cat3_str("\"", $1, "\""); } /* * C stuff */ -symbol: IDENT { $$ = $1; } +symbol: ecpg_ident { $$ = $1; } -c_anything: both_anything { fwrite(yytext, yyleng, 1, yyout); } - | ';' { fputc(';', yyout); } +c_anything: ecpg_ident { $$ = $1; } + | Iconst { $$ = $1; } + | FCONST { $$ = make_name(); } + | '*' { $$ = "*"; } + | ';' { $$ = ";"; } + | S_AUTO { $$ = "auto"; } + | S_BOOL { $$ = "bool"; } + | S_CHAR { $$ = "char"; } + | S_CONST { $$ = "const"; } + | S_DOUBLE { $$ = "double"; } + | S_EXTERN { $$ = "extern"; } + | S_FLOAT { $$ = "float"; } + | S_INT { $$ = "int"; } + | S_LONG { $$ = "long"; } + | S_REGISTER { $$ = "register"; } + | S_SHORT { $$ = "short"; } + | S_SIGNED { $$ = "signed"; } + | S_STATIC { $$ = "static"; } + | S_STRUCT { $$ = "struct"; } + | S_UNSIGNED { $$ = "unsigned"; } + | S_VARCHAR { $$ = "varchar"; } + | S_ANYTHING { $$ = make_name(); } + | '[' { $$ = "["; } + | ']' { $$ = "]"; } + | '(' { $$ = "("; } + | ')' { $$ = ")"; } + | '=' { $$ = "="; } + | ',' { $$ = ","; } -sql_anything: IDENT {} | ICONST {} | FCONST {} +sql_anything: ecpg_ident { $$ = $1; } + | Iconst { $$ = $1; } + | FCONST { $$ = make_name(); } + | ',' { $$ = ","; } -both_anything: IDENT {} | ICONST {} | FCONST {} - | S_AUTO | S_BOOL | S_CHAR | S_CONST | S_DOUBLE | S_EXTERN | S_FLOAT - | S_INT | S_LONG | S_REGISTER | S_SHORT | S_SIGNED | S_STATIC - | S_STRUCT | S_UNSIGNED | S_VARCHAR | S_ANYTHING - | '[' | ']' | '(' | ')' | '=' +var_anything: ecpg_ident { $$ = $1; } + | Iconst { $$ = $1; } + | FCONST { $$ = make_name(); } +/*FIXME: | ',' { $$ = ","; }*/ + | '{' { $$ = "{"; } + | '}' { $$ = "}"; } blockstart : '{' { braces_open++; - fputc('{', yyout); + $$ = "{"; } blockend : '}' { remove_variables(braces_open--); - fputc('}', yyout); + $$ = "}"; } %% diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 2b43fa9976..4b4e592766 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -130,6 +130,12 @@ ECPGdump_a_record(FILE *o, const char *name, const char *ind_name, long arrsiz, void ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix) { + if (ind_typ == NULL) + { + ind_typ = &ecpg_no_indicator; + ind_name = "no_indicator"; + } + if (IS_SIMPLE_TYPE(typ->typ)) { ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix); @@ -267,7 +273,7 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz, * then we are in a record in a record and the offset is used as * offset. */ - struct ECPGrecord_member *p, *ind_p; + struct ECPGrecord_member *p, *ind_p = NULL; char obuf[BUFSIZ]; char pbuf[BUFSIZ], ind_pbuf[BUFSIZ]; const char *offset; @@ -288,9 +294,11 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz, sprintf(ind_pbuf, "%s%s.", ind_prefix ? ind_prefix : "", ind_name); ind_prefix = ind_pbuf; - for (p = typ->u.members, ind_p = ind_typ->u.members; p; p = p->next, ind_p = ind_p->next) + if (ind_typ != NULL) ind_p = ind_typ->u.members; + for (p = typ->u.members; p; p = p->next) { - ECPGdump_a_type(o, p->name, p->typ, ind_p->name, ind_p->typ, prefix, ind_prefix); + ECPGdump_a_type(o, p->name, p->typ, (ind_p != NULL) ? ind_p->name : NULL, (ind_p != NULL) ? ind_p->typ : NULL, prefix, ind_prefix); + if (ind_p != NULL) ind_p = ind_p->next; } } diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h index 92d87055ee..9d66e3a8cb 100644 --- a/src/interfaces/ecpg/preproc/type.h +++ b/src/interfaces/ecpg/preproc/type.h @@ -74,3 +74,9 @@ struct when char *command; char *str; }; + +struct index +{ + int ival; + char *str; +}; diff --git a/src/interfaces/ecpg/test/perftest.pgc b/src/interfaces/ecpg/test/perftest.pgc index 45ca62abfe..8183bf9936 100644 --- a/src/interfaces/ecpg/test/perftest.pgc +++ b/src/interfaces/ecpg/test/perftest.pgc @@ -119,5 +119,7 @@ exec sql end declare section; exec sql drop table perftest1; + exec sql commit; + return (0); } diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc index e0bdac9287..5330991196 100644 --- a/src/interfaces/ecpg/test/test2.pgc +++ b/src/interfaces/ecpg/test/test2.pgc @@ -24,7 +24,7 @@ exec sql begin declare section; } ind_birth; } ind_personal; long ind_married; - char married[9]="a"; + char married[9]; exec sql end declare section; char msg[128], command[128]; FILE *dbgs; @@ -60,7 +60,7 @@ exec sql end declare section; while (not_found == 0) { strcpy(msg, "fetch"); - exec sql fetch cur into :personal:ind_personal, :married:ind_married; + exec sql fetch cur into :personal:ind_personal, :married:ind_married, :personal.birth.born; if (not_found == 0) printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married); }