#endif
static RemoteSubplan *find_push_down_plan(Plan *plan, bool force);
-static RemoteSubplan *find_delete_push_down_plan(PlannerInfo *root, Plan *plan,
- bool force, Plan **parent);
/*
* create_plan
return find_push_down_plan_int(NULL, plan, force, false, NULL);
}
-static RemoteSubplan *
-find_delete_push_down_plan(PlannerInfo *root,
- Plan *plan,
- bool force,
- Plan **parent)
-{
- return find_push_down_plan_int(root, plan, force, true, parent);
-}
#endif
RecursiveUnion *node = makeNode(RecursiveUnion);
Plan *plan = &node->plan;
int numCols = list_length(distinctList);
-#ifdef XCP
- RemoteSubplan *left_pushdown, *right_pushdown;
-#endif
plan->targetlist = tlist;
plan->qual = NIL;
}
node->numGroups = numGroups;
-#ifdef XCP
- /*
- * For recursive CTE, we have already checked that all tables involved in
- * the query are replicated tables (or coordinator local tables such as
- * catalog tables). So drill down the left and right plan trees and find
- * the corresponding remote subplan(s). If both sides contain a
- * RemoteSubplan then its possible that they are marked for execution on
- * different nodes, but that does not matter since tables are replicated
- * and nodes are picked randomly for replicated tables. So just reuse
- * either of the RemoteSubplan and pin the RecursiveUnion plan generated
- * above to the RemoteSubplan. They must have been already removed from the
- * subtree by find_delete_push_down_plan function
- *
- * XXX For tables replicated on different subsets of nodes, this may not
- * work. In fact, we probably can't support recursive queries for such
- * tables.
- */
- left_pushdown = find_delete_push_down_plan(root, lefttree, true, &plan->lefttree);
- right_pushdown = find_delete_push_down_plan(root, righttree, true, &plan->righttree);
- if (left_pushdown || right_pushdown)
- {
- /* Pick either one */
- if (!left_pushdown)
- left_pushdown = right_pushdown;
-
- /*
- * Push the RecursiveUnion to the remote node
- */
- left_pushdown->scan.plan.lefttree = plan;
-
- /*
- * The only caller for this function does not really care if the
- * returned node is RecursiveUnion or not. So we just return the
- * RemoteSubplan as it
- */
- return (RecursiveUnion *) left_pushdown;
- }
-#endif
return node;
}
}
}
+/*
+ * remove RemoteSubquery from the top of the path
+ *
+ * Essentially find_push_down_plan() but applied when constructing the path,
+ * not when creating the plan. Compared to find_push_down_plan it only deals
+ * with a subset of node types, however.
+ *
+ * XXX Does this need to handle additional node types?
+ */
+static Path *
+strip_remote_subquery(PlannerInfo *root, Path *path)
+{
+ /* if there's RemoteSubplan at the top, we're trivially done */
+ if (IsA(path, RemoteSubPath))
+ return ((RemoteSubPath *)path)->subpath;
+
+ /* for subquery, we tweak the subpath (and descend into it) */
+ if (IsA(path, SubqueryScanPath))
+ {
+ SubqueryScanPath *subquery = (SubqueryScanPath *)path;
+ subquery->subpath = strip_remote_subquery(root, subquery->subpath);
+
+ subquery->path.param_info = subquery->subpath->param_info;
+ subquery->path.pathkeys = subquery->subpath->pathkeys;
+
+ /* also update the distribution */
+ subquery->path.distribution = copyObject(subquery->subpath->distribution);
+
+ /* recompute costs */
+ cost_subqueryscan(subquery, root, path->parent, subquery->path.param_info);
+ }
+
+ return path;
+}
+
/*
* Generate path for a recursive UNION node
*/
dNumGroups = lpath->rows + rpath->rows * 10;
}
+ /*
+ * Push the resursive union (CTE) below Remote Subquery.
+ *
+ * We have already checked that all tables involved in the recursive CTE
+ * are replicated tables (or coordinator local tables such as catalogs).
+ * See subquery_planner for details. So here we search the left and right
+ * subpaths, and search for those remote subqueries.
+ *
+ * If either side contains a remote subquery, we remove those, and instead
+ * add a remote subquery on top of the recursive union later (we don't need
+ * to do that manually, it'll happen automatically).
+ *
+ * XXX The tables may be marked for execution on different nodes, but that
+ * does not matter since tables are replicated, and execution nodes are
+ * picked randomly.
+ *
+ * XXX For tables replicated on different groups of nodes, this may not
+ * work. We either need to pick a node from an intersection of the groups,
+ * or simply disable recursive queries on such tables.
+ *
+ * XXX This obviously breaks costing, because we're removing nodes that
+ * affected the cost (network transfers).
+ */
+ rpath = strip_remote_subquery(root, rpath);
+ lpath = strip_remote_subquery(root, lpath);
+
/*
* And make the path node.
*/
/* RecursiveUnion result is always unsorted */
pathnode->path.pathkeys = NIL;
+ /*
+ * FIXME This assumes left/right path have the same distribution, or one
+ * of them is NULL. This is related to the subquery_planner() assuming all
+ * tables are replicated on the same group of nodes, which may or may not
+ * be the case, and we need to be more careful about it.
+ */
+ if (leftpath->distribution)
+ pathnode->path.distribution = copyObject(leftpath->distribution);
+ else
+ pathnode->path.distribution = copyObject(rightpath->distribution);
+
pathnode->leftpath = leftpath;
pathnode->rightpath = rightpath;
pathnode->distinctList = distinctList;