pgpool2.git / summary / log / commit / refs

commit    26b773d5d14bfc3a2b545dd40699bef2cbd5172c
Author:   Tatsuo Ishii <ishii@postgresql.org>
Date:     Mon May 28 08:02:30 2012 +0000

    Fix the case when unable-to-parse query is issued and on memory query
    cache is enabled. Problem is, when such a query arrives, pgpool
    replaces it with a dummy query which uses non-existent table. And
    pool_table_name_to_oid() tries to convert non-existent table to oid,
    and causes error. Using pgpool_regclass() will supress the error but
    the relcache module will cache oid 0 in this case and continues to
    return the cache entry even when the table is created
    afterward. Solution is add new interface to control relcache not to
    cache if register_func returns 0. For this purpose new member
    "no_cache_if_zeo" is added to POOL_RELCACHE.
    
    Another problem is new SET TRANSACTION command in 9.2. This hates
    other SQL issued before the SET command in the transaction. Since
    pgpool-II 3.2 or before does not understand the new SET commmand, it
    tries to issue internal SQL to analyze the dummy SQL. Soltion is,
    adding new member "is_parse_error" to POOL_QUERY_CONTEXT and avoid
    trying to convert dummy table name to oid.


pool_proto_modules.c | 10 ++++++---- pool_query_context.h | 3 +++ pool_relcache.c | 39 ++++++++++++++++++++++----------------- pool_relcache.h | 1 + pool_select_walker.c | 26 +++++++++++++++++++------- 5 files changed, 51 insertions(+), 28 deletions(-) diff --git a/pool_proto_modules.c b/pool_proto_modules.c index 2385e43f1..488bdde1f 100644 --- a/pool_proto_modules.c +++ b/pool_proto_modules.c @@ -233,6 +233,7 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, pool_log("SimpleQuery: Unable to parse the query: \"%s\" from client %s(%s)", contents, remote_host, remote_port); } parse_tree_list = raw_parser(POOL_DUMMY_WRITE_QUERY); + query_context->is_parse_error = true; } } @@ -382,7 +383,7 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, } /* Switch the flag of is_cache_safe in session_context */ - if (is_select_query && + if (is_select_query && !query_context->is_parse_error && pool_is_allow_to_cache(query_context->parse_tree, query_context->original_query)) { @@ -394,7 +395,7 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, } /* If table is to be cached and the query is DML, save the table oid */ - if (!is_select_query) + if (!is_select_query && !query_context->is_parse_error) { num_oids = pool_extract_table_oids(node, &oids); @@ -886,6 +887,7 @@ POOL_STATUS Parse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, pool_log("Parse: Unable to parse the query: \"%s\" from client %s(%s)", stmt, remote_host, remote_port); } parse_tree_list = raw_parser(POOL_DUMMY_WRITE_QUERY); + query_context->is_parse_error = true; } } @@ -929,7 +931,7 @@ POOL_STATUS Parse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, } /* Switch the flag of is_cache_safe in session_context */ - if (is_select_query && + if (is_select_query && !query_context->is_parse_error && pool_is_allow_to_cache(query_context->parse_tree, query_context->original_query)) { @@ -941,7 +943,7 @@ POOL_STATUS Parse(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, } /* If table is to be cached and the query is DML, save the table oid */ - if (!is_select_query) + if (!is_select_query && !query_context->is_parse_error) { num_oids = pool_extract_table_oids(node, &oids); diff --git a/pool_query_context.h b/pool_query_context.h index 6f6e99a45..c48db973a 100644 --- a/pool_query_context.h +++ b/pool_query_context.h @@ -65,6 +65,9 @@ typedef struct { bool is_multi_statement; /* true if multi statement query */ int dboid; /* DB oid which is used at DROP DATABASE */ char *query_w_hex; /* original_query with bind message hex which used for committing cache of extended query */ + bool is_parse_error; /* if true, we could not parse the original + * query and parsed node is actually a dummy query. + */ } POOL_QUERY_CONTEXT; extern POOL_QUERY_CONTEXT *pool_init_query_context(void); diff --git a/pool_relcache.c b/pool_relcache.c index 6979a02f8..81d1197aa 100644 --- a/pool_relcache.c +++ b/pool_relcache.c @@ -101,6 +101,7 @@ void *pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backen int index = 0; int local_session_id; time_t now; + void *result; /* Eliminate double quotes */ rel = malloc(strlen(table)+1); @@ -207,28 +208,32 @@ void *pool_search_relcache(POOL_RELCACHE *relcache, POOL_CONNECTION_POOL *backen } /* Register cache */ - strlcpy(relcache->cache[index].dbname, dbname, MAX_ITEM_LENGTH); - strlcpy(relcache->cache[index].relname, rel, MAX_ITEM_LENGTH); - relcache->cache[index].refcnt = 1; - relcache->cache[index].session_id = local_session_id; - if (pool_config->relcache_expire > 0) - { - relcache->cache[index].expire = now + pool_config->relcache_expire; - } - else + result = (*relcache->register_func)(res); + + if (!relcache->no_cache_if_zero || result) { - relcache->cache[index].expire = 0; + strlcpy(relcache->cache[index].dbname, dbname, MAX_ITEM_LENGTH); + strlcpy(relcache->cache[index].relname, rel, MAX_ITEM_LENGTH); + relcache->cache[index].refcnt = 1; + relcache->cache[index].session_id = local_session_id; + if (pool_config->relcache_expire > 0) + { + relcache->cache[index].expire = now + pool_config->relcache_expire; + } + else + { + relcache->cache[index].expire = 0; + } + /* + * Call user defined unregister/register fuction. + */ + (*relcache->unregister_func)(relcache->cache[index].data); + relcache->cache[index].data = result; } free(rel); - - /* - * Call user defined unregister/register fuction. - */ - (*relcache->unregister_func)(relcache->cache[index].data); - relcache->cache[index].data = (*relcache->register_func)(res); free_select_result(res); - return relcache->cache[index].data; + return result; } /* diff --git a/pool_relcache.h b/pool_relcache.h index 0d00fa8a2..dc6e2ad07 100644 --- a/pool_relcache.h +++ b/pool_relcache.h @@ -61,6 +61,7 @@ typedef struct { */ func_ptr unregister_func; bool cache_is_session_local; /* True if cache life time is session local */ + bool no_cache_if_zero; /* if register func returns 0, do not cache the data */ PoolRelCache *cache; /* cache data */ } POOL_RELCACHE; diff --git a/pool_select_walker.c b/pool_select_walker.c index d3651cb97..c896daf46 100644 --- a/pool_select_walker.c +++ b/pool_select_walker.c @@ -868,16 +868,13 @@ int pool_table_name_to_oid(char *table_name) /* * Query to convert table name to oid */ -/* - * We use standard regclass() instead of pgpool_regclass(). Since we - * don't want to cache oid 0 (table not found). If table is not - * found, pool_search_relcache() do not cache the result. - */ -#define TABLE_TO_OID_QUERY "SELECT regclass('%s')::oid" +#define TABLE_TO_OID_QUERY "SELECT pgpool_regclass('%s')" +#define TABLE_TO_OID_QUERY2 "SELECT oid FROM pg_class WHERE relname = '%s'" int oid = 0; static POOL_RELCACHE *relcache; POOL_CONNECTION_POOL *backend; + char *query; if (table_name == NULL) { @@ -886,12 +883,21 @@ int pool_table_name_to_oid(char *table_name) backend = pool_get_session_context()->backend; + if (pool_has_pgpool_regclass()) + { + query = TABLE_TO_OID_QUERY; + } + else + { + query = TABLE_TO_OID_QUERY2; + } + /* * If relcache does not exist, create it. */ if (!relcache) { - relcache = pool_create_relcache(128, TABLE_TO_OID_QUERY, + relcache = pool_create_relcache(128, query, int_register_func, int_unregister_func, true); if (relcache == NULL) @@ -899,6 +905,12 @@ int pool_table_name_to_oid(char *table_name) pool_error("table_name_to_oid: pool_create_relcache error"); return oid; } + + /* Se do not cache if pgpool_regclass() returns 0, which indicates + * there's no such a table. In this case we do not want to cache the + * state because the table might be created later in this session. + */ + relcache->no_cache_if_zero = true; } /* [parent: 649c2d6379bd]