#include "pgxc/pgxc.h"
#include "optimizer/pgxcplan.h"
-static RemoteQueryPath *pgxc_find_remotequery_path(RelOptInfo *rel);
static RemoteQueryPath *create_remotequery_path(PlannerInfo *root, RelOptInfo *rel,
ExecNodes *exec_nodes, RemoteQueryPath *leftpath,
RemoteQueryPath *rightpath, JoinType jointype,
return rqpath;
}
-
-/*
- * create_plainrel_rqpath
- * Create a RemoteQuery path for a plain relation residing on datanode/s and add
- * it to the pathlist in corresponding RelOptInfo. The function returns true, if
- * it creates a remote query path and adds it, otherwise it returns false.
- * The caller can decide whether to add the scan paths depending upon the return
- * value.
- */
-extern bool
-create_plainrel_rqpath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
-{
- List *quals;
- ExecNodes *exec_nodes;
- RelationLocInfo *rel_loc_info;
-
- /*
- * If we are on the Coordinator, we always want to use
- * the remote query path unless relation is local to coordinator or the
- * query is to entirely executed on coordinator.
- */
- if (!IS_PGXC_COORDINATOR || IsConnFromCoord() || root->parse->is_local)
- return false;
-
- quals = extract_actual_clauses(rel->baserestrictinfo, false);
- rel_loc_info = GetRelationLocInfo(rte->relid);
- exec_nodes = GetRelationNodesByQuals(rte->relid, rel_loc_info, rel->relid,
- (Node *)quals,
- RELATION_ACCESS_READ);
- if (!exec_nodes)
- return false;
-
- /* We don't have subpaths for a plain base relation */
- add_path(rel, (Path *)create_remotequery_path(root, rel, exec_nodes,
- NULL, NULL, 0, NULL));
- return true;
-}
-
-/*
- * pgxc_find_remotequery_path
- * Search the path list for the rel for existence of a RemoteQuery path, return
- * if one found, NULL otherwise. There should be only one RemoteQuery path for
- * each rel, but we don't check for this.
- */
-static RemoteQueryPath *
-pgxc_find_remotequery_path(RelOptInfo *rel)
-{
- ListCell *cell;
-
- foreach (cell, rel->pathlist)
- {
- Path *path = (Path *)lfirst(cell);
- if (IsA(path, RemoteQueryPath))
- return (RemoteQueryPath *)path;
- }
- return NULL;
-}
-
-/*
- * pgxc_ship_remotejoin
- * If there are RemoteQuery paths for the rels being joined, check if the join
- * is shippable to the datanodes, and if so, create a remotequery path for this
- * JOIN.
- */
-extern void
-create_joinrel_rqpath(PlannerInfo *root, RelOptInfo *joinrel,
- RelOptInfo *outerrel, RelOptInfo *innerrel,
- List *restrictlist, JoinType jointype,
- SpecialJoinInfo *sjinfo)
-{
- RemoteQueryPath *innerpath;
- RemoteQueryPath *outerpath;
- ExecNodes *inner_en;
- ExecNodes *outer_en;
- ExecNodes *join_en;
- List *join_quals = NIL;
- List *other_quals = NIL;
-
- /* If GUC does not allow remote join optimization, so be it */
- if (!enable_remotejoin)
- return;
-
- innerpath = pgxc_find_remotequery_path(innerrel);
- outerpath = pgxc_find_remotequery_path(outerrel);
- /*
- * If one of the relation does not have RemoteQuery path, the join can not
- * be shipped to the datanodes.
- * If one of the relation has an unshippable qual, it needs to be evaluated
- * before joining the two relations. Hence this JOIN is not shippable.
- * PGXC_TODO: In case of INNER join above condition can be relaxed by
- * attaching the unshippable qual to the join itself, and thus shipping join
- * but evaluating the qual on join result. But we don't attempt it for now
- */
- if (!innerpath || !outerpath ||
- innerpath->has_unshippable_qual || outerpath->has_unshippable_qual)
- return;
-
- inner_en = innerpath->rqpath_en;
- outer_en = outerpath->rqpath_en;
-
- if (!inner_en || !outer_en)
- elog(ERROR, "No node list provided for remote query path");
- /*
- * Collect quals from restrictions so as to check the shippability of a JOIN
- * between distributed relations.
- */
- extract_actual_join_clauses(restrictlist, &join_quals, &other_quals);
- /*
- * If the joining qual is not shippable and it's an OUTER JOIN, we can not
- * ship the JOIN, since that would impact JOIN result.
- */
- if (jointype != JOIN_INNER &&
- !pgxc_is_expr_shippable((Expr *)join_quals, NULL))
- return;
- /*
- * For INNER JOIN there is no distinction between JOIN and non-JOIN clauses,
- * so let the JOIN reduction algorithm take all of them into consideration
- * to decide whether a JOIN is reducible or not based on quals (if
- * required).
- */
- if (jointype == JOIN_INNER)
- join_quals = list_concat(join_quals, other_quals);
-
- /*
- * If the nodelists on both the sides of JOIN can be merged, the JOIN is
- * shippable.
- */
- join_en = pgxc_is_join_shippable(inner_en, outer_en,
- innerrel->relids, outerrel->relids,
- jointype, join_quals, root->parse->rtable);
- if (join_en)
- add_path(joinrel, (Path *)create_remotequery_path(root, joinrel, join_en,
- outerpath, innerpath, jointype,
- restrictlist));
- return;
-}