static bool multi_statement_query(char *buf);
+static void check_prepare(List *parse_tree_list, int len, char *contents);
+
/*
* This is the workhorse of processing the pg_terminate_backend function to
* make sure that the use of function should not trigger the backend node failover.
query_context->is_parse_error = true;
}
}
+
+ if (query_context->is_multi_statement)
+ {
+ /*
+ * Check parse tree list and if it includes PREPARE statement in the
+ * second or subsequent parse tree, create "sent_message" entry so
+ * that bind message can find them later on (PREPARE is usually
+ * executed by EXECUTE, but it's possible that a client feels free to
+ * use PREPARE then bind and execute messages). If PREPARE is in the
+ * first parse tree, it will be processed subsequent code path.
+ */
+ check_prepare(parse_tree_list, len, contents);
+ }
+
MemoryContextSwitchTo(old_context);
if (parse_tree_list != NIL)
return num_semicolons > 1;
}
+
+/*
+ * Check given parse tree list and if it is a multi statement and includes
+ * PREPARE statement in the second or subsequent parse tree, create
+ * "sent_message" entry so that bind message can find them later on.
+ * parse_tree_list: raw parse tree list (list of RawStmt)
+ * len: full query string length
+ * contents: full query string
+ */
+static void
+check_prepare(List *parse_tree_list, int len, char *contents)
+{
+ Node *node;
+ RawStmt *rstmt;
+ POOL_QUERY_CONTEXT *query_context;
+ ListCell *l;
+ POOL_SENT_MESSAGE *message;
+
+ /* sanity check */
+ if (list_length(parse_tree_list) <= 1)
+ return;
+
+ foreach (l, parse_tree_list)
+ {
+ if (l == list_head(parse_tree_list)) /* skip the first parse tree */
+ continue;
+
+ rstmt = (RawStmt *) lfirst(l);
+ node = (Node *) rstmt->stmt; /* pick one parse tree */
+
+ if (!IsA(node, PrepareStmt)) /* PREPARE? */
+ continue;
+
+ query_context = pool_init_query_context(); /* initialize query context */
+ query_context->is_multi_statement = true; /* this is a multi statement query */
+ pool_start_query(query_context, contents, len, node); /* start query context */
+ pool_where_to_send(query_context, query_context->original_query, /* set query destination */
+ query_context->parse_tree);
+ message = pool_create_sent_message('Q', len, contents, 0, /* create sent message */
+ ((PrepareStmt *) node)->name, query_context);
+ pool_add_sent_message(message); /* add it to the sent message list */
+ }
+}
--- /dev/null
+FE=> Query (query="PREPARE mark_rels_by_node(int8) AS SELECT $1;PREPARE mark_rels_by_way(int8) AS SELECT $1")
+<= BE CommandComplete(PREPARE)
+<= BE CommandComplete(PREPARE)
+<= BE ReadyForQuery(I)
+FE=> Bind(stmt="mark_rels_by_node", portal="")
+FE=> Describe(portal="")
+FE=> Execute(portal="")
+FE=> Sync
+<= BE BindComplete
+<= BE RowDescription
+<= BE DataRow
+<= BE CommandComplete(SELECT 1)
+<= BE ReadyForQuery(I)
+FE=> Bind(stmt="mark_rels_by_way", portal="")
+FE=> Describe(portal="")
+FE=> Execute(portal="")
+FE=> Sync
+<= BE BindComplete
+<= BE RowDescription
+<= BE DataRow
+<= BE CommandComplete(SELECT 1)
+<= BE ReadyForQuery(I)
+FE=> Terminate
--- /dev/null
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# Test script for multi statement query including PREPARE *and* bind is used later on.
+# Discussion: [pgpool-general: 8870] Prepared statements over pgpool ?
+#
+source $TESTLIBS
+TESTDIR=testdir
+PSQL=$PGBIN/psql
+PG_CTL=$PGBIN/pg_ctl
+PGPROTO=$PGPOOL_INSTALL_DIR/bin/pgproto
+export PGDATABASE=test
+
+#for mode in s
+for mode in s i r n
+do
+ rm -fr $TESTDIR
+ mkdir $TESTDIR
+ cd $TESTDIR
+
+ echo -n "creating test environment..."
+ $PGPOOL_SETUP -m $mode || exit 1
+ echo "done."
+ source ./bashrc.ports
+ ./startall
+ wait_for_pgpool_startup
+
+ $PGPROTO -d $PGDATABASE -p $PGPOOL_PORT -f ../pgproto.data > results.txt 2>&1
+ cmp ../expected.txt results.txt
+
+ if [ $? != 0 ];then
+ echo "test failed in mode: $mode".
+ ./shutdownall
+ exit 1
+ fi
+ ./shutdownall
+ cd ..
+done
+
+exit 0