diff options
| author | Amit Khandekar | 2012-05-03 16:02:59 +0000 |
|---|---|---|
| committer | Amit Khandekar | 2012-05-03 16:02:59 +0000 |
| commit | 742c9553e01f32a4fefb9ef89bacb1864f7fad2c (patch) | |
| tree | 697ad05741cd7b01c5540421411010ce6e6aef1e | |
| parent | 8f67694c0bfa208437dd8e1918922197dbb21f0b (diff) | |
Add a Result plan node over RemoteQuery node in cases where the target list is
not a plain var tlist. This fixes cases when the target list contains RowExpr
expressions which cannot be handled by RemoteQuery. It deparses such expressions
as ROW(...) and when the remote query fetches such ROW(...) values, they
cannot be converted into input form. Hence the Result plan, which
allows to evaluate any such expressions.
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 71 |
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 |
