--- pool_proto_modules.h 2010-08-26 18:23:06.000000000 +0900 +++ pool_proto_modules.h 2010-09-27 11:01:57.000000000 +0900 @@ -1,7 +1,7 @@ /* -*-pgsql-c-*- */ /* * - * $Header: /cvsroot/pgpool/pgpool-II/pool_proto_modules.h,v 1.23 2010/08/26 09:23:06 kitagawa Exp $ + * $Header: /cvsroot/pgpool/pgpool-II/pool_proto_modules.h,v 1.24 2010/09/27 02:01:57 kitagawa Exp $ * * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii @@ -35,6 +35,7 @@ #include "pool_session_context.h" #define SPECIFIED_ERROR 1 +#define POOL_DUMMY_QUERY "DELETE FROM foo WHERE col = 'pgpool: unable to parse the query'" #define POOL_ERROR_QUERY "send invalid query from pgpool to abort transaction" extern char *copy_table; /* copy table name */ --- pool_proto_modules.c 2010-08-30 12:55:58.000000000 +0900 +++ pool_proto_modules.c 2010-09-29 15:02:07.000000000 +0900 @@ -1,6 +1,6 @@ /* -*-pgsql-c-*- */ /* - * $Header: /cvsroot/pgpool/pgpool-II/pool_proto_modules.c,v 1.85 2010/08/30 03:55:58 kitagawa Exp $ + * $Header: /cvsroot/pgpool/pgpool-II/pool_proto_modules.c,v 1.86 2010/09/27 02:01:57 kitagawa Exp $ * * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii @@ -164,10 +164,8 @@ * The command will be sent to all backends in replication mode * or master/primary in master/slave mode. */ - char *p = "DELETE FROM foo WHERE col = 'pgpool: unable to parse the query'"; - pool_log("SimpleQuery: Unable to parse the query: %s", contents); - parse_tree_list = raw_parser(p); + parse_tree_list = raw_parser(POOL_DUMMY_QUERY); } if (parse_tree_list != NIL) @@ -615,13 +613,25 @@ old_context = pool_memory; pool_memory = query_context->memory_context; + /* parse SQL string */ parse_tree_list = raw_parser(stmt); + if (parse_tree_list == NIL) { - /* free_parser(); */ - ; + /* + * Unable to parse the query. Probably syntax error or the + * query is too new and our parser cannot understand. Treat as + * if it were an DELETE command. Note that the DELETE command + * does not execute, instead the original query will be sent + * to backends, which may or may not cause an actual syntax errors. + * The command will be sent to all backends in replication mode + * or master/primary in master/slave mode. + */ + pool_log("Parse: Unable to parse the query: %s", contents); + parse_tree_list = raw_parser(POOL_DUMMY_QUERY); } - else + + if (parse_tree_list != NIL) { /* Save last query string for logging purpose */ snprintf(query_string_buffer, sizeof(query_string_buffer), "Parse: %s", stmt); @@ -968,6 +978,7 @@ return POOL_CONTINUE; } + POOL_STATUS Close(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, int len, char *contents) { @@ -995,6 +1006,7 @@ } session_context->pending_pstmt = pstmt; + query_context = pstmt->qctxt; } /* Portal */ else if (*contents == 'P') @@ -1007,6 +1019,7 @@ } session_context->pending_portal = portal; + query_context = portal->qctxt; } else { @@ -1014,15 +1027,14 @@ return POOL_END; } - query_context = pstmt->qctxt; if (query_context == NULL) { pool_error("Close: cannot get query context"); return POOL_END; } - pool_where_to_send(query_context, query_context->original_query, - query_context->parse_tree); + session_context->query_context = query_context; + /* pool_where_to_send(query_context, query_context->original_query, query_context->parse_tree); */ pool_debug("Close: waiting for master completing the query"); if (pool_send_and_wait(query_context, contents, len, 1, MASTER_NODE_ID, "C") Index: pool_session_context.h =================================================================== RCS file: /cvsroot/pgpool/pgpool-II/pool_session_context.h,v retrieving revision 1.19 diff -u -r1.19 pool_session_context.h --- pool_session_context.h 19 Aug 2010 09:25:40 -0000 1.19 +++ pool_session_context.h 6 Oct 2010 13:40:38 -0000 @@ -61,6 +61,7 @@ char *name; /* portal name */ int num_tsparams; PreparedStatement *pstmt; + POOL_QUERY_CONTEXT *qctxt; } Portal; /* Index: pool_session_context.c =================================================================== RCS file: /cvsroot/pgpool/pgpool-II/pool_session_context.c,v retrieving revision 1.23 diff -u -r1.23 pool_session_context.c --- pool_session_context.c 17 Aug 2010 09:23:18 -0000 1.23 +++ pool_session_context.c 6 Oct 2010 13:40:39 -0000 @@ -33,6 +33,8 @@ static void init_prepared_statement_list(void); static void init_portal_list(void); +static bool can_prepared_statement_destroy(POOL_QUERY_CONTEXT *qc); +static bool can_portal_destroy(POOL_QUERY_CONTEXT *qc); /* * Initialize per session context @@ -368,6 +370,8 @@ { if (strcmp(plist->portals[i]->name, name) == 0) { + if (can_portal_destroy(plist->portals[i]->qctxt)) + pool_query_context_destroy(plist->portals[i]->qctxt); pool_memory_free(session_context->memory_context, plist->portals[i]); break; } @@ -389,6 +393,7 @@ * Remove portals by prepared statement name * prepared statement : portal = 1 : N */ +#ifdef NOT_USED static void pool_remove_portal_by_pstmt_name(const char *name) { int i; @@ -413,6 +418,7 @@ pool_remove_portal_by_portal_name(plist->portals[i]->name); } } +#endif /* * Remove a prepared statement by prepared statement name @@ -451,7 +457,8 @@ { if (strcmp(pslist->pstmts[i]->name, name) == 0) { - pool_query_context_destroy(pslist->pstmts[i]->qctxt); + if (can_prepared_statement_destroy(pslist->pstmts[i]->qctxt)) + pool_query_context_destroy(pslist->pstmts[i]->qctxt); pool_memory_free(session_context->memory_context, pslist->pstmts[i]); break; } @@ -472,7 +479,11 @@ } pslist->size--; - pool_remove_portal_by_pstmt_name(name); + /* + * prepared statements and portals are closed separately + * by a frontend. + */ + /* pool_remove_portal_by_pstmt_name(name); */ if (in_progress) pool_set_query_in_progress(); @@ -639,6 +650,7 @@ portal->name = pool_memory_strdup(session_context->memory_context, name); portal->num_tsparams = num_tsparams; portal->pstmt = pstmt; + portal->qctxt = pstmt->qctxt; return portal; } @@ -1137,3 +1149,41 @@ exit(1); } } + +static bool can_prepared_statement_destroy(POOL_QUERY_CONTEXT *qc) +{ + int i; + PortalList *plist; + + plist = &session_context->portal_list; + + for (i = 0; i < plist->size; i++) + { + if (plist->portals[i]->qctxt == qc) + { + pool_debug("can_prepared_statement_destroy: query context is still used."); + return false; + } + } + + return true; +} + +static bool can_portal_destroy(POOL_QUERY_CONTEXT *qc) +{ + int i; + PreparedStatementList *pslist; + + pslist = &session_context->pstmt_list; + + for (i = 0; i < pslist->size; i++) + { + if (pslist->pstmts[i]->qctxt == qc) + { + pool_debug("can_portal_destroy: query context is still used."); + return false; + } + } + + return true; +}