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]