From 5bc75618e443b92ffb9266915fa39f5e916e4661 Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Fri, 22 Jan 2010 14:13:03 +0000 Subject: [PATCH] Applied patch by Boszormenyi Zoltan to fix problem in auto-prepare mode if the connection is closed and re-opened and the previously prepared query is issued again. --- src/interfaces/ecpg/ecpglib/execute.c | 5 +- src/interfaces/ecpg/ecpglib/prepare.c | 70 +++++--- .../ecpg/test/expected/preproc-autoprep.c | 7 +- .../test/expected/preproc-autoprep.stderr | 160 ++++++++++++++++++ .../test/expected/preproc-autoprep.stdout | 9 + src/interfaces/ecpg/test/preproc/autoprep.pgc | 7 +- 6 files changed, 232 insertions(+), 26 deletions(-) diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index acb1e4bfdd..ec2ca8915e 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.88 2010/01/05 16:38:23 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.89 2010/01/22 14:13:03 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -1753,7 +1753,10 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char stmt->command = ecpg_strdup(command, lineno); } else + { ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command); + return (false); + } } stmt->connection = con; diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c index 6be062f4d8..a9eef75460 100644 --- a/src/interfaces/ecpg/ecpglib/prepare.c +++ b/src/interfaces/ecpg/ecpglib/prepare.c @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.34 2010/01/15 10:44:34 meskes Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.35 2010/01/22 14:13:03 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -99,27 +99,13 @@ replace_variables(char **text, int lineno) return true; } -/* handle the EXEC SQL PREPARE statement */ -/* questionmarks is not needed but remians in there for the time being to not change the API */ -bool -ECPGprepare(int lineno, const char *connection_name, const bool questionmarks, const char *name, const char *variable) +static bool +prepare_common(int lineno, struct connection *con, const bool questionmarks, const char *name, const char *variable) { - struct connection *con; struct statement *stmt; - struct prepared_statement *this, - *prev; + struct prepared_statement *this; PGresult *query; - con = ecpg_get_connection(connection_name); - - if (!ecpg_init(con, connection_name, lineno)) - return false; - - /* check if we already have prepared this statement */ - this = ecpg_find_prepared_statement(name, con, &prev); - if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this)) - return false; - /* allocate new statement */ this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno); if (!this) @@ -169,6 +155,28 @@ ECPGprepare(int lineno, const char *connection_name, const bool questionmarks, c return true; } +/* handle the EXEC SQL PREPARE statement */ +/* questionmarks is not needed but remians in there for the time being to not change the API */ +bool +ECPGprepare(int lineno, const char *connection_name, const bool questionmarks, const char *name, const char *variable) +{ + struct connection *con; + struct prepared_statement *this, + *prev; + + con = ecpg_get_connection(connection_name); + + if (!ecpg_init(con, connection_name, lineno)) + return false; + + /* check if we already have prepared this statement */ + this = ecpg_find_prepared_statement(name, con, &prev); + if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this)) + return false; + + return prepare_common(lineno, con, questionmarks, name, variable); +} + struct prepared_statement * ecpg_find_prepared_statement(const char *name, struct connection * con, struct prepared_statement ** prev_) @@ -465,21 +473,37 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, cha /* if not found - add the statement to the cache */ if (entNo) { + char *stmtID; + struct connection *con; + struct prepared_statement *prep; + ecpg_log("ecpg_auto_prepare on line %d: statement found in cache; entry %d\n", lineno, entNo); - *name = ecpg_strdup(stmtCacheEntries[entNo].stmtID, lineno); + + stmtID = stmtCacheEntries[entNo].stmtID; + + con = ecpg_get_connection(connection_name); + prep = ecpg_find_prepared_statement(stmtID, con, NULL); + /* This prepared name doesn't exist on this connection. */ + if (!prep && !prepare_common(lineno, con, 0, stmtID, query)) + return (false); + + *name = ecpg_strdup(stmtID, lineno); } else { + char stmtID[STMTID_SIZE]; + ecpg_log("ecpg_auto_prepare on line %d: statement not in cache; inserting\n", lineno); /* generate a statement ID */ - *name = (char *) ecpg_alloc(STMTID_SIZE, lineno); - sprintf(*name, "ecpg%d", nextStmtID++); + sprintf(stmtID, "ecpg%d", nextStmtID++); - if (!ECPGprepare(lineno, connection_name, 0, ecpg_strdup(*name, lineno), query)) + if (!ECPGprepare(lineno, connection_name, 0, stmtID, query)) return (false); - if (AddStmtToCache(lineno, *name, connection_name, compat, query) < 0) + if (AddStmtToCache(lineno, stmtID, connection_name, compat, query) < 0) return (false); + + *name = ecpg_strdup(stmtID, lineno); } /* increase usage counter */ diff --git a/src/interfaces/ecpg/test/expected/preproc-autoprep.c b/src/interfaces/ecpg/test/expected/preproc-autoprep.c index 039ed43758..430d071000 100644 --- a/src/interfaces/ecpg/test/expected/preproc-autoprep.c +++ b/src/interfaces/ecpg/test/expected/preproc-autoprep.c @@ -23,7 +23,7 @@ #line 6 "autoprep.pgc" -int main() { +static void test(void) { /* exec sql begin declare section */ @@ -246,6 +246,11 @@ if (sqlca.sqlwarn[0] == 'W') sqlprint(); if (sqlca.sqlcode < 0) sqlprint();} #line 64 "autoprep.pgc" +} + +int main() { + test(); + test(); /* retry */ return 0; } diff --git a/src/interfaces/ecpg/test/expected/preproc-autoprep.stderr b/src/interfaces/ecpg/test/expected/preproc-autoprep.stderr index 1bed36a7e2..307ba42116 100644 --- a/src/interfaces/ecpg/test/expected/preproc-autoprep.stderr +++ b/src/interfaces/ecpg/test/expected/preproc-autoprep.stderr @@ -158,3 +158,163 @@ [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_finish: connection regress1 closed [NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdebug: set to 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGconnect: opening database regress1 on port +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 21: query: create table T ( Item1 int , Item2 int ); with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 21: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 21: OK: CREATE TABLE +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_auto_prepare on line 23: statement found in cache; entry 15328 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGprepare on line 23: name ecpg1; query: "insert into T values ( 1 , null )" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 23: query: insert into T values ( 1 , null ); with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 23: using PQexecPrepared for "insert into T values ( 1 , null )" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 23: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_auto_prepare on line 24: statement found in cache; entry 1640 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGprepare on line 24: name ecpg2; query: "insert into T values ( 1 , $1 )" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 24: query: insert into T values ( 1 , $1 ); with 1 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 24: using PQexecPrepared for "insert into T values ( 1 , $1 )" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: free_params on line 24: parameter 1 = 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 24: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_auto_prepare on line 26: statement found in cache; entry 1640 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 26: query: insert into T values ( 1 , $1 ); with 1 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 26: using PQexecPrepared for "insert into T values ( 1 , $1 )" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: free_params on line 26: parameter 1 = 2 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 26: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGprepare on line 27: name i; query: " insert into T values ( 1 , 2 ) " +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 28: query: insert into T values ( 1 , 2 ) ; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 28: using PQexecPrepared for " insert into T values ( 1 , 2 ) " +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 28: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_auto_prepare on line 30: statement found in cache; entry 13056 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGprepare on line 30: name ecpg3; query: "select Item2 from T order by Item2 nulls last" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: query: select Item2 from T order by Item2 nulls last; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: using PQexecPrepared for "select Item2 from T order by Item2 nulls last" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: correctly got 4 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 30: RESULT: 1 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 30: RESULT: offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 37: query: declare C cursor for select Item1 from T; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 37: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 37: OK: DECLARE CURSOR +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 39: query: fetch 1 in C; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 39: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 39: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 39: RESULT: 1 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 42: query: close C; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 42: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 42: OK: CLOSE CURSOR +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGprepare on line 44: name stmt1; query: "SELECT item2 FROM T ORDER BY item2 NULLS LAST" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 48: query: declare cur1 cursor for SELECT item2 FROM T ORDER BY item2 NULLS LAST; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 48: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 48: OK: DECLARE CURSOR +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 55: RESULT: 1 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_get_data on line 55: RESULT: offset: -1; array: yes +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 55: correctly got 0 tuples with 1 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: raising sqlcode 100 on line 55: no data found on line 55 +[NO_PID]: sqlca: code: 100, state: 02000 +[NO_PID]: ecpg_execute on line 60: query: close cur1; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 60: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 60: OK: CLOSE CURSOR +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 62: query: drop table T; with 0 parameter(s) on connection regress1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 62: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 62: OK: DROP TABLE +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdeallocate on line 0: name stmt1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdeallocate on line 0: name ecpg3 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdeallocate on line 0: name i +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdeallocate on line 0: name ecpg2 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGdeallocate on line 0: name ecpg1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_finish: connection regress1 closed +[NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/expected/preproc-autoprep.stdout b/src/interfaces/ecpg/test/expected/preproc-autoprep.stdout index ae943aac60..16a3263c44 100644 --- a/src/interfaces/ecpg/test/expected/preproc-autoprep.stdout +++ b/src/interfaces/ecpg/test/expected/preproc-autoprep.stdout @@ -7,3 +7,12 @@ item[0] = 1 item[1] = 2 item[2] = 2 item[3] = -1 +item[0] = 1 +item[1] = 2 +item[2] = 2 +item[3] = -1 +i = 1 +item[0] = 1 +item[1] = 2 +item[2] = 2 +item[3] = -1 diff --git a/src/interfaces/ecpg/test/preproc/autoprep.pgc b/src/interfaces/ecpg/test/preproc/autoprep.pgc index d774038558..eeeb879d10 100644 --- a/src/interfaces/ecpg/test/preproc/autoprep.pgc +++ b/src/interfaces/ecpg/test/preproc/autoprep.pgc @@ -5,7 +5,7 @@ /* test automatic prepare for all statements */ EXEC SQL INCLUDE ../regression; -int main() { +static void test(void) { EXEC SQL BEGIN DECLARE SECTION; int item[4], ind[4], i = 1; int item1, ind1; @@ -62,6 +62,11 @@ int main() { EXEC SQL DROP TABLE T; EXEC SQL DISCONNECT ALL; +} + +int main() { + test(); + test(); /* retry */ return 0; }