/* * cdbpathtoplan_create_flow */ Flow * cdbpathtoplan_create_flow(PlannerInfo *root, CdbPathLocus locus, Relids relids, List *pathkeys, Plan *plan) { Flow *flow = NULL; /* Distribution */ if (CdbPathLocus_IsEntry(locus)) { flow = makeFlow(FLOW_SINGLETON); flow->segindex = -1; } else if (CdbPathLocus_IsSingleQE(locus)) { flow = makeFlow(FLOW_SINGLETON); flow->segindex = 0; } else if (CdbPathLocus_IsGeneral(locus)) { flow = makeFlow(FLOW_SINGLETON); flow->segindex = 0; } else if (CdbPathLocus_IsReplicated(locus)) { flow = makeFlow(FLOW_REPLICATED); } else if (CdbPathLocus_IsHashed(locus) || CdbPathLocus_IsHashedOJ(locus)) { flow = makeFlow(FLOW_PARTITIONED); flow->hashExpr = cdbpathlocus_get_partkey_exprs(locus, relids, plan->targetlist); /* * hashExpr can be NIL if the rel is partitioned on columns that aren't * projected (i.e. are not present in the result of this Path operator). */ } else if (CdbPathLocus_IsStrewn(locus)) flow = makeFlow(FLOW_PARTITIONED); else Insist(0); /* * Describe the ordering of the result rows. The ordering info will be * truncated upon encountering an expr which is not already present in the * plan's targetlist. Duplicate cols and constant cols will be omitted. */ if (pathkeys) { Sort *sort = make_sort_from_pathkeys(root, plan, pathkeys, relids, false); if (sort) { flow->numSortCols = sort->numCols; flow->sortColIdx = sort->sortColIdx; flow->sortOperators = sort->sortOperators; } } flow->req_move = MOVEMENT_NONE; flow->locustype = locus.locustype; return flow; } /* cdbpathtoplan_create_flow */
/* * cdbpathtoplan_create_motion_plan */ Motion * cdbpathtoplan_create_motion_plan(PlannerInfo *root, CdbMotionPath *path, Plan *subplan) { Motion *motion = NULL; Path *subpath = path->subpath; /* Send all tuples to a single process? */ if (CdbPathLocus_IsBottleneck(path->path.locus)) { int destSegIndex = -1; /* to dispatcher */ if (CdbPathLocus_IsSingleQE(path->path.locus)) destSegIndex = gp_singleton_segindex; /* to singleton qExec */ if (path->path.pathkeys) { /* * Build a dummy Sort node. We'll take its sort key info to * define our Merge Receive keys. Unchanged subplan ptr is * returned to us if ordering is degenerate (all cols constant). */ Sort *sort = make_sort_from_pathkeys(root, subplan, path->path.pathkeys, path->path.parent->relids, true); /* Merge Receive to preserve ordering */ if (sort) { /* Result node might have been added below the Sort */ subplan = sort->plan.lefttree; motion = make_sorted_union_motion(subplan, destSegIndex, sort->numCols, sort->sortColIdx, sort->sortOperators, false /* useExecutorVarFormat */ ); } /* Degenerate ordering... build unordered Union Receive */ else motion = make_union_motion(subplan, destSegIndex, false /* useExecutorVarFormat */ ); } /* Unordered Union Receive */ else motion = make_union_motion(subplan, destSegIndex, false /* useExecutorVarFormat */ ); } /* Send all of the tuples to all of the QEs in gang above... */ else if (CdbPathLocus_IsReplicated(path->path.locus)) motion = make_broadcast_motion(subplan, false /* useExecutorVarFormat */ ); /* Hashed redistribution to all QEs in gang above... */ else if (CdbPathLocus_IsHashed(path->path.locus) || CdbPathLocus_IsHashedOJ(path->path.locus)) { List *hashExpr = cdbpathlocus_get_partkey_exprs(path->path.locus, path->path.parent->relids, subplan->targetlist); Insist(hashExpr); /** * If there are subplans in the hashExpr, push it down to lower level. */ if (contain_subplans( (Node *) hashExpr) &&is_projection_capable_plan(subplan)) { subplan->targetlist = add_to_flat_tlist(subplan->targetlist, hashExpr, true /* resjunk */); } motion = make_hashed_motion(subplan, hashExpr, false /* useExecutorVarFormat */); } else Insist(0); /* * Decorate the subplan with a Flow node telling the plan slicer * what kind of gang will be needed to execute the subplan. */ subplan->flow = cdbpathtoplan_create_flow(root, subpath->locus, subpath->parent ? subpath->parent->relids : NULL, subpath->pathkeys, subplan); /** * If plan has a flow node, and its child is projection capable, * then ensure all entries of hashExpr are in the targetlist. */ if (subplan->flow && subplan->flow->hashExpr && is_projection_capable_plan(subplan)) { subplan->targetlist = add_to_flat_tlist(subplan->targetlist, subplan->flow->hashExpr, true /* resjunk */); } return motion; } /* cdbpathtoplan_create_motion_plan */
/* * cdbpath_create_motion_path * Returns a Path that delivers the subpath result to the * given locus, or NULL if it can't be done. * * 'pathkeys' must specify an ordering equal to or weaker than the * subpath's existing ordering. * * If no motion is needed, the caller's subpath is returned unchanged. * Else if require_existing_order is true, NULL is returned if the * motion would not preserve an ordering at least as strong as the * specified ordering; also NULL is returned if pathkeys is NIL * meaning the caller is just checking and doesn't want to add motion. * Else a CdbMotionPath is returned having either the specified pathkeys * (if given and the motion uses Merge Receive), or the pathkeys * of the original subpath (if the motion is order-preserving), or no * pathkeys otherwise (the usual case). */ Path * cdbpath_create_motion_path(PlannerInfo *root, Path *subpath, List *pathkeys, bool require_existing_order, CdbPathLocus locus) { CdbMotionPath *pathnode; UnusedArg(root); Assert(cdbpathlocus_is_valid(locus) && cdbpathlocus_is_valid(subpath->locus)); /* Moving subpath output to a single executor process (qDisp or qExec)? */ if (CdbPathLocus_IsBottleneck(locus)) { /* entry-->entry or singleQE-->singleQE? No motion needed. */ if (CdbPathLocus_IsEqual(subpath->locus, locus)) return subpath; /* entry-->singleQE? Don't move. Slice's QE will run on entry db. */ if (CdbPathLocus_IsEntry(subpath->locus)) return subpath; /* singleQE-->entry? Don't move. Slice's QE will run on entry db. */ if (CdbPathLocus_IsSingleQE(subpath->locus)) { /* Create CdbMotionPath node to indicate that the slice must be * dispatched to a singleton gang running on the entry db. We * merely use this node to note that the path has 'Entry' locus; * no corresponding Motion node will be created in the Plan tree. */ Assert(CdbPathLocus_IsEntry(locus)); pathnode = makeNode(CdbMotionPath); pathnode->path.pathtype = T_Motion; pathnode->path.parent = subpath->parent; pathnode->path.locus = locus; pathnode->path.pathkeys = pathkeys; pathnode->subpath = subpath; /* Costs, etc, are same as subpath. */ pathnode->path.startup_cost = subpath->total_cost; pathnode->path.total_cost = subpath->total_cost; pathnode->path.memory = subpath->memory; pathnode->path.motionHazard = subpath->motionHazard; pathnode->path.rescannable = subpath->rescannable; return (Path *)pathnode; } /* No motion needed if subpath can run anywhere giving same output. */ if (CdbPathLocus_IsGeneral(subpath->locus)) return subpath; /* Fail if caller refuses motion. */ if (require_existing_order && !pathkeys) return NULL; /* replicated-->singleton would give redundant copies of the rows. */ if (CdbPathLocus_IsReplicated(subpath->locus)) goto invalid_motion_request; /* Must be partitioned-->singleton. * If caller gave pathkeys, they'll be used for Merge Receive. * If no pathkeys, Union Receive will arbitrarily interleave * the rows from the subpath partitions in no special order. */ if (!CdbPathLocus_IsPartitioned(subpath->locus)) goto invalid_motion_request; } /* Output from a single process to be distributed over a gang? */ else if (CdbPathLocus_IsBottleneck(subpath->locus)) { /* Must be bottleneck-->partitioned or bottleneck-->replicated */ if (!CdbPathLocus_IsPartitioned(locus) && !CdbPathLocus_IsReplicated(locus)) goto invalid_motion_request; /* Fail if caller disallows motion. */ if (require_existing_order && !pathkeys) return NULL; /* Each qExec receives a subset of the rows, with ordering preserved. */ pathkeys = subpath->pathkeys; } /* Redistributing partitioned subpath output from one gang to another? */ else if (CdbPathLocus_IsPartitioned(subpath->locus)) { /* partitioned-->partitioned? */ if (CdbPathLocus_IsPartitioned(locus)) { /* No motion if subpath partitioning matches caller's request. */ if (cdbpathlocus_compare(CdbPathLocus_Comparison_Equal, subpath->locus, locus)) return subpath; } /* Must be partitioned-->replicated */ else if (!CdbPathLocus_IsReplicated(locus)) goto invalid_motion_request; /* Fail if caller insists on ordered result or no motion. */ if (require_existing_order) return NULL; /* Output streams lose any ordering they had. * Only a qDisp or singleton qExec can merge sorted streams (for now). */ pathkeys = NIL; } /* If subplan uses no tables, it can run on qDisp or a singleton qExec. */ else if (CdbPathLocus_IsGeneral(subpath->locus)) { /* No motion needed if general-->general or general-->replicated. */ if (CdbPathLocus_IsGeneral(locus) || CdbPathLocus_IsReplicated(locus)) return subpath; /* Must be general-->partitioned. */ if (!CdbPathLocus_IsPartitioned(locus)) goto invalid_motion_request; /* Fail if caller wants no motion. */ if (require_existing_order && !pathkeys) return NULL; /* Since the motion is 1-to-many, the rows remain in the same order. */ pathkeys = subpath->pathkeys; } /* Does subpath produce same multiset of rows on every qExec of its gang? */ else if (CdbPathLocus_IsReplicated(subpath->locus)) { /* No-op if replicated-->replicated. */ if (CdbPathLocus_IsReplicated(locus)) return subpath; /* Other destinations aren't used or supported at present. */ goto invalid_motion_request; } else goto invalid_motion_request; /* Don't materialize before motion. */ if (IsA(subpath, MaterialPath)) subpath = ((MaterialPath *)subpath)->subpath; /* * MPP-3300: materialize *before* motion can never help us, motion * pushes data. other nodes pull. We relieve motion deadlocks by * adding materialize nodes on top of motion nodes */ /* Create CdbMotionPath node. */ pathnode = makeNode(CdbMotionPath); pathnode->path.pathtype = T_Motion; pathnode->path.parent = subpath->parent; pathnode->path.locus = locus; pathnode->path.pathkeys = pathkeys; pathnode->subpath = subpath; /* Cost of motion */ cdbpath_cost_motion(root, pathnode); /* Tell operators above us that slack may be needed for deadlock safety. */ pathnode->path.motionHazard = true; pathnode->path.rescannable = false; return (Path *)pathnode; /* Unexpected source or destination locus. */ invalid_motion_request: Assert(0); return NULL; } /* cdbpath_create_motion_path */