diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 1c610f3dd5..f7a68f69f1 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -1,5 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.8 2009/11/11 20:31:26 alvherre Exp $ */ - +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.9 2009/11/26 15:06:47 meskes Exp $ */ ECPG: stmtClosePortalStmt block { if (INFORMIX_MODE) @@ -213,18 +212,36 @@ ECPG: var_valueNumericOnly addon } ECPG: fetch_argscursor_name addon add_additional_variables($1, false); + if ($1[0] == ':') + { + free($1); + $1 = make_str("$0"); + } ECPG: fetch_argsfrom_incursor_name addon add_additional_variables($2, false); + if ($2[0] == ':') + { + free($2); + $2 = make_str("$0"); + } ECPG: fetch_argsNEXTopt_from_incursor_name addon ECPG: fetch_argsPRIORopt_from_incursor_name addon ECPG: fetch_argsFIRST_Popt_from_incursor_name addon ECPG: fetch_argsLAST_Popt_from_incursor_name addon ECPG: fetch_argsALLopt_from_incursor_name addon -ECPG: fetch_argsFORWARDopt_from_incursor_name addon -ECPG: fetch_argsBACKWARDopt_from_incursor_name addon add_additional_variables($3, false); + if ($3[0] == ':') + { + free($3); + $3 = make_str("$0"); + } ECPG: fetch_argsSignedIconstopt_from_incursor_name addon add_additional_variables($3, false); + if ($3[0] == ':') + { + free($3); + $3 = make_str("$0"); + } if ($1[0] == '$') { free($1); @@ -233,16 +250,35 @@ ECPG: fetch_argsSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon add_additional_variables($4, false); + if ($4[0] == ':') + { + free($4); + $4 = make_str("$0"); + } ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon add_additional_variables($4, false); + if ($4[0] == ':') + { + free($4); + $4 = make_str("$0"); + } if ($2[0] == '$') { free($2); $2 = make_str("$0"); } +ECPG: cursor_namename rule + | char_civar + { + char *curname = mm_alloc(strlen($1) + 2); + sprintf(curname, ":%s", $1); + free($1); + $1 = curname; + $$ = $1; + } ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block { $$.name = $2; @@ -260,6 +296,7 @@ ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block { struct cursor *ptr, *this; + char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2); char *comment; for (ptr = cur; ptr != NULL; ptr = ptr->next) @@ -274,7 +311,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt this->name = $2; this->connection = connection; this->opened = false; - this->command = cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7); + this->command = cat_str(7, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for"), $7); this->argsinsert = argsinsert; this->argsresult = argsresult; argsinsert = argsresult = NULL; @@ -294,6 +331,11 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt else $$ = comment; } +ECPG: ClosePortalStmtCLOSEcursor_name block + { + char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; + $$ = cat2_str(make_str("close"), cursor_marker); + } ECPG: opt_hold block { if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true) @@ -363,6 +405,54 @@ ECPG: FetchStmtMOVEfetch_args rule { $$ = cat2_str(make_str("fetch"), $2); } + | FETCH FORWARD cursor_name opt_ecpg_into + { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; + add_additional_variables($3, false); + $$ = cat_str(2, make_str("fetch forward"), cursor_marker); + } + | FETCH FORWARD from_in cursor_name opt_ecpg_into + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); + } + | FETCH BACKWARD cursor_name opt_ecpg_into + { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; + add_additional_variables($3, false); + $$ = cat_str(2, make_str("fetch backward"), cursor_marker); + } + | FETCH BACKWARD from_in cursor_name opt_ecpg_into + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(2, make_str("fetch backward from"), cursor_marker); + } + | MOVE FORWARD cursor_name + { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; + add_additional_variables($3, false); + $$ = cat_str(2, make_str("move forward"), cursor_marker); + } + | MOVE FORWARD from_in cursor_name + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(2, make_str("move forward from"), cursor_marker); + } + | MOVE BACKWARD cursor_name + { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; + add_additional_variables($3, false); + $$ = cat_str(2, make_str("move backward"), cursor_marker); + } + | MOVE BACKWARD from_in cursor_name + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(2, make_str("move backward from"), cursor_marker); + } ECPG: select_limitLIMITselect_limit_value','select_offset_value block { mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to server"); diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index c18844a208..e5f50c915e 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.15 2009/11/21 05:44:05 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.16 2009/11/26 15:06:47 meskes Exp $ */ statements: /*EMPTY*/ | statements statement @@ -278,6 +278,7 @@ prepared_name: name { ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name { struct cursor *ptr, *this; + char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2); struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); const char *con = connection ? connection : "NULL"; @@ -294,7 +295,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared this->next = cur; this->name = $2; this->connection = connection; - this->command = cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1")); + this->command = cat_str(6, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for $1")); this->argsresult = NULL; thisquery->type = &ecpg_query; @@ -304,6 +305,12 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); this->argsinsert = NULL; + if ($2[0] == ':') + { + struct variable *var = find_variable($2 + 1); + remove_variable_from_list(&argsinsert, var); + add_variable_to_head(&(this->argsinsert), var, &no_indicator); + } add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); cur = this; @@ -947,7 +954,13 @@ ECPGFree: SQL_FREE name { $$ = $2; } /* * open is an open cursor, at the moment this has to be removed */ -ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using { $$ = $2; }; +ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using + { + if ($2[0] == ':') + remove_variable_from_list(&argsinsert, find_variable($2 + 1)); + $$ = $2; + } + ; opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } | ecpg_using { $$ = $1; } @@ -1567,6 +1580,17 @@ civarind: cvariable indicator } ; +char_civar: char_variable + { + char *ptr = strstr($1, ".arr"); + + if (ptr) /* varchar, we need the struct name here, not the struct element */ + *ptr = '\0'; + add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); + $$ = $1; + } + ; + civar: cvariable { add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); @@ -1782,6 +1806,10 @@ ecpg_into: INTO into_list { $$ = EMPTY; } | into_descriptor { $$ = $1; } ; +opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } + | ecpg_into { $$ = $1; } + ; + %% void base_yyerror(const char *error) diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type index 7ca5591827..58f410d80d 100644 --- a/src/interfaces/ecpg/preproc/ecpg.type +++ b/src/interfaces/ecpg/preproc/ecpg.type @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.3 2009/11/21 05:44:05 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.4 2009/11/26 15:06:47 meskes Exp $ */ %type ECPGAllocateDescr %type ECPGCKeywords %type ECPGColId @@ -42,6 +42,7 @@ %type c_term %type c_thing %type char_variable +%type char_civar %type civar %type civarind %type ColId @@ -75,6 +76,7 @@ %type opt_bit_field %type opt_connection_name %type opt_database_name +%type opt_ecpg_into %type opt_ecpg_using %type opt_initializer %type opt_options diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h index 9643ab2406..8b740f1744 100644 --- a/src/interfaces/ecpg/preproc/extern.h +++ b/src/interfaces/ecpg/preproc/extern.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/extern.h,v 1.75 2009/09/08 04:25:00 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/extern.h,v 1.76 2009/11/26 15:06:47 meskes Exp $ */ #ifndef _ECPG_PREPROC_EXTERN_H #define _ECPG_PREPROC_EXTERN_H @@ -90,6 +90,7 @@ extern struct descriptor *lookup_descriptor(char *, char *); extern struct variable *descriptor_variable(const char *name, int input); extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *); extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); +extern void remove_variable_from_list(struct arguments ** list, struct variable * var); extern void dump_variables(struct arguments *, int); extern struct typedefs *get_typedef(char *); extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool); diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index 8d2bc450b1..e0615d577c 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/parse.pl,v 1.5 2009/11/21 05:44:05 tgl Exp $ +# $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/parse.pl,v 1.6 2009/11/26 15:06:47 meskes Exp $ # parser generater for ecpg # call with backend parser as stdin # @@ -74,7 +74,8 @@ $replace_line{'reserved_keywordTO'} = 'ignore'; $replace_line{'reserved_keywordUNION'} = 'ignore'; # some other production rules have to be ignored or replaced -$replace_line{'fetch_direction'} = 'ignore'; +$replace_line{'fetch_argsFORWARDopt_from_incursor_name'} = 'ignore'; +$replace_line{'fetch_argsBACKWARDopt_from_incursor_name'} = 'ignore'; $replace_line{"opt_array_boundsopt_array_bounds'['Iconst']'"} = 'ignore'; $replace_line{'VariableShowStmtSHOWvar_name'} = 'SHOW var_name ecpg_into'; $replace_line{'VariableShowStmtSHOWTIMEZONE'} = 'SHOW TIME ZONE ecpg_into'; diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index 9d29f340b6..ce3b950621 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/variable.c,v 1.50 2009/08/07 10:51:20 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/variable.c,v 1.51 2009/11/26 15:06:47 meskes Exp $ */ #include "postgres_fe.h" @@ -401,6 +401,30 @@ add_variable_to_tail(struct arguments ** list, struct variable * var, struct var *list = new; } +void +remove_variable_from_list(struct arguments ** list, struct variable * var) +{ + struct arguments *p, *prev = NULL; + bool found = false; + + for (p = *list; p; p = p->next) + { + if (p->variable == var) + { + found = true; + break; + } + prev = p; + } + if (found) + { + if (prev) + prev->next = p->next; + else + *list = p->next; + } +} + /* 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. diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule index 14fcd41a46..a9245be1fd 100644 --- a/src/interfaces/ecpg/test/ecpg_schedule +++ b/src/interfaces/ecpg/test/ecpg_schedule @@ -16,6 +16,7 @@ test: pgtypeslib/num_test2 test: preproc/array_of_struct test: preproc/autoprep test: preproc/comment +test: preproc/cursor test: preproc/define test: preproc/init test: preproc/strings diff --git a/src/interfaces/ecpg/test/ecpg_schedule_tcp b/src/interfaces/ecpg/test/ecpg_schedule_tcp index 8143473244..917c590c8c 100644 --- a/src/interfaces/ecpg/test/ecpg_schedule_tcp +++ b/src/interfaces/ecpg/test/ecpg_schedule_tcp @@ -16,6 +16,7 @@ test: pgtypeslib/num_test2 test: preproc/array_of_struct test: preproc/autoprep test: preproc/comment +test: preproc/cursor test: preproc/define test: preproc/init test: preproc/strings diff --git a/src/interfaces/ecpg/test/preproc/Makefile b/src/interfaces/ecpg/test/preproc/Makefile index 94b6779a41..ed3243214e 100644 --- a/src/interfaces/ecpg/test/preproc/Makefile +++ b/src/interfaces/ecpg/test/preproc/Makefile @@ -7,6 +7,7 @@ include $(top_srcdir)/$(subdir)/../Makefile.regress TESTS = array_of_struct array_of_struct.c \ autoprep autoprep.c \ comment comment.c \ + cursor cursor.c \ define define.c \ init init.c \ strings strings.c \