summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/plan/createplan.c71
1 files changed, 65 insertions, 6 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 98bb4a622d..6c42be9366 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -91,7 +91,7 @@ static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path *best_pa
#ifdef PGXC
static RowMarkClause *mk_row_mark_clause(PlanRowMark *prm);
static bool compare_alias(Alias *a1, Alias *a2);
-static RemoteQuery *create_remotequery_plan(PlannerInfo *root, Path *best_path,
+static Plan *create_remotequery_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses);
static Plan *create_remotejoin_plan(PlannerInfo *root, JoinPath *best_path,
Plan *parent, Plan *outer_plan, Plan *inner_plan);
@@ -799,7 +799,7 @@ create_remotejoin_plan(PlannerInfo *root, JoinPath *best_path, Plan *parent, Pla
* intermediate, the children vars may or may not be referenced
* multiple times in it.
*/
- parent_vars = pull_var_clause((Node *)parent->targetlist, PVC_REJECT_PLACEHOLDERS);
+ parent_vars = pull_var_clause((Node *)parent->targetlist, PVC_RECURSE_PLACEHOLDERS);
findReferencedVars(parent_vars, outer_plan, &out_tlist, &out_relids);
findReferencedVars(parent_vars, inner_plan, &in_tlist, &in_relids);
@@ -2540,14 +2540,40 @@ compare_alias(Alias *a1, Alias *a2)
}
/*
+ * contains_only_vars(tlist)
+ * Return true only if each element of tlist is a target entry having Var node
+ * as its containing expression.
+ */
+static bool
+contains_only_vars(List *tlist)
+{
+ ListCell *l;
+
+ foreach(l, (List *) tlist)
+ {
+ Node *tle = lfirst(l);
+ if (nodeTag(tle) != T_TargetEntry)
+ return false;
+ else
+ {
+ Expr *expr = ((TargetEntry *) tle)->expr;
+ if (nodeTag(expr) != T_Var)
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
* create_remotequery_plan
* Returns a remotequery plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
-static RemoteQuery *
+static Plan *
create_remotequery_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
+ Plan *result_node ;
RemoteQuery *scan_plan;
Index scan_relid = best_path->parent->relid;
RangeTblEntry *rte;
@@ -2565,6 +2591,8 @@ create_remotequery_plan(PlannerInfo *root, Path *best_path,
Oid distcol_type;
Node *tmp_node;
List *rmlist;
+ List *tvarlist;
+ bool tlist_is_simple = contains_only_vars(tlist);
Assert(scan_relid > 0);
Assert(best_path->parent->rtekind == RTE_RELATION);
@@ -2612,7 +2640,22 @@ create_remotequery_plan(PlannerInfo *root, Path *best_path,
query->jointree->fromlist = list_make1(rtr);
query->jointree->quals = (Node *)make_ands_explicit(copyObject(remote_scan_clauses));
- query->targetList = copyObject(tlist);
+
+ /*
+ * RemoteQuery node cannot handle arbitrary expressions in the target list.
+ * So if the target list has any elements that are not plain Vars, we need
+ * to create a Result node above RemoteQuery, and assign a plain var tlist
+ * in RemoteQuery node, and Result node will handle the expressions. So if
+ * the passed-in tlist is not a simple vars tlist, derive one out of the
+ * tlist.
+ */
+ if (tlist_is_simple)
+ query->targetList = copyObject(tlist);
+ else
+ {
+ tvarlist = copyObject(pull_var_clause((Node *)tlist, PVC_RECURSE_PLACEHOLDERS));
+ query->targetList = add_to_flat_tlist(NIL, copyObject(tvarlist));
+ }
/*
* Change the varno in Var nodes in the targetlist of the query to be shipped to the
@@ -2708,7 +2751,23 @@ create_remotequery_plan(PlannerInfo *root, Path *best_path,
rel_loc_info = GetRelationLocInfo(rte->relid);
if (!rel_loc_info)
elog(ERROR, "No distribution information found for relid %d", rte->relid);
- scan_plan = make_remotequery(tlist, local_scan_clauses, scan_relid);
+
+ if (tlist_is_simple)
+ {
+ scan_plan = make_remotequery(tlist, local_scan_clauses, scan_relid);
+ result_node = (Plan *) scan_plan;
+ }
+ else
+ {
+ /*
+ * Use simple tlist for RemoteQuery, and let Result plan handle
+ * non-simple target list.
+ */
+ scan_plan = make_remotequery(add_to_flat_tlist(NIL, copyObject(tvarlist)),
+ local_scan_clauses, scan_relid);
+ result_node = (Plan *) make_result(root, tlist, NULL, (Plan*) scan_plan);
+ }
+
/* Track if the remote query involves a temporary object */
scan_plan->is_temp = IsTempTable(rte->relid);
@@ -2776,7 +2835,7 @@ create_remotequery_plan(PlannerInfo *root, Path *best_path,
/* PGXCTODO - get better estimates */
scan_plan->scan.plan.plan_rows = 1000;
- return scan_plan;
+ return result_node;
}
#endif