summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2011-10-04 08:19:44 +0000
committerPavan Deolasee2011-10-04 08:19:44 +0000
commit34ba88b93acf5dd8f06f8dd1b13061d4ca498ab2 (patch)
treec08440c0c60d0e7cc670abcb318297567ec6f501
parent9875b6a3170e02666ad2e4ad12460dd412800598 (diff)
Fix a server crash is query deparsing. PostgreSQL has introduced a new
API for query deparse since 9.1, but that works only for init-ed plans. We were using that API on a Plan node where as it expects a PlanState node to work on. This causes segfault, especially on a 32-bit machine, but the code was wrong anyways. We create dummy PlanState nodes for the purpose of deparse. Since the use is quite limited right now, it works. But this is just a work-around and in the long term, we should either add appropriate API for query deparsing at planning time or move the logic of generating query string at the execution time. The second option looks more promising, but the remote join reduction logic may need some rework.
-rw-r--r--src/backend/optimizer/plan/createplan.c2
-rw-r--r--src/backend/pgxc/plan/planner.c2
-rw-r--r--src/backend/pgxc/pool/postgresql_fdw.c2
-rw-r--r--src/backend/utils/adt/ruleutils.c104
-rw-r--r--src/include/utils/builtins.h4
5 files changed, 111 insertions, 3 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 04b07457a0..3abcd6cfe5 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1266,7 +1266,7 @@ create_remote_expr(PlannerInfo *root, Plan *parent, StringInfo expr,
bms_free(tmprelids);
/* Set up deparsing context */
- context = deparse_context_for_planstate((Node *) parent,
+ context = deparse_context_for_plan((Node *) parent,
NULL,
root->parse->rtable);
diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c
index 9971d4a94b..28521cb8e6 100644
--- a/src/backend/pgxc/plan/planner.c
+++ b/src/backend/pgxc/plan/planner.c
@@ -2213,7 +2213,7 @@ reconstruct_step_query(List *rtable, bool has_order_by, List *extra_sort,
char *sql_from;
int count_from = 1;
- context = deparse_context_for_planstate((Node *) step, NULL, rtable);
+ context = deparse_context_for_plan((Node *) step, NULL, rtable);
useprefix = list_length(rtable) > 1;
foreach(l, sub_tlist)
diff --git a/src/backend/pgxc/pool/postgresql_fdw.c b/src/backend/pgxc/pool/postgresql_fdw.c
index b63690e4e4..dc302a3232 100644
--- a/src/backend/pgxc/pool/postgresql_fdw.c
+++ b/src/backend/pgxc/pool/postgresql_fdw.c
@@ -248,7 +248,7 @@ elog(DEBUG2, "%s(%u) called", __FUNCTION__, __LINE__);
/* prepare to deparse plan */
initStringInfo(&sql);
- context = deparse_context_for_planstate((Node *)scan, NULL,
+ context = deparse_context_for_plan((Node *)scan, NULL,
estate->es_range_table);
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index bc41c14c31..b581474ae8 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -36,6 +36,9 @@
#include "commands/tablespace.h"
#include "executor/spi.h"
#include "funcapi.h"
+#ifdef PGXC
+#include "nodes/execnodes.h"
+#endif
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -171,6 +174,9 @@ static int print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args, bool print_defaults);
static void print_function_rettype(StringInfo buf, HeapTuple proctup);
static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
+#ifdef PGXC
+static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
+#endif
static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
deparse_namespace *save_dpns);
static void pop_child_plan(deparse_namespace *dpns,
@@ -2289,6 +2295,104 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
dpns->inner_plan = NULL;
}
+#ifdef PGXC
+/*
+ * This is a special case deparse context to be used at the planning time to
+ * generate query strings and expressions for remote shipping.
+ *
+ * XXX We should be careful while using this since the support is quite
+ * limited. The only supported use case at this point is for remote join
+ * reduction and some simple plan trees rooted by Agg node having a single
+ * RemoteQuery node as leftree.
+ */
+List *
+deparse_context_for_plan(Node *plan, List *ancestors,
+ List *rtable)
+{
+ deparse_namespace *dpns;
+
+ dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
+
+ /* Initialize fields that stay the same across the whole plan tree */
+ dpns->rtable = rtable;
+ dpns->ctes = NIL;
+#ifdef PGXC
+ dpns->remotequery = false;
+#endif
+
+ /* Set our attention on the specific plan node passed in */
+ set_deparse_plan(dpns, (Plan *) plan);
+ dpns->ancestors = ancestors;
+
+ /* Return a one-deep namespace stack */
+ return list_make1(dpns);
+}
+
+/*
+ * Set deparse context for Plan. Only those plan nodes which are immediate (or
+ * through simple nodes) parents of RemoteQuery nodes are supported right now.
+ *
+ * This is a kind of work-around since the new deparse interface (since 9.1)
+ * expects a PlanState node. But planstates are instantiated only at execution
+ * time when InitPlan is called. But we are required to deparse the query
+ * during planning time, so we hand-cook these dummy PlanState nodes instead of
+ * init-ing the plan. Another approach could have been to delay the query
+ * generation to the execution time, but we are not yet sure if this can be
+ * safely done, especially for remote join reduction.
+ */
+static void
+set_deparse_plan(deparse_namespace *dpns, Plan *plan)
+{
+
+ if (IsA(plan, NestLoop))
+ {
+ NestLoop *nestloop = (NestLoop *) plan;
+
+ dpns->planstate = (PlanState *) makeNode(NestLoopState);
+ dpns->planstate->plan = plan;
+
+ dpns->outer_planstate = (PlanState *) makeNode(PlanState);
+ dpns->outer_plan = dpns->outer_planstate->plan = nestloop->join.plan.lefttree;
+
+ dpns->inner_planstate = (PlanState *) makeNode(PlanState);
+ dpns->inner_plan = dpns->inner_planstate->plan = nestloop->join.plan.righttree;
+ }
+ else if (IsA(plan, RemoteQuery))
+ {
+ dpns->planstate = (PlanState *) makeNode(PlanState);
+ dpns->planstate->plan = plan;
+ }
+ else if (IsA(plan, Agg) || IsA(plan, Group))
+ {
+ /*
+ * We expect plan tree as Group/Agg->Sort->Result->Material->RemoteQuery,
+ * Result, Material nodes are optional. Sort is compulsory for Group but not
+ * for Agg.
+ * anything else is not handled right now.
+ */
+ Plan *temp_plan = plan->lefttree;
+ Plan *remote_scan = NULL;
+
+ if (temp_plan && IsA(temp_plan, Sort))
+ temp_plan = temp_plan->lefttree;
+ if (temp_plan && IsA(temp_plan, Result))
+ temp_plan = temp_plan->lefttree;
+ if (temp_plan && IsA(temp_plan, Material))
+ temp_plan = temp_plan->lefttree;
+ if (temp_plan && IsA(temp_plan, RemoteQuery))
+ remote_scan = temp_plan;
+
+ if (!remote_scan)
+ elog(ERROR, "Deparse of this query at planning is not supported yet");
+
+ dpns->planstate = (PlanState *) makeNode(PlanState);
+ dpns->planstate->plan = plan;
+ }
+ else
+ elog(ERROR, "Deparse of this query at planning not supported yet");
+}
+
+#endif
/*
* push_child_plan: temporarily transfer deparsing attention to a child plan
*
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 0926c34d3d..b11db63ace 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -640,6 +640,10 @@ extern void deparse_query(Query *query, StringInfo buf, List *parentnamespace);
extern List *deparse_context_for(const char *aliasname, Oid relid);
extern List *deparse_context_for_planstate(Node *planstate, List *ancestors,
List *rtable);
+#ifdef PGXC
+extern List *deparse_context_for_plan(Node *plan, List *ancestors,
+ List *rtable);
+#endif
extern const char *quote_identifier(const char *ident);
extern char *quote_qualified_identifier(const char *qualifier,
const char *ident);