From dbdc2e52a0c3569c6237c0b675fc739968f015d9 Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Tue, 15 Jan 2008 10:31:47 +0000 Subject: [PATCH] Re-enabled variables in fetch/move command. --- src/interfaces/ecpg/ChangeLog | 4 + src/interfaces/ecpg/ecpglib/descriptor.c | 4 +- src/interfaces/ecpg/ecpglib/execute.c | 174 +++++++++--------- src/interfaces/ecpg/ecpglib/extern.h | 4 +- src/interfaces/ecpg/preproc/pgc.l | 3 +- src/interfaces/ecpg/preproc/preproc.y | 81 +++----- src/interfaces/ecpg/test/expected/sql-fetch.c | 8 +- src/interfaces/ecpg/test/sql/fetch.pgc | 4 +- 8 files changed, 126 insertions(+), 156 deletions(-) diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 59e22774d7..871630923c 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -2293,6 +2293,10 @@ Mon, 14 Jan 2008 10:42:23 +0100 - Set valid return values even in case of an error to prevent segfaults. + +Tue, 15 Jan 2008 11:26:14 +0100 + + - Re-enabled variables in fetch/move command. - Set pgtypes library version to 3.0. - Set compat library version to 3.0. - Set ecpg library version to 6.0. diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index 0e76e244b1..df9ea29534 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -1,6 +1,6 @@ /* dynamic SQL support routines * - * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.28 2007/11/15 21:14:45 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.29 2008/01/15 10:31:47 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL @@ -529,7 +529,7 @@ ECPGset_desc(int lineno, const char *desc_name, int index,...) for (;;) { enum ECPGdtype itemtype; - const char *tobeinserted = NULL; + char *tobeinserted = NULL; itemtype = va_arg(args, enum ECPGdtype); diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 1b1f47217b..2ccdcbb68f 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.74 2008/01/13 11:53:16 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.75 2008/01/15 10:31:47 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -128,8 +128,8 @@ next_insert(char *text, int pos, bool questionmarks) int i; for (i = p + 1; isdigit(text[i]); i++); - if (!isalpha(text[i]) &&isascii(text[i]) &&text[i] != '_') - /* not dollar delimeted quote */ + if (!isalpha(text[i]) && isascii(text[i]) && text[i] != '_') + /* not dollar delimited quote */ return p; } else if (questionmarks && text[p] == '?') @@ -451,7 +451,7 @@ ecpg_store_result(const PGresult *results, int act_field, bool ecpg_store_input(const int lineno, const bool force_indicator, const struct variable * var, - const char **tobeinserted_p, bool quote) + char **tobeinserted_p, bool quote) { char *mallocedval = NULL; char *newcopy = NULL; @@ -1046,6 +1046,39 @@ free_params(const char **paramValues, int nParams, bool print, int lineno) ecpg_free(paramValues); } + +static bool +insert_tobeinserted(int position, int ph_len, struct statement * stmt, char *tobeinserted) +{ + char *newcopy; + + if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command) + + strlen(tobeinserted) + + 1, stmt->lineno))) + { + ecpg_free(tobeinserted); + return false; + } + + strcpy(newcopy, stmt->command); + strcpy(newcopy + position - 1, tobeinserted); + + /* + * The strange thing in the second argument is the rest of the + * string from the old string + */ + strcat(newcopy, + stmt->command + + position + + ph_len - 1); + + ecpg_free(stmt->command); + stmt->command = newcopy; + + ecpg_free((char *) tobeinserted); + return true; +} + static bool ecpg_execute(struct statement * stmt) { @@ -1069,7 +1102,7 @@ ecpg_execute(struct statement * stmt) var = stmt->inlist; while (var) { - const char *tobeinserted; + char *tobeinserted; int counter = 1; tobeinserted = NULL; @@ -1134,11 +1167,51 @@ ecpg_execute(struct statement * stmt) /* * now tobeinserted points to an area that contains the next parameter + * now find the positin in the string where it belongs + */ + if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0) + { + /* + * We have an argument but we dont have the matched up + * placeholder in the string + */ + ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, + ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, + NULL); + free_params(paramValues, nParams, false, stmt->lineno); + return false; + } + + /* * if var->type=ECPGt_char_variable we have a dynamic cursor we have * to simulate a dynamic cursor because there is no backend * functionality for it */ - if (var->type != ECPGt_char_variable) + if (var->type == ECPGt_char_variable) + { + int ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1"); + + if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted)) + { + free_params(paramValues, nParams, false, stmt->lineno); + return false; + } + tobeinserted = NULL; + } + /* + * if the placeholder is '$0' we have to replace it on the client side + * this is for places we want to support variables at that are not supported in the backend + */ + else if (stmt->command[position] == '0' ) + { + if (!insert_tobeinserted(position, 2, stmt, tobeinserted)) + { + free_params(paramValues, nParams, false, stmt->lineno); + return false; + } + tobeinserted = NULL; + } + else { nParams++; if (!(paramValues = (const char **) ecpg_realloc(paramValues, sizeof(const char *) * nParams, stmt->lineno))) @@ -1149,107 +1222,28 @@ ecpg_execute(struct statement * stmt) paramValues[nParams - 1] = tobeinserted; - if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0) - { - /* - * We have an argument but we dont have the matched up - * placeholder in the string - */ - ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, - ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, - NULL); - free_params(paramValues, nParams, false, stmt->lineno); - return false; - } - /* let's see if this was an old style placeholder */ - if (stmt->command[position - 1] == '?') + if (stmt->command[position] == '?') { /* yes, replace with new style */ int buffersize = sizeof(int) * CHAR_BIT * 10 / 3; /* a rough guess of the * size we need */ - char *buffer, - *newcopy; - if (!(buffer = (char *) ecpg_alloc(buffersize, stmt->lineno))) + if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno))) { free_params(paramValues, nParams, false, stmt->lineno); return false; } - snprintf(buffer, buffersize, "$%d", counter++); + snprintf(tobeinserted, buffersize, "$%d", counter++); - if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command) + strlen(buffer) + 1, stmt->lineno))) + if (!insert_tobeinserted(position, 2, stmt, tobeinserted)) { free_params(paramValues, nParams, false, stmt->lineno); - ecpg_free(buffer); return false; } - - strcpy(newcopy, stmt->command); - - /* set positional parameter */ - strcpy(newcopy + position - 1, buffer); - - /* - * The strange thing in the second argument is the rest of the - * string from the old string - */ - strcat(newcopy, - stmt->command - + position + 1); - ecpg_free(buffer); - ecpg_free(stmt->command); - stmt->command = newcopy; - } - } - else - { - char *newcopy; - - if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command) - + strlen(tobeinserted) - + 1, stmt->lineno))) - { - free_params(paramValues, nParams, false, stmt->lineno); - return false; - } - - strcpy(newcopy, stmt->command); - if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0) - { - /* - * We have an argument but we dont have the matched up string - * in the string - */ - ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, - ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, - NULL); - free_params(paramValues, nParams, false, stmt->lineno); - ecpg_free(newcopy); - return false; + tobeinserted = NULL; } - else - { - int ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1"); - - strcpy(newcopy + position - 1, tobeinserted); - - /* - * The strange thing in the second argument is the rest of the - * string from the old string - */ - strcat(newcopy, - stmt->command - + position - + ph_len - 1); - } - - ecpg_free(stmt->command); - stmt->command = newcopy; - - ecpg_free((char *) tobeinserted); - tobeinserted = NULL; } if (desc_counter == 0) diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h index e366c9ce44..975904eb77 100644 --- a/src/interfaces/ecpg/ecpglib/extern.h +++ b/src/interfaces/ecpg/ecpglib/extern.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.32 2007/11/15 21:14:45 momjian Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.33 2008/01/15 10:31:47 meskes Exp $ */ #ifndef _ECPG_LIB_EXTERN_H #define _ECPG_LIB_EXTERN_H @@ -138,7 +138,7 @@ struct descriptor *ecpg_find_desc(int line, const char *name); bool ecpg_store_result(const PGresult *results, int act_field, const struct statement * stmt, struct variable * var); -bool ecpg_store_input(const int, const bool, const struct variable *, const char **, bool); +bool ecpg_store_input(const int, const bool, const struct variable *, char **, bool); bool ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE); void ecpg_raise(int line, int code, const char *sqlstate, const char *str); diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 1bdfc7e0fa..e5bd28be92 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.158 2008/01/11 15:19:16 meskes Exp $ + * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.159 2008/01/15 10:31:47 meskes Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,6 @@ extern YYSTYPE yylval; static int xcdepth = 0; /* depth of nesting in slash-star comments */ static char *dolqstart; /* current $foo$ quote start string */ -static bool escape_string_warning; static YY_BUFFER_STATE scanbufhandle; static char *scanbuf; diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 563a891bc6..9bcf994480 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.358 2008/01/14 09:43:42 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.359 2008/01/15 10:31:47 meskes Exp $ */ /* Copyright comment */ %{ @@ -566,7 +566,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu %type join_outer where_clause relation_expr sub_type arg_class %type opt_column_list insert_rest InsertStmt param_name %type columnList DeleteStmt UpdateStmt DeclareCursorStmt -%type NotifyStmt columnElem UnlistenStmt TableElement +%type NotifyStmt columnElem UnlistenStmt TableElement fetch_count %type copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary %type FetchStmt from_in CreateOpClassStmt returning_clause %type ClosePortalStmt DropStmt VacuumStmt AnalyzeStmt opt_verbose @@ -2337,61 +2337,32 @@ FetchStmt: FETCH fetch_direction from_in name ecpg_into { $$ = cat2_str(make_str("move"), $2); } ; -fetch_direction: NEXT { $$ = make_str("next"); } - | PRIOR { $$ = make_str("prior"); } - | FIRST_P { $$ = make_str("first"); } - | LAST_P { $$ = make_str("last"); } - | ABSOLUTE_P IntConst { - if ($2[1] == '$') - { - mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n"); - $$ = make_str("absolute"); - } - else - $$ = cat2_str(make_str("absolute"), $2); - } - | RELATIVE_P IntConst { - if ($2[1] == '$') - { - mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n"); - $$ = make_str("relative"); - } - else - $$ = cat2_str(make_str("relative"), $2); +fetch_direction: NEXT { $$ = make_str("next"); } + | PRIOR { $$ = make_str("prior"); } + | FIRST_P { $$ = make_str("first"); } + | LAST_P { $$ = make_str("last"); } + | ABSOLUTE_P fetch_count { $$ = cat2_str(make_str("absolute"), $2); } + | RELATIVE_P fetch_count { $$ = cat2_str(make_str("relative"), $2); } + | fetch_count { $$ = $1; } + | ALL { $$ = make_str("all"); } + | FORWARD { $$ = make_str("forward"); } + | FORWARD fetch_count { $$ = cat2_str(make_str("forward"), $2); } + | FORWARD ALL { $$ = make_str("forward all"); } + | BACKWARD { $$ = make_str("backward"); } + | BACKWARD fetch_count { $$ = cat2_str(make_str("backward"), $2); } + | BACKWARD ALL { $$ = make_str("backward all"); } + ; + +fetch_count: IntConst { + if ($1[1] == '$') + { + /* a variable here has to be replaced on the client side, thus we have to use '?' here */ + $$ = make_str("$0"); + free($1); } - | IntConst { - if ($1[1] == '$') - { - mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variablei, ignoring it.\n"); - $$ = EMPTY; - } - else + else $$ = $1; - } - | ALL { $$ = make_str("all"); } - | FORWARD { $$ = make_str("forward"); } - | FORWARD IntConst { - if ($2[1] == '$') - { - mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n"); - $$ = make_str("forward"); - } - else - $$ = cat2_str(make_str("forward"), $2); - } - | FORWARD ALL { $$ = make_str("forward all"); } - | BACKWARD { $$ = make_str("backward"); } - | BACKWARD IntConst { - if ($2[1] == '$') - { - mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n"); - $$ = make_str("backward"); - } - else - $$ = cat2_str(make_str("backward"), $2); - } - | BACKWARD ALL { $$ = make_str("backward all"); } - ; + } from_in: IN_P { $$ = make_str("in"); } | FROM { $$ = make_str("from"); } diff --git a/src/interfaces/ecpg/test/expected/sql-fetch.c b/src/interfaces/ecpg/test/expected/sql-fetch.c index dd04d6f14f..54d69e47ab 100644 --- a/src/interfaces/ecpg/test/expected/sql-fetch.c +++ b/src/interfaces/ecpg/test/expected/sql-fetch.c @@ -26,13 +26,13 @@ int main(int argc, char* argv[]) { /* exec sql begin declare section */ - + #line 9 "fetch.pgc" char str [ 25 ] ; #line 10 "fetch.pgc" - int i ; + int i , count = 1 ; /* exec sql end declare section */ #line 11 "fetch.pgc" @@ -146,7 +146,9 @@ if (sqlca.sqlcode < 0) sqlprint();} #line 37 "fetch.pgc" - { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 1 in C", ECPGt_EOIT, + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch $0 in C", + ECPGt_int,&(count),(long)1,(long)1,sizeof(int), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_int,&(i),(long)1,(long)1,sizeof(int), ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_char,(str),(long)25,(long)1,(25)*sizeof(char), diff --git a/src/interfaces/ecpg/test/sql/fetch.pgc b/src/interfaces/ecpg/test/sql/fetch.pgc index a65d393748..340b888048 100644 --- a/src/interfaces/ecpg/test/sql/fetch.pgc +++ b/src/interfaces/ecpg/test/sql/fetch.pgc @@ -7,7 +7,7 @@ EXEC SQL INCLUDE ../regression; int main(int argc, char* argv[]) { EXEC SQL BEGIN DECLARE SECTION; char str[25]; - int i; + int i, count=1; EXEC SQL END DECLARE SECTION; ECPGdebug(1, stderr); @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) { EXEC SQL WHENEVER NOT FOUND CONTINUE; EXEC SQL MOVE BACKWARD 2 IN C; - EXEC SQL FETCH 1 IN C INTO :i, :str; + EXEC SQL FETCH :count IN C INTO :i, :str; printf("%d: %s\n", i, str); EXEC SQL CLOSE C; -- 2.40.0