From 80f7c4138859543e447b5358623eb63bca1bbd68 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Fri, 20 Mar 1998 03:08:11 +0000 Subject: [PATCH] Here's my next patch to bring ecpg to version 1.1. It now correctly handles all transaction commands and the exec sql include command. Michael Meskes --- src/interfaces/ecpg/ChangeLog | 15 ++++ src/interfaces/ecpg/TODO | 5 +- src/interfaces/ecpg/include/ecpglib.h | 16 +++- src/interfaces/ecpg/include/ecpgtype.h | 8 ++ src/interfaces/ecpg/include/sqlca.h | 9 +++ src/interfaces/ecpg/lib/Makefile.in | 2 +- src/interfaces/ecpg/lib/ecpglib.c | 29 +++---- src/interfaces/ecpg/preproc/Makefile | 6 +- src/interfaces/ecpg/preproc/ecpg.c | 107 ++++++++++++++++--------- src/interfaces/ecpg/preproc/extern.h | 5 ++ src/interfaces/ecpg/preproc/pgc.l | 99 ++++++++++++++++++++++- src/interfaces/ecpg/preproc/preproc.y | 61 ++++++++------ src/interfaces/ecpg/test/perftest.pgc | 3 +- src/interfaces/ecpg/test/test2.pgc | 5 +- 14 files changed, 275 insertions(+), 95 deletions(-) diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 44f87208f0..f20a717dbc 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -71,3 +71,18 @@ Fri Feb 27 12:00:55 CET 1998 - removed all shift/reduce conflicts - allow syntax 'fetch cursor' as well as 'fetch in cursor' +Fri Mar 13 11:37:16 CET 1998 + + - finished transaction handling, needs only one function in ecpglib now + old functions are still supported for compatibility + - set library to version 1.1.0 + +Fri Mar 13 13:35:13 CET 1998 + + - exec sql include includes files during parsing + - set parser to version 1.1.0 + - added -I option to ecpg to set include path + +Mon Mar 16 15:09:10 CET 1998 + + - fixed parser to print correct filename and line number diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO index 8385553963..4c7c15f40f 100644 --- a/src/interfaces/ecpg/TODO +++ b/src/interfaces/ecpg/TODO @@ -59,4 +59,7 @@ There is no way yet to fill a complete array with one call except arrays of ecpg cannot use pointer variables except [unsigned] char * -List all commands as sqlcommand, not just S_SYMBOL +List all commands as sqlcommand, not just S_SYMBOL or even better rewrite +pareser to be equivalent to backendīs parser. + +Set standard include paths. diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index b506908ebc..6dd2f92aeb 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -1,15 +1,23 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + void ECPGdebug(int, FILE *); bool ECPGconnect(const char *dbname); bool ECPGdo(int, char *,...); -bool ECPGcommit(int); -bool ECPGrollback(int); +bool ECPGtrans(int, const char *); bool ECPGfinish(void); bool ECPGstatus(void); void ECPGlog(const char *format,...); +/* These functions are only kept for compatibility reasons. */ +/* Use ECPGtrans instead. */ +bool ECPGcommit(int); +bool ECPGrollback(int); + #ifdef LIBPQ_FE_H bool ECPGsetdb(PGconn *); @@ -32,3 +40,7 @@ void sqlprint(void); /* define this for simplicity as well as compatibility */ #define SQLCODE sqlca.sqlcode + +#ifdef __cplusplus +} +#endif diff --git a/src/interfaces/ecpg/include/ecpgtype.h b/src/interfaces/ecpg/include/ecpgtype.h index 5cecc9e2e1..30b1f55713 100644 --- a/src/interfaces/ecpg/include/ecpgtype.h +++ b/src/interfaces/ecpg/include/ecpgtype.h @@ -29,6 +29,10 @@ */ #include +#ifdef __cplusplus +extern "C" { +#endif + enum ECPGttype { ECPGt_char = 1, ECPGt_unsigned_char, ECPGt_short, ECPGt_unsigned_short, @@ -45,3 +49,7 @@ enum ECPGttype #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2) const char * ECPGtype_name(enum ECPGttype); + +#ifdef __cplusplus +} +#endif diff --git a/src/interfaces/ecpg/include/sqlca.h b/src/interfaces/ecpg/include/sqlca.h index 454eba2201..e493e46bb5 100644 --- a/src/interfaces/ecpg/include/sqlca.h +++ b/src/interfaces/ecpg/include/sqlca.h @@ -1,6 +1,10 @@ #ifndef POSTGRES_SQLCA_H #define POSTGRES_SQLCA_H +#ifdef __cplusplus +extern "C" { +#endif + struct sqlca { int sqlcode; @@ -12,3 +16,8 @@ struct sqlca } sqlca; #endif + +#ifdef __cplusplus +} +#endif + diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in index 34faf548c1..a39af1df62 100644 --- a/src/interfaces/ecpg/lib/Makefile.in +++ b/src/interfaces/ecpg/lib/Makefile.in @@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq SO_MAJOR_VERSION=1 -SO_MINOR_VERSION=0 +SO_MINOR_VERSION=1 PORTNAME=@PORTNAME@ diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c index 301b43d6c7..87b2350bdb 100644 --- a/src/interfaces/ecpg/lib/ecpglib.c +++ b/src/interfaces/ecpg/lib/ecpglib.c @@ -572,14 +572,14 @@ ECPGdo(int lineno, char *query,...) bool -ECPGcommit(int lineno) +ECPGtrans(int lineno, const char * transaction) { PGresult *res; - ECPGlog("ECPGcommit line %d\n", lineno); - if ((res = PQexec(simple_connection, "end")) == NULL) + ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction); + if ((res = PQexec(simple_connection, transaction)) == NULL) { - register_error(-1, "Error committing line %d.", lineno); + register_error(-1, "Error in transaction processing line %d.", lineno); return (FALSE); } PQclear(res); @@ -587,24 +587,19 @@ ECPGcommit(int lineno) return (TRUE); } +/* include these for compatibility */ +bool +ECPGcommit(int lineno) +{ + return(ECPGtrans(lineno, "end")); +} + bool ECPGrollback(int lineno) { - PGresult *res; - - ECPGlog("ECPGrollback line %d\n", lineno); - if ((res = PQexec(simple_connection, "abort")) == NULL) - { - register_error(-1, "Error rolling back line %d.", lineno); - return (FALSE); - } - PQclear(res); - committed = 1; - return (TRUE); + return(ECPGtrans(lineno, "abort")); } - - bool ECPGsetdb(PGconn *newcon) { diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 92d3e8b390..9dc093aa23 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -2,10 +2,12 @@ SRCDIR= ../../.. include $(SRCDIR)/Makefile.global MAJOR_VERSION=1 -MINOR_VERSION=0 +MINOR_VERSION=1 PATCHLEVEL=0 -CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) +CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ + -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \ + -DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\" all:: ecpg diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index e31d4cfd42..321406f85b 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -9,6 +9,8 @@ #include #else #include +extern int optind; +extern char *optarg; #endif #include #if defined(HAVE_STRING_H) @@ -19,19 +21,37 @@ #include "extern.h" +struct _include_path *include_paths; + 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] [ -o outout file name] file1 [file2] ...\n", progname); + fprintf(stderr, "Usage: %s: [-v] [-d] [-I include path] [ -o output file name] file1 [file2] ...\n", progname); +} + +static void +add_include_path(char * path) +{ + struct _include_path *ip = include_paths; + + include_paths = mm_alloc(sizeof(struct _include_path)); + include_paths->path = path; + include_paths->next = ip; } int main(int argc, char *const argv[]) { int fnr, c, out_option = 0; + struct _include_path *ip; + + add_include_path("/usr/include"); + add_include_path(INCLUDE_PATH); + add_include_path("/usr/local/include"); + add_include_path("."); - while ((c = getopt(argc, argv, "vdo:")) != EOF) + while ((c = getopt(argc, argv, "vdo:I:")) != EOF) { switch (c) { @@ -45,64 +65,71 @@ main(int argc, char *const argv[]) case 'd': debugging = 1; break; + case 'I': + add_include_path(optarg); + break; case 'v': + fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); + fprintf(stderr, "exec sql include ... search starts here:\n"); + for (ip = include_paths; ip != NULL; ip = ip->next) + fprintf(stderr, " %s\n", ip->path); + fprintf(stderr, "End of search list.\n"); + return (0); default: usage(argv[0]); + return (1); } } if (optind >= argc) /* no files specified */ + { usage(argv[0]); + return(1); + } else { /* after the options there must not be anything but filenames */ for (fnr = optind; fnr < argc; fnr++) { - char *filename, - *ptr2ext; - int ext = 0; + char *output_filename, *ptr2ext; - filename = mm_alloc(strlen(argv[fnr]) + 4); + input_filename = mm_alloc(strlen(argv[fnr]) + 5); - strcpy(filename, argv[fnr]); + strcpy(input_filename, argv[fnr]); - ptr2ext = strrchr(filename, '.'); - /* no extension or extension not equal .pgc */ - if (ptr2ext == NULL || strcmp(ptr2ext, ".pgc") != 0) - { - if (ptr2ext == NULL) - ext = 1; /* we need this information a while later */ - ptr2ext = filename + strlen(filename); - ptr2ext[0] = '.'; - } - - /* make extension = .c */ - ptr2ext[1] = 'c'; - ptr2ext[2] = '\0'; - - if (out_option == 0)/* calculate the output name */ - { - yyout = fopen(filename, "w"); - if (yyout == NULL) - { - perror(filename); - free(filename); - continue; - } - } - - if (ext == 1) + ptr2ext = strrchr(input_filename, '.'); + /* no extension? */ + if (ptr2ext == NULL) { + ptr2ext = input_filename + strlen(input_filename); + /* no extension => add .pgc */ - ptr2ext = strrchr(filename, '.'); + ptr2ext[0] = '.'; ptr2ext[1] = 'p'; ptr2ext[2] = 'g'; ptr2ext[3] = 'c'; ptr2ext[4] = '\0'; - input_filename = filename; } - else - input_filename = argv[fnr]; + + if (out_option == 0)/* calculate the output name */ + { + output_filename = strdup(input_filename); + + ptr2ext = strrchr(output_filename, '.'); + /* make extension = .c */ + ptr2ext[1] = 'c'; + ptr2ext[2] = '\0'; + + yyout = fopen(output_filename, "w"); + if (yyout == NULL) + { + perror(output_filename); + free(output_filename); + free(input_filename); + continue; + } + } + yyin = fopen(input_filename, "r"); if (yyin == NULL) perror(argv[fnr]); @@ -117,12 +144,14 @@ main(int argc, char *const argv[]) /* and parse the source */ yyparse(); - fclose(yyin); + if (yyin != NULL) + fclose(yyin); if (out_option == 0) fclose(yyout); } - free(filename); + free(output_filename); + free(input_filename); } } return (0); diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index b6166f9bb9..53da42cfb1 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -8,6 +8,11 @@ extern int yylineno, extern FILE *yyin, *yyout; +struct _include_path { char * path; + struct _include_path * next; + }; + +extern struct _include_path *include_paths; /* functions */ diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 75a9708322..adda5e2278 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -1,15 +1,28 @@ /* Copyright comment! */ %{ #include +#include +#if defined(HAVE_STRING_H) +#include +#else +#include +#endif + #include "type.h" #include "y.tab.h" #include "extern.h" +struct _yy_buffer { YY_BUFFER_STATE buffer; + long lineno; + char * filename; + struct _yy_buffer * next; + } *yy_buffer = NULL; + #define dbg(arg) if (debugging) fprintf(stderr, "DEBUG, %d: %s\n", yylineno, #arg); %} %option yylineno -%s C SQL +%s C SQL incl ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/ ws ([ \t\n][ \t\n]*|{ccomment})* letter [A-Za-z_] @@ -19,6 +32,7 @@ symbol {letter}({letter}|{digit})* label ({letter}|{digit})* string '[^']*' +abort [aA][bB][oO][rR][tT] begin [bB][eE][gG][iI][nN] commit [cC][oO][mM][mM][iI][tT] connect [cC][oO][nN][nN][eE][cC][tT] @@ -46,21 +60,23 @@ sql [sS][qQ][lL] sqlerror [sS][qQ][lL][eE][rR][rR][oO][rR] sqlprint [sS][qQ][lL][pP][rR][iI][nN][tT] stop [sS][tT][oO][pP] +transaction [tT][rR][aA][nN][sS][aA][cC][tT][iI][oO][nN] to [tT][oO] varchar [vV][aA][rR][cC][hH][aA][rR] varchar2 [vV][aA][rR][cC][hH][aA][rR]2 whenever [wW][hH][eE][nN][eE][vV][eE][rR] work [wW][oO][rR][kK] +vacuum [vV][aA][cC][uU][uU][mM] %% {exec}{ws}{sql} { BEGIN SQL; dbg(SQL_START); return SQL_START; } ";" { BEGIN C; dbg(SQL_SEMI); return SQL_SEMI; } +{abort} { dbg(SQL_ABORT); return SQL_ABORT; } {begin} { dbg(SQL_BEGIN); return SQL_BEGIN; } {end} { dbg(SQL_END); return SQL_END; } {declare} { dbg(SQL_DECLARE); return SQL_DECLARE; } {execute} { dbg(SQL_EXECUTE); return SQL_EXECUTE; } {immediate} { dbg(SQL_IMMEDIATE); return SQL_IMMEDIATE; } {section} { dbg(SQL_SECTION); return SQL_SECTION; } -{include} { dbg(SQL_INCLUDE); return SQL_INCLUDE; } {connect} { dbg(SQL_CONNECT); return SQL_CONNECT; } {open} { dbg(SQL_OPEN); return SQL_OPEN; } {commit} { dbg(SQL_COMMIT); return SQL_COMMIT; } @@ -80,7 +96,62 @@ work [wW][oO][rR][kK] {stop} { dbg(SQL_STOP); return SQL_STOP; } {do} { dbg(SQL_DO); return SQL_DO; } {from} { dbg(SQL_FROM); return SQL_FROM; } - +{transaction} { dbg(SQL_TRANSACTION); return SQL_TRANSACTION; } +{vacuum} { dbg(SQL_VACUUM); return SQL_VACUUM; } + + +{exec}{ws}{sql}{ws}{include} { BEGIN(incl); } +{ws} /* eat the whitespace */ +[^ \t\n]+ { /* got the include file name */ + struct _yy_buffer *yb; + struct _include_path *ip; + char inc_file[PATH_MAX]; + + yb = mm_alloc(sizeof(struct _yy_buffer)); + + yb->buffer = YY_CURRENT_BUFFER; + yb->lineno = yylineno; + yb->filename = input_filename; + yb->next = yy_buffer; + + yy_buffer = yb; + + if (yytext[strlen(yytext) - 1] == ';') + yytext[strlen(yytext) - 1] = '\0'; + + yyin = NULL; + for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next) + { + if (strlen(ip->path) + strlen(yytext) + 3 > PATH_MAX) + { + fprintf(stderr, "Path %s/%s is too long, skipping.\n", ip->path, yytext); + continue; + } + sprintf (inc_file, "%s/%s", ip->path, yytext); + yyin = fopen( inc_file, "r" ); + if (!yyin) + { + if (strcmp(inc_file + strlen(inc_file) - 2, ".h")) + { + strcat(inc_file, ".h"); + yyin = fopen( inc_file, "r" ); + } + + } + } + if (!yyin) + { + fprintf(stderr, "Cannot open include file %s\n", yytext); + exit(1); + } + + input_filename = strdup(inc_file); + yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE )); + yylineno = 0; + + BEGIN C; + } +";" { BEGIN C; } {length} { dbg(S_LENGTH); return S_LENGTH; } {varchar} { dbg(S_VARCHAR); return S_VARCHAR; } @@ -154,6 +225,28 @@ struct { dbg(S_STRUCT); return S_STRUCT; } {ws} { ECHO; } . { dbg(.); return S_ANYTHING; } +<> { if (yy_buffer == NULL) + yyterminate(); + else + { + struct _yy_buffer *yb = yy_buffer; + + if (yyin != NULL) + fclose(yyin); + + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer(yy_buffer->buffer); + + yylineno = yy_buffer->lineno; + + free(input_filename); + input_filename = yy_buffer->filename; + + yy_buffer = yy_buffer->next; + free(yb); + } + } + %% void lex_init(void) diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index a3bdc7224a..d3a2fc6d9b 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -226,6 +226,7 @@ dump_variables(struct arguments * list) %token SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK SQL_WHENEVER %token SQL_SQLERROR SQL_NOT_FOUND SQL_CONTINUE SQL_FROM SQL_FETCH %token SQL_DO SQL_GOTO SQL_SQLPRINT SQL_STOP SQL_CONV +%token SQL_ABORT SQL_TRANSACTION SQL_VACUUM %token S_SYMBOL S_LENGTH S_ANYTHING S_LABEL %token S_VARCHAR S_VARCHAR2 @@ -236,32 +237,31 @@ dump_variables(struct arguments * list) %type type type_detailed varchar_type simple_type struct_type string_type /* % type array_type pointer_type */ -%type symbol label +%type symbol label transactionstmt %type maybe_storage_clause varchar_tag db_name cursor %type simple_tag char_tag %type index length %type action -%type canything sqlanything both_anything vartext commit_release sqlcommand - +%type canything sqlanything both_anything vartext sqlcommand +%type transbegin, transend, transabort %% prog : statements; statements : /* empty */ | statements statement; -statement : sqldeclaration - | sqlinclude - | sqlconnect - | sqlopen - | sqlcommit - | sqlrollback +statement : sqlconnect + | sqldeclaration | sqlexecute - | sqlwhenever - | sqlstatement | sqlfetch - | cthing + | sqlinclude + | sqlopen + | sqlstatement + | sqltransaction + | sqlwhenever | blockstart - | blockend; + | blockend + | cthing; sqldeclaration : sql_startdeclare variable_declarations @@ -489,19 +489,32 @@ sqlgarbage : /* Empty */ | sqlgarbage sqlanything; -sqlcommit : SQL_START commit_release SQL_SEMI { - fprintf(yyout, "ECPGcommit(__LINE__);"); +sqltransaction : SQL_START transactionstmt SQL_SEMI { + fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $2); whenever_action(); } -commit_release : SQL_COMMIT - | SQL_COMMIT SQL_RELEASE - | SQL_COMMIT SQL_WORK SQL_RELEASE; -sqlrollback : SQL_START SQL_ROLLBACK SQL_SEMI { - fprintf(yyout, "ECPGrollback(__LINE__);"); - whenever_action(); -}; +transactionstmt: transbegin + { + $$="begin"; + } + | transend + { + $$="end"; + } + | transabort + { + $$="abort"; + } + +transabort: SQL_ABORT SQL_TRANSACTION | SQL_ROLLBACK SQL_WORK + | SQL_ABORT | SQL_ROLLBACK; + +transend: SQL_END SQL_TRANSACTION | SQL_COMMIT | SQL_COMMIT SQL_RELEASE + | SQL_COMMIT SQL_WORK SQL_RELEASE; + +transbegin: SQL_BEGIN SQL_TRANSACTION | SQL_BEGIN SQL_WORK; sqlexecute : SQL_START SQL_EXECUTE SQL_IMMEDIATE ':' symbol SQL_SEMI { fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT );", $5); @@ -605,9 +618,9 @@ sqlstatement : SQL_START { /* Reset stack */ } /* FIXME: instead of S_SYMBOL we should list all possible commands */ -sqlcommand : S_SYMBOL | SQL_DECLARE; +sqlcommand : S_SYMBOL | SQL_DECLARE | SQL_VACUUM; -sqlstatement_words : sqlstatement_word +sqlstatement_words : /* empty */ | sqlstatement_words sqlstatement_word; sqlstatement_word : ':' symbol diff --git a/src/interfaces/ecpg/test/perftest.pgc b/src/interfaces/ecpg/test/perftest.pgc index 6e212cf6b9..46df24b4d5 100644 --- a/src/interfaces/ecpg/test/perftest.pgc +++ b/src/interfaces/ecpg/test/perftest.pgc @@ -16,6 +16,7 @@ print_result(long sec, long usec, char *text) usec+=1000000; } printf("I needed %ld seconds and %ld microseconds for the %s test.\n", sec, usec, text); + exec sql vacuum analyze; } int @@ -107,7 +108,5 @@ 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 54a6d6e30a..6500ba89a9 100644 --- a/src/interfaces/ecpg/test/test2.pgc +++ b/src/interfaces/ecpg/test/test2.pgc @@ -1,12 +1,9 @@ #include -exec sql include sqlca; +exec sql include header_test; extern void ECPGdebug(int n, FILE *dbgs); -exec sql whenever not found do set_not_found(); -exec sql whenever sqlerror sqlprint; - static int not_found = 0; static void set_not_found(void)