pgpool2.git / summary / log / commit / refs
commit 1ea486c29e8f3ff5d9b1ae69f32e2dde56bc0302
Author: Tatsuo Ishii <ishii@postgresql.org>
Date: Sat Mar 31 01:03:51 2012 +0000
Allow to use multi statement in master/slave mode. From 3.1
transactional statements such as "BEGIN" are sent to not only primary
but also standbys. This brings an unfortunate side effect: if the
multi statement is "BEGIN;DELETE FROM table;END", this will be sent to
standy as well and cause an error because standby does not allow write
SQL. So fix is, if a query is a multi statement one, then send it to
primary only.
Committed to master and V3_1_STABLE.
pool_proto_modules.c | 12 ++++++++++++
pool_query_context.c | 21 +++++++++++++++++++++
pool_query_context.h | 1 +
3 files changed, 34 insertions(+)
diff --git a/pool_proto_modules.c b/pool_proto_modules.c
index 4afff9542..b455be200 100644
--- a/pool_proto_modules.c
+++ b/pool_proto_modules.c
@@ -249,6 +249,18 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend,
*/
pool_start_query(query_context, contents, len, node);
+ /*
+ * Check if multi statement query
+ */
+ if (parse_tree_list && list_length(parse_tree_list) > 1)
+ {
+ query_context->is_multi_statement = true;
+ }
+ else
+ {
+ query_context->is_multi_statement = false;
+ }
+
if (PARALLEL_MODE)
{
bool parallel = true;
diff --git a/pool_query_context.c b/pool_query_context.c
index bd9fc1797..accc2942a 100644
--- a/pool_query_context.c
+++ b/pool_query_context.c
@@ -331,6 +331,27 @@ void pool_where_to_send(POOL_QUERY_CONTEXT *query_context, char *query, Node *no
{
pool_set_node_to_be_sent(query_context, REAL_MASTER_NODE_ID);
}
+ else if (MASTER_SLAVE && query_context->is_multi_statement)
+ {
+ /*
+ * If we are in master/slave mode and we have multi stametemt
+ * query, we should send it to primary server only. Otherwise
+ * it is possible to send a write query to standby servers
+ * because we only use the first element of the multi
+ * statement query and don't care about the rest. Typical
+ * situation where we are bugged by this is, "BEGIN;DELETE
+ * FROM table;END". Note that from pgpool-II 3.1.0
+ * transactional statements such as "BEGIN" is unconditionaly
+ * sent to all nodes(see send_to_where() for more details).
+ * Someday we might be able to understand all part of multi
+ * statement queries, but until that day we need this band
+ * aid.
+ */
+ if (query_context->is_multi_statement)
+ {
+ pool_set_node_to_be_sent(query_context, PRIMARY_NODE_ID);
+ }
+ }
else if (MASTER_SLAVE)
{
POOL_DEST dest;
diff --git a/pool_query_context.h b/pool_query_context.h
index 5fb0940e4..e4a50e243 100644
--- a/pool_query_context.h
+++ b/pool_query_context.h
@@ -57,6 +57,7 @@ typedef struct {
POOL_QUERY_STATE query_state[MAX_NUM_BACKENDS]; /* for extended query protocol */
bool is_cache_safe; /* true if SELECT is safe to cache */
POOL_TEMP_QUERY_CACHE *temp_cache; /* temporary cache */
+ bool is_multi_statement; /* true if multi statement query */
} POOL_QUERY_CONTEXT;
extern POOL_QUERY_CONTEXT *pool_init_query_context(void);
[parent: a29cd65a642c]