diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in index e236487d6aaec05d351744292689d85f7e14712b..53f3d5ac44abf91be8b3dfc81b971583a469384a 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=2 -SO_MINOR_VERSION=5 +SO_MINOR_VERSION=6 PORTNAME=@PORTNAME@ diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c index 0d3d4fa0e6a471ca82607d4c8fb6cebf2657c467..e2b8e2ce5993ac5130ae7a05c93313e949256bd1 100644 --- a/src/interfaces/ecpg/lib/ecpglib.c +++ b/src/interfaces/ecpg/lib/ecpglib.c @@ -24,7 +24,32 @@ #include <ecpglib.h> #include <sqlca.h> -extern int no_auto_trans; +/* variables visible to the programs */ +int no_auto_trans; + +static struct sqlca sqlca_init = +{ + {'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '}, + sizeof(struct sqlca), + 0, + { 0, {0}}, + {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +struct sqlca sqlca = +{ + {'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '}, + sizeof(struct sqlca), + 0, + { 0, {0}}, + {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; static struct connection { @@ -72,39 +97,6 @@ register_error(long code, char *fmt,...) sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc); } -/* This function returns a newly malloced string that has the ' and \ - in the argument quoted with \. - */ -static -char * -quote_postgres(char *arg) -{ - char *res = (char *) malloc(2 * strlen(arg) + 1); - int i, - ri; - - if (!res) - return(res); - - for (i = 0, ri = 0; arg[i]; i++, ri++) - { - switch (arg[i]) - { - case '\'': - case '\\': - res[ri++] = '\\'; - default: - ; - } - - res[ri] = arg[i]; - } - res[ri] = '\0'; - - return res; -} - - static void ECPGfinish(struct connection *act) { @@ -139,6 +131,54 @@ ECPGfinish(struct connection *act) ECPGlog("ECPGfinish: called an extra time.\n"); } +static char *ecpg_alloc(long size, int lineno) +{ + char *new = (char *) malloc(size); + + if (!new) + { + ECPGfinish(actual_connection); + ECPGlog("out of memory\n"); + register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); + return NULL; + } + + memset(new, '\0', size); + return(new); +} + +/* This function returns a newly malloced string that has the ' and \ + in the argument quoted with \. + */ +static +char * +quote_postgres(char *arg, int lineno) +{ + char *res = (char *) ecpg_alloc(2 * strlen(arg) + 1, lineno); + int i, + ri; + + if (!res) + return(res); + + for (i = 0, ri = 0; arg[i]; i++, ri++) + { + switch (arg[i]) + { + case '\'': + case '\\': + res[ri++] = '\\'; + default: + ; + } + + res[ri] = arg[i]; + } + res[ri] = '\0'; + + return res; +} + /* create a list of variables */ static bool create_statement(int lineno, struct statement **stmt, char *query, va_list ap) @@ -146,15 +186,8 @@ create_statement(int lineno, struct statement **stmt, char *query, va_list ap) struct variable **list = &((*stmt)->inlist); enum ECPGttype type; - *stmt = calloc(sizeof(struct statement), 1); - - if (!*stmt) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); - return false; - } + if (!(*stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno))) + return false; (*stmt)->command = query; (*stmt)->lineno = lineno; @@ -173,14 +206,8 @@ create_statement(int lineno, struct statement **stmt, char *query, va_list ap) { struct variable *var, *ptr; - var = malloc(sizeof(struct variable)); - if (!var) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); + if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno))) return false; - } var->type = type; var->value = va_arg(ap, void *); @@ -217,8 +244,8 @@ ECPGexecute(struct statement *stmt) PGnotify *notify; struct variable *var; - memset((char *) &sqlca, 0, sizeof (sqlca)); - + memcpy((char *)&sqlca, (char *)&sqlca_init, sizeof(sqlca)); + copiedquery = strdup(stmt->command); /* @@ -314,36 +341,19 @@ ECPGexecute(struct statement *stmt) int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize; char * tmp; - newcopy = (char *) malloc(slen + 1); - if (!newcopy) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); + if (!(newcopy = ecpg_alloc(slen + 1, stmt->lineno))) return false; - } strncpy(newcopy, (char *) var->value, slen); newcopy[slen] = '\0'; - mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); - if (!mallocedval) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); + if (!(mallocedval = (char *) ecpg_alloc(2 * strlen(newcopy) + 3, stmt->lineno))) return false; - } strcpy(mallocedval, "'"); - tmp = quote_postgres(newcopy); + tmp = quote_postgres(newcopy, stmt->lineno); if (!tmp) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); return false; - } strcat(mallocedval, tmp); strcat(mallocedval, "'"); @@ -360,36 +370,19 @@ ECPGexecute(struct statement *stmt) (struct ECPGgeneric_varchar *) (var->value); char *tmp; - newcopy = (char *) malloc(variable->len + 1); - if (!newcopy) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); + if (!(newcopy = (char *) ecpg_alloc(variable->len + 1, stmt->lineno))) return false; - } strncpy(newcopy, variable->arr, variable->len); newcopy[variable->len] = '\0'; - mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); - if (!mallocedval) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); + if (!(mallocedval = (char *) ecpg_alloc(2 * strlen(newcopy) + 3, stmt->lineno))) return false; - } strcpy(mallocedval, "'"); - tmp = quote_postgres(newcopy); + tmp = quote_postgres(newcopy, stmt->lineno); if (!tmp) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); return false; - } strcat(mallocedval, tmp); strcat(mallocedval, "'"); @@ -415,16 +408,8 @@ ECPGexecute(struct statement *stmt) * Now tobeinserted points to an area that is to be inserted at * the first %s */ - newcopy = (char *) malloc(strlen(copiedquery) - + strlen(tobeinserted) - + 1); - if (!newcopy) - { - ECPGfinish(actual_connection); - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno); + if (!(newcopy = (char *) ecpg_alloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno))) return false; - } strcpy(newcopy, copiedquery); if ((p = strstr(newcopy, ";;")) == NULL) @@ -857,7 +842,15 @@ ECPGdo(int lineno, char *query, ...) if (create_statement(lineno, &stmt, query, args) == false) return(false); va_end(args); - + + /* are we connected? */ + if (actual_connection == NULL || actual_connection->connection == NULL) + { + ECPGlog("ECPGdo: not connected\n"); + register_error(ECPG_NOT_CONN, "Not connected in line %d", lineno); + return false; + } + return(ECPGexecute(stmt)); } @@ -902,14 +895,10 @@ ECPGsetconn(int lineno, const char *connection_name) bool ECPGconnect(int lineno, const char *dbname, const char *user, const char *passwd, const char * connection_name) { - struct connection *this = malloc(sizeof(struct connection)); + struct connection *this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno); if (!this) - { - ECPGlog("out of memory\n"); - register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); return false; - } if (dbname == NULL && connection_name == NULL) connection_name = "DEFAULT"; @@ -937,7 +926,6 @@ ECPGconnect(int lineno, const char *dbname, const char *user, const char *passwd { ECPGfinish(this); ECPGlog("connect: could not open database %s %s%s in line %d\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "", lineno); - register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname ? dbname : "NULL"); return false; } diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 2b73c8ed88e09f278eefb1908ede0a172b7d9e02..207259559586243f6b0c45084e9686fedb95a82e 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=3 -PATCHLEVEL=5 +MINOR_VERSION=4 +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 1fe777845b7ad3979130c06bbd75347a669da60a..3d8624b334aabbb75208146a6192d2901879af06 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -22,7 +22,7 @@ extern char *optarg; #include "extern.h" struct _include_path *include_paths; -static int no_auto_trans = 0; +int no_auto_trans = 0; struct cursor *cur = NULL; static void @@ -138,10 +138,12 @@ main(int argc, char *const argv[]) else { struct cursor *ptr; + struct _defines *defptr; /* remove old cursor definitions if any are still there */ - for (ptr = cur; ptr != NULL; ptr=ptr->next) + for (ptr = cur; ptr != NULL;) { + struct cursor *this = ptr; struct arguments *l1, *l2; free(ptr->command); @@ -156,12 +158,25 @@ main(int argc, char *const argv[]) l2 = l1->next; free(l1); } + ptr = ptr->next; + free(this); } + + /* remove old defines as well */ + for (defptr = defines; defptr != NULL;) + { + struct _defines *this = defptr; + free(defptr->new); + free(defptr->old); + defptr = defptr->next; + free(this); + } + /* initialize lex */ lex_init(); /* we need two includes and a constant */ - fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/*These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n\nconst int no_auto_trans = %d;\n\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, no_auto_trans); + fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); /* and parse the source */ yyparse(); diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index 43a15394af3d86c92f548255e471c6778c7c1b67..1f25d0824dd0c736d1a63f89199b76e3f3a92046 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -3,7 +3,7 @@ /* variables */ -extern int braces_open; +extern int braces_open, no_auto_trans; extern char *yytext; extern int yylineno, yyleng; @@ -25,6 +25,13 @@ struct cursor { char *name; extern struct cursor *cur; +struct _defines { char *old; + char *new; + struct _defines *next; + }; + +extern struct _defines *defines; + /* This is a linked list of the variable names and types. */ struct variable { diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index f578ec8c766fe1c572ceebdc4ce034eabb82d518..5336d132bf9121ef99690a8b5d31fd34265fc056 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -46,9 +46,12 @@ struct _yy_buffer { YY_BUFFER_STATE buffer; struct _yy_buffer * next; } *yy_buffer = NULL; +struct _defines *defines = NULL; +static char *old; + %} %option yylineno -%s C SQL incl +%s C SQL incl def def_ident /* OK, here is a short description of lex/flex rules behavior. * The longest pattern which matches an input string is always chosen. * For equal-length patterns, the first occurring in the rules list is chosen. @@ -156,6 +159,7 @@ other . /* some stuff needed for ecpg */ ccomment "//".*\n exec [eE][xX][eE][cC] +define [dD][eE][fF][iI][nN][eE] include [iI][nN][cC][lL][uU][dD][eE] sql [sS][qQ][lL] @@ -307,7 +311,6 @@ cppline {space}*#.*(\\{space}*\n)*\n* <SQL>{typecast} { return TYPECAST; } - <SQL>{self}/{space}*-[\.0-9] { BEGIN(xm); return (yytext[0]); @@ -328,7 +331,6 @@ cppline {space}*#.*(\\{space}*\n)*\n* yylval.ival = atoi((char*)&yytext[1]); return (PARAM); } - <SQL>{identifier}/{space}*-{number} { int i; ScanKeyword *keyword; @@ -350,12 +352,36 @@ cppline {space}*#.*(\\{space}*\n)*\n* } else { - yylval.str = strdup((char*)yytext); - return (IDENT); + struct _defines *ptr; + + for (ptr = defines; ptr; ptr = ptr->next) + { + if (strcmp(yytext, ptr->old) == 0) + { + struct _yy_buffer *yb; + + yb = mm_alloc(sizeof(struct _yy_buffer)); + + yb->buffer = YY_CURRENT_BUFFER; + yb->lineno = yylineno; + yb->filename = strdup(input_filename); + yb->next = yy_buffer; + + yy_buffer = yb; + + yy_scan_string(ptr->new); + break; + } + } + if (ptr == NULL) + { + yylval.str = strdup((char*)yytext); + return (IDENT); + } } } } -{integer}/{space}*-{number} { +<SQL>{integer}/{space}*-{number} { char* endptr; BEGIN(xm); @@ -372,7 +398,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* } return (ICONST); } -{real}/{space}*-{number} { +<SQL>{real}/{space}*-{number} { char* endptr; BEGIN(xm); @@ -382,7 +408,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* yyerror("ERROR: Bad float8 input"); return (FCONST); } -{integer} { +<SQL>{integer} { char* endptr; errno = 0; @@ -398,7 +424,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* } return (ICONST); } -{real} { +<SQL>{real} { char* endptr; errno = 0; @@ -407,7 +433,39 @@ cppline {space}*#.*(\\{space}*\n)*\n* yyerror("ERROR: Bad float input"); return (FCONST); } +<C>{integer}/{space}*-{number} { + char* endptr; + BEGIN(xm); + errno = 0; + yylval.ival = strtol((char *)yytext,&endptr,10); + if (*endptr != '\0' || errno == ERANGE) + { + errno = 0; + yylval.dval = strtod(((char *)yytext),&endptr); + if (*endptr != '\0' || errno == ERANGE) + yyerror("ERROR: Bad integer input"); + yyerror("WARNING: Integer input is out of range; promoted to float"); + return (FCONST); + } + return (ICONST); + } +<C>{integer} { + char* endptr; + + errno = 0; + yylval.ival = strtol((char *)yytext,&endptr,10); + if (*endptr != '\0' || errno == ERANGE) + { + errno = 0; + yylval.dval = strtod(((char *)yytext),&endptr); + if (*endptr != '\0' || errno == ERANGE) + yyerror("ERROR: Bad integer input"); + yyerror("WARNING: Integer input is out of range; promoted to float"); + return (FCONST); + } + return (ICONST); + } <SQL>:{identifier}(("->"|\.){identifier})* { yylval.str = strdup((char*)yytext+1); return(CVARIABLE); @@ -432,15 +490,38 @@ cppline {space}*#.*(\\{space}*\n)*\n* } else { - yylval.str = strdup((char*)yytext); - return (IDENT); + struct _defines *ptr; + + for (ptr = defines; ptr; ptr = ptr->next) + { + if (strcmp(yytext, ptr->old) == 0) + { + struct _yy_buffer *yb; + + yb = mm_alloc(sizeof(struct _yy_buffer)); + + yb->buffer = YY_CURRENT_BUFFER; + yb->lineno = yylineno; + yb->filename = strdup(input_filename); + yb->next = yy_buffer; + + yy_buffer = yb; + + yy_scan_string(ptr->new); + break; + } + } + if (ptr == NULL) + { + yylval.str = strdup((char*)yytext); + return (IDENT); + } } } } <SQL>{space} { /* ignore */ } <SQL>";" { BEGIN C; return SQL_SEMI; } <SQL>{other} { return (yytext[0]); } - <C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; } <C>{ccomment} { /* ignore */ } <C>{cppline} { @@ -456,8 +537,32 @@ cppline {space}*#.*(\\{space}*\n)*\n* } else { - yylval.str = strdup((char*)yytext); - return (IDENT); + struct _defines *ptr; + + for (ptr = defines; ptr; ptr = ptr->next) + { + if (strcmp(yytext, ptr->old) == 0) + { + struct _yy_buffer *yb; + + yb = mm_alloc(sizeof(struct _yy_buffer)); + + yb->buffer = YY_CURRENT_BUFFER; + yb->lineno = yylineno; + yb->filename = strdup(input_filename); + yb->next = yy_buffer; + + yy_buffer = yb; + + yy_scan_string(ptr->new); + break; + } + } + if (ptr == NULL) + { + yylval.str = strdup((char*)yytext); + return (IDENT); + } } } <C>";" { return(';'); } @@ -470,6 +575,45 @@ cppline {space}*#.*(\\{space}*\n)*\n* <C>\] { return(']'); } <C>\= { return('='); } <C>{other} { return (S_ANYTHING); } +<C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);} +<def_ident>{space} {} +<def_ident>{identifier} { + old = strdup(yytext); + BEGIN(def); + llen = 0; + *literal = '\0'; + } +<def>{space} /* eat the whitespace */ +<def>";" { + struct _defines *ptr, *this; + + for (ptr = defines; ptr != NULL; ptr = ptr->next) + { + if (strcmp(old, ptr->old) == 0) + { + free(ptr->new); + ptr->new = strdup(scanstr(literal)); + } + } + if (ptr == NULL) + { + this = (struct _defines *) mm_alloc(sizeof(struct _defines)); + + /* initial definition */ + this->old = old; + this->new = strdup(scanstr(literal)); + this->next = defines; + defines = this; + } + + BEGIN(C); + } +<def>[^";"] { + if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1)) + yyerror("ERROR: define statement parse buffer exceeded"); + memcpy(literal+llen, yytext, yyleng+1); + llen += yyleng; + } <C>{exec}{space}{sql}{space}{include} { BEGIN(incl); } <incl>{space} /* eat the whitespace */ <incl>[^ \t\n]+ { /* got the include file name */ diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 4d6960e406bd3d526c6f0cc3959b9499b5ce10e4..5f67ff48d4236e8fe19f8ea978a38d4eeebea111 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -620,7 +620,7 @@ output_statement(char * stmt, int mode) %type <str> ColId default_expr ColQualifier columnDef ColQualList %type <str> ColConstraint ColConstraintElem default_list NumericOnly FloatOnly %type <str> OptTableElementList OptTableElement TableConstraint -%type <str> ConstraintElem key_actions constraint_list TypeId +%type <str> ConstraintElem key_actions constraint_list %type <str> res_target_list res_target_el res_target_list2 %type <str> res_target_el2 opt_id relation_name database_name %type <str> access_method attr_name class index_name name func_name @@ -636,12 +636,12 @@ output_statement(char * stmt, int mode) %type <str> SelectStmt union_clause select_list SubSelect result %type <str> opt_table opt_union opt_unique sort_clause sortby_list %type <str> sortby OptUseOp opt_inh_star relation_name_list name_list -%type <str> group_clause groupby_list groupby having_clause from_clause +%type <str> group_clause having_clause from_clause c_list %type <str> from_list from_val join_expr join_outer join_spec join_list %type <str> join_using where_clause relation_expr row_op sub_type %type <str> opt_column_list insert_rest InsertStmt OptimizableStmt %type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt -%type <str> NotifyStmt columnElem copy_dirn SubUnion +%type <str> NotifyStmt columnElem copy_dirn SubUnion c_expr %type <str> copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary %type <str> opt_with_copy FetchStmt opt_direction fetch_how_many opt_portal_name %type <str> ClosePortalStmt DestroyStmt VacuumStmt opt_verbose @@ -652,7 +652,7 @@ output_statement(char * stmt, int mode) %type <str> def_elem def_list definition def_name def_type DefineStmt %type <str> opt_instead event event_object OptStmtMulti OptStmtBlock %type <str> OptStmtList RuleStmt opt_column opt_name oper_argtypes -%type <str> MathOp RemoveOperStmt RemoveFuncStmt aggr_argtype +%type <str> MathOp RemoveFuncStmt aggr_argtype %type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt %type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause %type <str> VariableSetStmt var_value zone_value VariableShowStmt @@ -661,7 +661,7 @@ output_statement(char * stmt, int mode) %type <str> user_createuser_clause user_group_list user_group_clause %type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList %type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType -%type <str> TriggerFuncArgs DropTrigStmt TriggerOneEvent TriggerEvents +%type <str> DropTrigStmt TriggerOneEvent TriggerEvents %type <str> TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted %type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg %type <str> ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location @@ -669,7 +669,7 @@ output_statement(char * stmt, int mode) %type <str> GrantStmt privileges operation_commalist operation %type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts -%type <str> indicator ECPGExecute c_expr variable_list dotext +%type <str> indicator ECPGExecute ecpg_expr dotext %type <str> storage_clause opt_initializer vartext c_anything blockstart %type <str> blockend variable_list variable var_anything do_anything %type <str> opt_pointer cvariable ECPGDisconnect dis_name @@ -756,6 +756,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } | VariableShowStmt { output_statement($1, 0); } | VariableResetStmt { output_statement($1, 0); } | ECPGConnect { + fprintf(yyout, "no_auto_trans = %d;\n", no_auto_trans); fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1); whenever_action(0); free($1); @@ -1307,6 +1308,8 @@ constraint_expr: AexprConst { $$ = cat3_str($1, $2, $3); } | constraint_expr LIKE constraint_expr { $$ = cat3_str($1, make1_str("like"), $3); } + | constraint_expr NOT LIKE constraint_expr + { $$ = cat3_str($1, make1_str("not like"), $4); } | constraint_expr AND constraint_expr { $$ = cat3_str($1, make1_str("and"), $3); } | constraint_expr OR constraint_expr @@ -1333,7 +1336,28 @@ constraint_expr: AexprConst { $$ = cat2_str($1, make1_str("is not true")); } | constraint_expr IS NOT FALSE_P { $$ = cat2_str($1, make1_str("is not false")); } - ; + | constraint_expr IN '(' c_list ')' + { $$ = cat4_str($1, make1_str("in ("), $4, make1_str(")")); } + | constraint_expr NOT IN '(' c_list ')' + { $$ = cat4_str($1, make1_str("not in ("), $5, make1_str(")")); } + | constraint_expr BETWEEN c_expr AND c_expr + { $$ = cat5_str($1, make1_str("between"), $3, make1_str("and"), $5); } + | constraint_expr NOT BETWEEN c_expr AND c_expr + { $$ = cat5_str($1, make1_str("not between"), $4, make1_str("and"), $6); } + ; +c_list: c_list ',' c_expr + { + $$ = make3_str($1, make1_str(", "), $3); + } + | c_expr + { + $$ = $1; + } + +c_expr: AexprConst + { + $$ = $1; + } key_match: MATCH FULL { $$ = make1_str("match full"); } | MATCH PARTIAL { $$ = make1_str("match partial"); } @@ -2025,6 +2049,7 @@ RuleStmt: CREATE RULE name AS OptStmtList: NOTHING { $$ = make1_str("nothing"); } | OptimizableStmt { $$ = $1; } | '[' OptStmtBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); } + | '(' OptStmtBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); } ; OptStmtBlock: OptStmtMulti @@ -2480,18 +2505,10 @@ sortby_list: sortby { $$ = $1; } | sortby_list ',' sortby { $$ = cat3_str($1, make1_str(","), $3); } ; -sortby: ColId OptUseOp - { - $$ = cat2_str($1, $2); - } - | ColId '.' ColId OptUseOp +sortby: a_expr OptUseOp { - $$ = cat2_str(make3_str($1, make1_str("."), $3), $4); - } - | Iconst OptUseOp - { - $$ = cat2_str($1, $2); - } + $$ = cat2_str($1, $2); + } ; OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); } @@ -2521,28 +2538,10 @@ name_list: name { $$ = cat3_str($1, make1_str(","), $3); } ; -group_clause: GROUP BY groupby_list { $$ = cat2_str(make1_str("groub by"), $3); } +group_clause: GROUP BY expr_list { $$ = cat2_str(make1_str("groub by"), $3); } | /*EMPTY*/ { $$ = make1_str(""); } ; -groupby_list: groupby { $$ = $1; } - | groupby_list ',' groupby { $$ = cat3_str($1, make1_str(","), $3); } - ; - -groupby: ColId - { - $$ = $1; - } - | ColId '.' ColId - { - $$ = make3_str($1, make1_str(","), $3); - } - | Iconst - { - $$ = $1; - } - ; - having_clause: HAVING a_expr { $$ = cat2_str(make1_str("having"), $2); @@ -3410,11 +3409,11 @@ b_expr: attr opt_indirection { $$ = make1_str(";;"); } ; -opt_indirection: '[' c_expr ']' opt_indirection +opt_indirection: '[' ecpg_expr ']' opt_indirection { $$ = cat4_str(make1_str("["), $2, make1_str("]"), $4); } - | '[' c_expr ':' c_expr ']' opt_indirection + | '[' ecpg_expr ':' ecpg_expr ']' opt_indirection { $$ = cat2_str(cat5_str(make1_str("["), $2, make1_str(":"), $4, make1_str("]")), $6); } @@ -4353,7 +4352,7 @@ action : SQL_CONTINUE { /* some other stuff for ecpg */ -c_expr: attr opt_indirection +ecpg_expr: attr opt_indirection { $$ = cat2_str($1, $2); } @@ -4365,27 +4364,27 @@ c_expr: attr opt_indirection { $$ = $1; } - | '-' c_expr %prec UMINUS + | '-' ecpg_expr %prec UMINUS { $$ = cat2_str(make1_str("-"), $2); } - | a_expr '+' c_expr + | a_expr '+' ecpg_expr { $$ = cat3_str($1, make1_str("+"), $3); } - | a_expr '-' c_expr + | a_expr '-' ecpg_expr { $$ = cat3_str($1, make1_str("-"), $3); } - | a_expr '/' c_expr + | a_expr '/' ecpg_expr { $$ = cat3_str($1, make1_str("/"), $3); } - | a_expr '*' c_expr + | a_expr '*' ecpg_expr { $$ = cat3_str($1, make1_str("*"), $3); } - | a_expr '<' c_expr + | a_expr '<' ecpg_expr { $$ = cat3_str($1, make1_str("<"), $3); } - | a_expr '>' c_expr + | a_expr '>' ecpg_expr { $$ = cat3_str($1, make1_str(">"), $3); } - | a_expr '=' c_expr + | a_expr '=' ecpg_expr { $$ = cat3_str($1, make1_str("="), $3); } - /* | ':' c_expr + /* | ':' ecpg_expr { $$ = cat2_str(make1_str(":"), $2); }*/ - | ';' c_expr + | ';' ecpg_expr { $$ = cat2_str(make1_str(";"), $2); } - | '|' c_expr + | '|' ecpg_expr { $$ = cat2_str(make1_str("|"), $2); } | a_expr TYPECAST Typename { @@ -4397,13 +4396,13 @@ c_expr: attr opt_indirection } | '(' a_expr_or_null ')' { $$ = make3_str(make1_str("("), $2, make1_str(")")); } - | a_expr Op c_expr + | a_expr Op ecpg_expr { $$ = cat3_str($1, $2, $3); } - | a_expr LIKE c_expr + | a_expr LIKE ecpg_expr { $$ = cat3_str($1, make1_str("like"), $3); } - | a_expr NOT LIKE c_expr + | a_expr NOT LIKE ecpg_expr { $$ = cat3_str($1, make1_str("not like"), $4); } - | Op c_expr + | Op ecpg_expr { $$ = cat2_str($1, $2); } | a_expr Op { $$ = cat2_str($1, $2); } @@ -4621,11 +4620,11 @@ c_expr: attr opt_indirection { $$ = make4_str($1, make1_str("=all("), $5, make1_str(")")); } - | a_expr AND c_expr + | a_expr AND ecpg_expr { $$ = cat3_str($1, make1_str("and"), $3); } - | a_expr OR c_expr + | a_expr OR ecpg_expr { $$ = cat3_str($1, make1_str("or"), $3); } - | NOT c_expr + | NOT ecpg_expr { $$ = cat2_str(make1_str("not"), $2); } | civariableonly { $$ = make1_str(";;"); }