pgpool2.git / summary / log / commit / refs

commit    b5f26de7d67278db695e1be8f0c426e59b8a050b
Author:   Tatsuo Ishii <ishii@postgresql.org>
Date:     Sat Nov 17 10:12:40 2012 +0000

    Fix bug with query cache returning incorrect data in some cases when a
    persistent table and temp table have same name.
    
    Here is a sequence to trigger the bug:
    1) CREATE TABLE t1(i int);	-- create a persistent table
    2) INSERT INTO t1 VALUES(1);
    3) SELECT * FROM t1;		-- query cache entry created
    4) CREATE TEMP TABLE t1(i int);	-- create a temp table
    5) SELECT * FROM t1;		-- query cache entry mistakenly created!
    
    Problem is #3 creates relcache entry for t1, and #5 incorrecly uses it
    and believes that temp table t1 is not a temp table. To solve the
    problem, new function discard_temp_table_relcache() added and it gets
    called in ReadyforQuery if CREATE TEMP TABLE executed to discard
    relcache for temp table info.


pool_proto_modules.c | 31 +++++++++++++++++++++++-------- pool_select_walker.c | 27 ++++++++++++++++++++------- pool_select_walker.h | 1 + 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/pool_proto_modules.c b/pool_proto_modules.c index ed186a647..2fd2a1d8c 100644 --- a/pool_proto_modules.c +++ b/pool_proto_modules.c @@ -1724,15 +1724,30 @@ POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend, return POOL_END; } - /* - * If the query was not READ SELECT, and we are in an - * explicit transaction, remember that we had a write - * query in this transaction. - */ - else if (!is_select_query(node, query) && - TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) == 'T') + else if (!is_select_query(node, query)) { - pool_set_writing_transaction(); + /* + * If the query was not READ SELECT, and we are in an + * explicit transaction, remember that we had a write + * query in this transaction. + */ + if (TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) == 'T') + { + pool_set_writing_transaction(); + } + + /* + * If the query was CREATE TEMP TABLE, discard + * temp table relcache because we might have had + * persistent table relation cache which has table + * name as the tem table. + */ + if (IsA(node, CreateStmt)) + { + CreateStmt *create_table_stmt = (CreateStmt *)node; + if (create_table_stmt->relation->istemp) + discard_temp_table_relcache(); + } } } diff --git a/pool_select_walker.c b/pool_select_walker.c index 8a2e23222..1f16d0d1f 100644 --- a/pool_select_walker.c +++ b/pool_select_walker.c @@ -493,6 +493,8 @@ static bool is_system_catalog(char *table_name) * Judge the table used in a query represented by node is a temporary * table or not. */ +static POOL_RELCACHE *is_temp_table_relcache; + static bool is_temp_table(char *table_name) { /* @@ -520,7 +522,6 @@ static bool is_temp_table(char *table_name) int hasrelistemp; bool result; static POOL_RELCACHE *hasrelistemp_cache; - static POOL_RELCACHE *relcache; char *query; POOL_CONNECTION_POOL *backend; @@ -555,12 +556,12 @@ static bool is_temp_table(char *table_name) /* * If relcache does not exist, create it. */ - if (!relcache) + if (!is_temp_table_relcache) { - relcache = pool_create_relcache(pool_config->relcache_size, query, - int_register_func, int_unregister_func, - true); - if (relcache == NULL) + is_temp_table_relcache = pool_create_relcache(pool_config->relcache_size, query, + int_register_func, int_unregister_func, + true); + if (is_temp_table_relcache == NULL) { pool_error("is_temp_table: pool_create_relcache error"); return false; @@ -570,10 +571,22 @@ static bool is_temp_table(char *table_name) /* * Search relcache. */ - result = pool_search_relcache(relcache, backend, table_name)==0?false:true; + result = pool_search_relcache(is_temp_table_relcache, backend, table_name)==0?false:true; return result; } +/* + * Discard relcache used by is_temp_table_relcache(). + */ +void discard_temp_table_relcache(void) +{ + if (is_temp_table_relcache) + { + pool_discard_relcache(is_temp_table_relcache); + is_temp_table_relcache = NULL; + } +} + /* * Judge the table used in a query represented by node is a unlogged * table or not. diff --git a/pool_select_walker.h b/pool_select_walker.h index 5bf8afc28..3e6555b77 100644 --- a/pool_select_walker.h +++ b/pool_select_walker.h @@ -51,6 +51,7 @@ extern bool pool_has_function_call(Node *node); extern bool pool_has_non_immutable_function_call(Node *node); extern bool pool_has_system_catalog(Node *node); extern bool pool_has_temp_table(Node *node); +extern void discard_temp_table_relcache(void); extern bool pool_has_unlogged_table(Node *node); extern bool pool_has_view(Node *node); extern bool pool_has_insertinto_or_locking_clause(Node *node); [parent: ece0f8ffafcf]