static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path, int flags); static Plan *create_scan_plan(PlannerInfo *root, Path *best_path, int flags); static List *build_path_tlist(PlannerInfo *root, Path *path); staticbool use_physical_tlist(PlannerInfo *root, Path *path, int flags); static List *get_gating_quals(PlannerInfo *root, List *quals); static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
List *gating_quals); static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); staticbool mark_async_capable_plan(Plan *plan, Path *path); static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags); static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, int flags); static Result *create_group_result_plan(PlannerInfo *root,
GroupResultPath *best_path); static ProjectSet *create_project_set_plan(PlannerInfo *root, ProjectSetPath *best_path); static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path, int flags); static Memoize *create_memoize_plan(PlannerInfo *root, MemoizePath *best_path, int flags); static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags); static Gather *create_gather_plan(PlannerInfo *root, GatherPath *best_path); static Plan *create_projection_plan(PlannerInfo *root,
ProjectionPath *best_path, int flags); static Plan *inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe); static Sort *create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags); static IncrementalSort *create_incrementalsort_plan(PlannerInfo *root,
IncrementalSortPath *best_path, int flags); static Group *create_group_plan(PlannerInfo *root, GroupPath *best_path); static Unique *create_upper_unique_plan(PlannerInfo *root, UpperUniquePath *best_path, int flags); static Agg *create_agg_plan(PlannerInfo *root, AggPath *best_path); static Plan *create_groupingsets_plan(PlannerInfo *root, GroupingSetsPath *best_path); static Result *create_minmaxagg_plan(PlannerInfo *root, MinMaxAggPath *best_path); static WindowAgg *create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path); static SetOp *create_setop_plan(PlannerInfo *root, SetOpPath *best_path, int flags); static RecursiveUnion *create_recursiveunion_plan(PlannerInfo *root, RecursiveUnionPath *best_path); static LockRows *create_lockrows_plan(PlannerInfo *root, LockRowsPath *best_path, int flags); static ModifyTable *create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path); static Limit *create_limit_plan(PlannerInfo *root, LimitPath *best_path, int flags); static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static SampleScan *create_samplescan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static Scan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path,
List *tlist, List *scan_clauses, bool indexonly); static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root,
BitmapHeapPath *best_path,
List *tlist, List *scan_clauses); static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual, List **indexqual, List **indexECs); staticvoid bitmap_subplan_mark_shared(Plan *plan); static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses); static TidRangeScan *create_tidrangescan_plan(PlannerInfo *root,
TidRangePath *best_path,
List *tlist,
List *scan_clauses); static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root,
SubqueryScanPath *best_path,
List *tlist, List *scan_clauses); static FunctionScan *create_functionscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static ValuesScan *create_valuesscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static TableFuncScan *create_tablefuncscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static CteScan *create_ctescan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static NamedTuplestoreScan *create_namedtuplestorescan_plan(PlannerInfo *root,
Path *best_path, List *tlist, List *scan_clauses); static Result *create_resultscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static WorkTableScan *create_worktablescan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses); static ForeignScan *create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
List *tlist, List *scan_clauses); static CustomScan *create_customscan_plan(PlannerInfo *root,
CustomPath *best_path,
List *tlist, List *scan_clauses); static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path); static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path); static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path); static Node *replace_nestloop_params(PlannerInfo *root, Node *expr); static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root); staticvoid fix_indexqual_references(PlannerInfo *root, IndexPath *index_path,
List **stripped_indexquals_p,
List **fixed_indexquals_p); static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path); static Node *fix_indexqual_clause(PlannerInfo *root,
IndexOptInfo *index, int indexcol,
Node *clause, List *indexcolnos); static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol); static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *order_qual_clauses(PlannerInfo *root, List *clauses); staticvoid copy_generic_path_info(Plan *dest, Path *src); staticvoid copy_plan_costsize(Plan *dest, Plan *src); staticvoid label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples); staticvoid label_incrementalsort_with_costsize(PlannerInfo *root, IncrementalSort *plan,
List *pathkeys, double limit_tuples); static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); static SampleScan *make_samplescan(List *qptlist, List *qpqual, Index scanrelid,
TableSampleClause *tsc); static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
Oid indexid, List *indexqual, List *indexqualorig,
List *indexorderby, List *indexorderbyorig,
List *indexorderbyops,
ScanDirection indexscandir); static IndexOnlyScan *make_indexonlyscan(List *qptlist, List *qpqual,
Index scanrelid, Oid indexid,
List *indexqual, List *recheckqual,
List *indexorderby,
List *indextlist,
ScanDirection indexscandir); static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
List *indexqual,
List *indexqualorig); static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
List *qpqual,
Plan *lefttree,
List *bitmapqualorig,
Index scanrelid); static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals); static TidRangeScan *make_tidrangescan(List *qptlist, List *qpqual,
Index scanrelid, List *tidrangequals); static SubqueryScan *make_subqueryscan(List *qptlist,
List *qpqual,
Index scanrelid,
Plan *subplan); static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid, List *functions, bool funcordinality); static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
Index scanrelid, List *values_lists); static TableFuncScan *make_tablefuncscan(List *qptlist, List *qpqual,
Index scanrelid, TableFunc *tablefunc); static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam); static NamedTuplestoreScan *make_namedtuplestorescan(List *qptlist, List *qpqual,
Index scanrelid, char *enrname); static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam); static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree, int wtParam,
List *distinctList, long numGroups); static BitmapAnd *make_bitmap_and(List *bitmapplans); static BitmapOr *make_bitmap_or(List *bitmapplans); static NestLoop *make_nestloop(List *tlist,
List *joinclauses, List *otherclauses, List *nestParams,
Plan *lefttree, Plan *righttree,
JoinType jointype, bool inner_unique); static HashJoin *make_hashjoin(List *tlist,
List *joinclauses, List *otherclauses,
List *hashclauses,
List *hashoperators, List *hashcollations,
List *hashkeys,
Plan *lefttree, Plan *righttree,
JoinType jointype, bool inner_unique); static Hash *make_hash(Plan *lefttree,
List *hashkeys,
Oid skewTable,
AttrNumber skewColumn, bool skewInherit); static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses,
List *mergeclauses,
Oid *mergefamilies,
Oid *mergecollations, bool *mergereversals, bool *mergenullsfirst,
Plan *lefttree, Plan *righttree,
JoinType jointype, bool inner_unique, bool skip_mark_restore); static Sort *make_sort(Plan *lefttree, int numCols,
AttrNumber *sortColIdx, Oid *sortOperators,
Oid *collations, bool *nullsFirst); static IncrementalSort *make_incrementalsort(Plan *lefttree, int numCols, int nPresortedCols,
AttrNumber *sortColIdx, Oid *sortOperators,
Oid *collations, bool *nullsFirst); static Plan *prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys,
Relids relids, const AttrNumber *reqColIdx, bool adjust_tlist_in_place, int *p_numsortkeys,
AttrNumber **p_sortColIdx,
Oid **p_sortOperators,
Oid **p_collations, bool **p_nullsFirst); static Sort *make_sort_from_pathkeys(Plan *lefttree, List *pathkeys,
Relids relids); static IncrementalSort *make_incrementalsort_from_pathkeys(Plan *lefttree,
List *pathkeys, Relids relids, int nPresortedCols); static Sort *make_sort_from_groupcols(List *groupcls,
AttrNumber *grpColIdx,
Plan *lefttree); static Material *make_material(Plan *lefttree); static Memoize *make_memoize(Plan *lefttree, Oid *hashoperators,
Oid *collations, List *param_exprs, bool singlerow, bool binary_mode,
uint32 est_entries, Bitmapset *keyparamids); static WindowAgg *make_windowagg(List *tlist, WindowClause *wc, int partNumCols, AttrNumber *partColIdx, Oid *partOperators, Oid *partCollations, int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
List *runCondition, List *qual, bool topWindow,
Plan *lefttree); static Group *make_group(List *tlist, List *qual, int numGroupCols,
AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations,
Plan *lefttree); static Unique *make_unique_from_sortclauses(Plan *lefttree, List *distinctList); static Unique *make_unique_from_pathkeys(Plan *lefttree,
List *pathkeys, int numCols); static Gather *make_gather(List *qptlist, List *qpqual, int nworkers, int rescan_param, bool single_copy, Plan *subplan); static SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy,
List *tlist, Plan *lefttree, Plan *righttree,
List *groupList, long numGroups); static LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam); static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); static ProjectSet *make_project_set(List *tlist, Plan *subplan); static ModifyTable *make_modifytable(PlannerInfo *root, Plan *subplan,
CmdType operation, bool canSetTag,
Index nominalRelation, Index rootRelation, bool partColsUpdated,
List *resultRelations,
List *updateColnosLists,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict,
List *mergeActionLists, List *mergeJoinConditions, int epqParam); static GatherMerge *create_gather_merge_plan(PlannerInfo *root,
GatherMergePath *best_path);
/* Check we successfully assigned all NestLoopParams to plan nodes */ if (root->curOuterParams != NIL)
elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
/* *create_plan_recurse *Recursivegutsofcreate_plan().
*/ static Plan *
create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
{
Plan *plan;
/* Guard against stack overflow due to overly complex plans */
check_stack_depth();
switch (best_path->pathtype)
{ case T_SeqScan: case T_SampleScan: case T_IndexScan: case T_IndexOnlyScan: case T_BitmapHeapScan: case T_TidScan: case T_TidRangeScan: case T_SubqueryScan: case T_FunctionScan: case T_TableFuncScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: case T_NamedTuplestoreScan: case T_ForeignScan: case T_CustomScan:
plan = create_scan_plan(root, best_path, flags); break; case T_HashJoin: case T_MergeJoin: case T_NestLoop:
plan = create_join_plan(root,
(JoinPath *) best_path); break; case T_Append:
plan = create_append_plan(root,
(AppendPath *) best_path,
flags); break; case T_MergeAppend:
plan = create_merge_append_plan(root,
(MergeAppendPath *) best_path,
flags); break; case T_Result: if (IsA(best_path, ProjectionPath))
{
plan = create_projection_plan(root,
(ProjectionPath *) best_path,
flags);
} elseif (IsA(best_path, MinMaxAggPath))
{
plan = (Plan *) create_minmaxagg_plan(root,
(MinMaxAggPath *) best_path);
} elseif (IsA(best_path, GroupResultPath))
{
plan = (Plan *) create_group_result_plan(root,
(GroupResultPath *) best_path);
} else
{ /* Simple RTE_RESULT base relation */
Assert(IsA(best_path, Path));
plan = create_scan_plan(root, best_path, flags);
} break; case T_ProjectSet:
plan = (Plan *) create_project_set_plan(root,
(ProjectSetPath *) best_path); break; case T_Material:
plan = (Plan *) create_material_plan(root,
(MaterialPath *) best_path,
flags); break; case T_Memoize:
plan = (Plan *) create_memoize_plan(root,
(MemoizePath *) best_path,
flags); break; case T_Unique: if (IsA(best_path, UpperUniquePath))
{
plan = (Plan *) create_upper_unique_plan(root,
(UpperUniquePath *) best_path,
flags);
} else
{
Assert(IsA(best_path, UniquePath));
plan = create_unique_plan(root,
(UniquePath *) best_path,
flags);
} break; case T_Gather:
plan = (Plan *) create_gather_plan(root,
(GatherPath *) best_path); break; case T_Sort:
plan = (Plan *) create_sort_plan(root,
(SortPath *) best_path,
flags); break; case T_IncrementalSort:
plan = (Plan *) create_incrementalsort_plan(root,
(IncrementalSortPath *) best_path,
flags); break; case T_Group:
plan = (Plan *) create_group_plan(root,
(GroupPath *) best_path); break; case T_Agg: if (IsA(best_path, GroupingSetsPath))
plan = create_groupingsets_plan(root,
(GroupingSetsPath *) best_path); else
{
Assert(IsA(best_path, AggPath));
plan = (Plan *) create_agg_plan(root,
(AggPath *) best_path);
} break; case T_WindowAgg:
plan = (Plan *) create_windowagg_plan(root,
(WindowAggPath *) best_path); break; case T_SetOp:
plan = (Plan *) create_setop_plan(root,
(SetOpPath *) best_path,
flags); break; case T_RecursiveUnion:
plan = (Plan *) create_recursiveunion_plan(root,
(RecursiveUnionPath *) best_path); break; case T_LockRows:
plan = (Plan *) create_lockrows_plan(root,
(LockRowsPath *) best_path,
flags); break; case T_ModifyTable:
plan = (Plan *) create_modifytable_plan(root,
(ModifyTablePath *) best_path); break; case T_Limit:
plan = (Plan *) create_limit_plan(root,
(LimitPath *) best_path,
flags); break; case T_GatherMerge:
plan = (Plan *) create_gather_merge_plan(root,
(GatherMergePath *) best_path); break; default:
elog(ERROR, "unrecognized node type: %d",
(int) best_path->pathtype);
plan = NULL; /* keep compiler quiet */ break;
}
return plan;
}
/* *create_scan_plan *Createascanplanfortheparentrelationof'best_path'.
*/ static Plan *
create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
{
RelOptInfo *rel = best_path->parent;
List *scan_clauses;
List *gating_clauses;
List *tlist;
Plan *plan;
/* *Can'tdoitifanysystemcolumnsorwhole-rowVarsarerequested. *(Thiscouldpossiblybefixedbutwouldtakesomefragileassumptions *insetrefs.c,Ithink.)
*/ for (i = rel->min_attr; i <= 0; i++)
{ if (!bms_is_empty(rel->attr_needed[i - rel->min_attr])) returnfalse;
}
/* *get_gating_quals *Seeiftherearepseudoconstantqualsinanode'squalslist * *Ifthenode'squalslistincludesanypseudoconstantquals, *returnjustthosequals.
*/ static List *
get_gating_quals(PlannerInfo *root, List *quals)
{ /* No need to look if we know there are no pseudoconstants */ if (!root->hasPseudoConstantQuals) return NIL;
/* Sort into desirable execution order while still in RestrictInfo form */
quals = order_qual_clauses(root, quals);
/* Pull out any pseudoconstant quals from the RestrictInfo list */ return extract_actual_clauses(quals, true);
}
/* *create_gating_plan *Dealwithpseudoconstantqualclauses * *AddagatingResultnodeatopthealready-builtplan.
*/ static Plan *
create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
List *gating_quals)
{
Plan *gplan;
Plan *splan;
Assert(gating_quals);
/* *WemighthaveatrivialResultplanalready.StackingoneResultatop *anotherissilly,soifthatapplies,justdiscardtheinputplan. *(We'reassumingitstargetlistisuninteresting;itshouldbeeither *thesameastheresultofbuild_path_tlist,orasimplifiedversion.)
*/
splan = plan; if (IsA(plan, Result))
{
Result *rplan = (Result *) plan;
/* *create_append_plan *CreateanAppendplanfor'best_path'and(recursively)plans *foritssubpaths. * *ReturnsaPlannode.
*/ static Plan *
create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
{
Append *plan;
List *tlist = build_path_tlist(root, &best_path->path); int orig_tlist_length = list_length(tlist); bool tlist_was_changed = false;
List *pathkeys = best_path->path.pathkeys;
List *subplans = NIL;
ListCell *subpaths; int nasyncplans = 0;
RelOptInfo *rel = best_path->path.parent; int nodenumsortkeys = 0;
AttrNumber *nodeSortColIdx = NULL;
Oid *nodeSortOperators = NULL;
Oid *nodeCollations = NULL; bool *nodeNullsFirst = NULL; bool consider_async = false;
/* *Thesubpathslistcouldbeempty,ifeverychildwasprovenemptyby *constraintexclusion.Inthatcasegenerateadummyplanthatreturns *norows. * *NotethatanAppendPathwithnomembersisalsogeneratedincertain *caseswheretherewasnoappendingconstructatall,butweknowthe *relationisempty(seeset_dummy_rel_pathlistandmark_dummy_rel).
*/ if (best_path->subpaths == NIL)
{ /* Generate a Result plan with constant-FALSE gating qual */
Plan *plan;
plan = (Plan *) make_result(tlist,
(Node *) list_make1(makeBoolConst(false, false)),
NULL);
/* Build the plan for each child */
foreach(subpaths, best_path->subpaths)
{
Path *subpath = (Path *) lfirst(subpaths);
Plan *subplan;
/* Must insist that all children return the same tlist */
subplan = create_plan_recurse(root, subpath, CP_EXACT_TLIST);
/* *FororderedAppends,wemustinsertaSortnodeifsubplanisn't *sufficientlyordered.
*/ if (pathkeys != NIL)
{ int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations; bool *nullsFirst;
/* If needed, check to see if subplan can be executed asynchronously */ if (consider_async && mark_async_capable_plan(subplan, subpath))
{
Assert(subplan->async_capable);
++nasyncplans;
}
subplans = lappend(subplans, subplan);
}
/* Set below if we find quals that we can use to run-time prune */
plan->part_prune_index = -1;
/* *Ifanyqualsexist,theymaybeusefultoperformfurtherpartition *pruningduringexecution.Gatherinformationneededbytheexecutorto *dopartitionpruning.
*/ if (enable_partition_pruning)
{
List *prunequal;
/* Set below if we find quals that we can use to run-time prune */
node->part_prune_index = -1;
/* *Ifanyqualsexist,theymaybeusefultoperformfurtherpartition *pruningduringexecution.Gatherinformationneededbytheexecutorto *dopartitionpruning.
*/ if (enable_partition_pruning)
{
List *prunequal;
/* *create_unique_plan *CreateaUniqueplanfor'best_path'and(recursively)plans *foritssubpaths. * *ReturnsaPlannode.
*/ static Plan *
create_unique_plan(PlannerInfo *root, UniquePath *best_path, int flags)
{
Plan *plan;
Plan *subplan;
List *in_operators;
List *uniq_exprs;
List *newtlist; int nextresno; bool newitems; int numGroupCols;
AttrNumber *groupColIdx;
Oid *groupCollations; int groupColPos;
ListCell *l;
/* Unique doesn't project, so tlist requirements pass through */
subplan = create_plan_recurse(root, best_path->subpath, flags);
/* Done if we don't need to do any actual unique-ifying */ if (best_path->umethod == UNIQUE_PATH_NOOP) return subplan;
tle = tlist_member(uniqexpr, newtlist); if (!tle)
{
tle = makeTargetEntry((Expr *) uniqexpr,
nextresno,
NULL, false);
newtlist = lappend(newtlist, tle);
nextresno++;
newitems = true;
}
}
/* Use change_plan_targetlist in case we need to insert a Result node */ if (newitems || best_path->umethod == UNIQUE_PATH_SORT)
subplan = change_plan_targetlist(subplan, newtlist,
best_path->path.parallel_safe);
/* Create an ORDER BY list to sort the input compatibly */
groupColPos = 0;
foreach(l, in_operators)
{
Oid in_oper = lfirst_oid(l);
Oid sortop;
Oid eqop;
TargetEntry *tle;
SortGroupClause *sortcl;
sortop = get_ordering_op_for_equality_op(in_oper, false); if (!OidIsValid(sortop)) /* shouldn't happen */
elog(ERROR, "could not find ordering operator for equality operator %u",
in_oper);
/* *TheUniquenodewillneedequalityoperators.Normallythese *arethesameastheINclauseoperators,butifthoseare *cross-typeoperatorsthentheequalityoperatorsaretheones *fortheINclauseoperators'RHSdatatype.
*/
eqop = get_equality_op_for_ordering_op(sortop, NULL); if (!OidIsValid(eqop)) /* shouldn't happen */
elog(ERROR, "could not find equality operator for ordering operator %u",
sortop);
tle = get_tle_by_resno(subplan->targetlist,
groupColIdx[groupColPos]);
Assert(tle != NULL);
sortcl = makeNode(SortGroupClause);
sortcl->tleSortGroupRef = assignSortGroupRef(tle,
subplan->targetlist);
sortcl->eqop = eqop;
sortcl->sortop = sortop;
sortcl->reverse_sort = false;
sortcl->nulls_first = false;
sortcl->hashable = false; /* no need to make this accurate */
sortList = lappend(sortList, sortcl);
groupColPos++;
}
sort = make_sort_from_sortclauses(sortList, subplan);
label_sort_with_costsize(root, sort, -1.0);
plan = (Plan *) make_unique_from_sortclauses((Plan *) sort, sortList);
}
/* Copy cost data from Path to Plan */
copy_generic_path_info(plan, &best_path->path);
return plan;
}
/* *create_gather_plan * *CreateaGatherplanfor'best_path'and(recursively)plans *foritssubpaths.
*/ static Gather *
create_gather_plan(PlannerInfo *root, GatherPath *best_path)
{
Gather *gather_plan;
Plan *subplan;
List *tlist;
/* *IfwemakeadifferentdecisionaboutwhethertoincludeaResultnode *thancreate_projection_pathdid,we'llhavemadeslightlywrongcost *estimates;butlabeltheplanwiththecostestimatesweactuallyused, *not"corrected"ones.(XXXthiscouldbecleanedupifwemovedmore *ofthesortcolumnsetuplogicintoPathcreation,butthatwouldadd *expensetocreatingPathswemightendupnotusing.)
*/ if (!needs_result_node)
{ /* Don't need a separate Result, just assign tlist to subplan */
plan = subplan;
plan->targetlist = tlist;
/* Label plan with the estimated costs we actually used */
plan->startup_cost = best_path->path.startup_cost;
plan->total_cost = best_path->path.total_cost;
plan->plan_rows = best_path->path.rows;
plan->plan_width = best_path->path.pathtarget->width;
plan->parallel_safe = best_path->path.parallel_safe; /* ... but don't change subplan's parallel_aware flag */
} else
{ /* We need a Result node */
plan = (Plan *) make_result(tlist, NULL, subplan);
/* *create_group_plan * *CreateaGroupplanfor'best_path'and(recursively)plans *foritssubpaths.
*/ static Group *
create_group_plan(PlannerInfo *root, GroupPath *best_path)
{
Group *plan;
Plan *subplan;
List *tlist;
List *quals;
/* *create_windowagg_plan * *CreateaWindowAggplanfor'best_path'and(recursively)plans *foritssubpaths.
*/ static WindowAgg *
create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path)
{
WindowAgg *plan;
WindowClause *wc = best_path->winclause; int numPart = list_length(wc->partitionClause); int numOrder = list_length(wc->orderClause);
Plan *subplan;
List *tlist; int partNumCols;
AttrNumber *partColIdx;
Oid *partOperators;
Oid *partCollations; int ordNumCols;
AttrNumber *ordColIdx;
Oid *ordOperators;
Oid *ordCollations;
ListCell *lc;
/* And finally we can make the WindowAgg node */
plan = make_windowagg(tlist,
wc,
partNumCols,
partColIdx,
partOperators,
partCollations,
ordNumCols,
ordColIdx,
ordOperators,
ordCollations,
best_path->runCondition,
best_path->qual,
best_path->topwindow,
subplan);
/* *create_recursiveunion_plan * *CreateaRecursiveUnionplanfor'best_path'and(recursively)plans *foritssubpaths.
*/ static RecursiveUnion *
create_recursiveunion_plan(PlannerInfo *root, RecursiveUnionPath *best_path)
{
RecursiveUnion *plan;
Plan *leftplan;
Plan *rightplan;
List *tlist; long numGroups;
/* Need both children to produce same tlist, so force it */
leftplan = create_plan_recurse(root, best_path->leftpath, CP_EXACT_TLIST);
rightplan = create_plan_recurse(root, best_path->rightpath, CP_EXACT_TLIST);
tlist = build_path_tlist(root, &best_path->path);
/* Convert numGroups to long int --- but 'ware overflow! */
numGroups = clamp_cardinality_to_long(best_path->numGroups);
plan = make_recursive_union(tlist,
leftplan,
rightplan,
best_path->wtParam,
best_path->distinctList,
numGroups);
/* *create_limit_plan * *CreateaLimitplanfor'best_path'and(recursively)plans *foritssubpaths.
*/ static Limit *
create_limit_plan(PlannerInfo *root, LimitPath *best_path, int flags)
{
Limit *plan;
Plan *subplan; int numUniqkeys = 0;
AttrNumber *uniqColIdx = NULL;
Oid *uniqOperators = NULL;
Oid *uniqCollations = NULL;
/* Limit doesn't project, so tlist requirements pass through */
subplan = create_plan_recurse(root, best_path->subpath, flags);
/* Extract information necessary for comparing rows for WITH TIES. */ if (best_path->limitOption == LIMIT_OPTION_WITH_TIES)
{
Query *parse = root->parse;
ListCell *l;
/* *create_samplescan_plan *Returnsasamplescanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'.
*/ static SampleScan *
create_samplescan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
SampleScan *scan_plan;
Index scan_relid = best_path->parent->relid;
RangeTblEntry *rte;
TableSampleClause *tsc;
/* it should be a base rel with a tablesample clause... */
Assert(scan_relid > 0);
rte = planner_rt_fetch(scan_relid, root);
Assert(rte->rtekind == RTE_RELATION);
tsc = rte->tablesample;
Assert(tsc != NULL);
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */ if (best_path->param_info)
{
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses);
tsc = (TableSampleClause *)
replace_nestloop_params(root, (Node *) tsc);
}
/* *create_indexscan_plan *Returnsanindexscanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'. * *WeusethisforbothplainIndexScansandIndexOnlyScans,becausethe *qualpreprocessingworkisthesameforboth.Notethatthecallertells *uswhichtobuild---wedon'tlookatbest_path->path.pathtype,because *create_bitmap_subplanneedstobeabletooverridethepriordecision.
*/ static Scan *
create_indexscan_plan(PlannerInfo *root,
IndexPath *best_path,
List *tlist,
List *scan_clauses, bool indexonly)
{
Scan *scan_plan;
List *indexclauses = best_path->indexclauses;
List *indexorderbys = best_path->indexorderbys;
Index baserelid = best_path->path.parent->relid;
IndexOptInfo *indexinfo = best_path->indexinfo;
Oid indexoid = indexinfo->indexoid;
List *qpqual;
List *stripped_indexquals;
List *fixed_indexquals;
List *fixed_indexorderbys;
List *indexorderbyops = NIL;
ListCell *l;
/* it should be a base rel... */
Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION); /* check the scan direction is valid */
Assert(best_path->indexscandir == ForwardScanDirection ||
best_path->indexscandir == BackwardScanDirection);
if (rinfo->pseudoconstant) continue; /* we may drop pseudoconstants here */ if (is_redundant_with_indexclauses(rinfo, indexclauses)) continue; /* dup or derived from same EquivalenceClass */ if (!contain_mutable_functions((Node *) rinfo->clause) &&
predicate_implied_by(list_make1(rinfo->clause), stripped_indexquals, false)) continue; /* provably implied by indexquals */
qpqual = lappend(qpqual, rinfo);
}
/* Sort clauses into best execution order */
qpqual = order_qual_clauses(root, qpqual);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
qpqual = extract_actual_clauses(qpqual, false);
/* Get sort operator from opfamily */
sortop = get_opfamily_member_for_cmptype(pathkey->pk_opfamily,
exprtype,
exprtype,
pathkey->pk_cmptype); if (!OidIsValid(sortop))
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
pathkey->pk_cmptype, exprtype, exprtype, pathkey->pk_opfamily);
indexorderbyops = lappend_oid(indexorderbyops, sortop);
}
}
/* *Foranindex-onlyscan,wemustmarkindextlistentriesasresjunkif *theyarecolumnsthattheindexAMcan'treturn;thiscuessetrefs.cto *notgeneratereferencestothosecolumns.
*/ if (indexonly)
{ int i = 0;
/* *create_bitmap_scan_plan *Returnsabitmapscanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'.
*/ static BitmapHeapScan *
create_bitmap_scan_plan(PlannerInfo *root,
BitmapHeapPath *best_path,
List *tlist,
List *scan_clauses)
{
Index baserelid = best_path->path.parent->relid;
Plan *bitmapqualplan;
List *bitmapqualorig;
List *indexquals;
List *indexECs;
List *qpqual;
ListCell *l;
BitmapHeapScan *scan_plan;
/* it should be a base rel... */
Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
/* Process the bitmapqual tree into a Plan tree and qual lists */
bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
&bitmapqualorig, &indexquals,
&indexECs);
if (best_path->path.parallel_aware)
bitmap_subplan_mark_shared(bitmapqualplan);
if (rinfo->pseudoconstant) continue; /* we may drop pseudoconstants here */ if (list_member(indexquals, clause)) continue; /* simple duplicate */ if (rinfo->parent_ec && list_member_ptr(indexECs, rinfo->parent_ec)) continue; /* derived from same EquivalenceClass */ if (!contain_mutable_functions(clause) &&
predicate_implied_by(list_make1(clause), indexquals, false)) continue; /* provably implied by indexquals */
qpqual = lappend(qpqual, rinfo);
}
/* Sort clauses into best execution order */
qpqual = order_qual_clauses(root, qpqual);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
qpqual = extract_actual_clauses(qpqual, false);
/* *Givenabitmapqualtree,generatethePlantreethatimplementsit * *Asbyproducts,wealsoreturnin*qualand*indexqualthequallists *(inimplicit-ANDform,withoutRestrictInfos)describingtheoriginalindex *conditionsandthegeneratedindexqualconditions.(Thesearethesamein *simplecases,butwhenspecialindexoperatorsareinvolved,theformer *listincludesthespecialconditionswhilethelatterincludestheactual *indexableconditionsderivedfromthem.)Bothlistsincludepartial-index *predicates,becausewehavetorecheckpredicatesaswellasindex *conditionsifthebitmapscanbecomeslossy. * *Inaddition,wereturnalistofEquivalenceClasspointersforallthe *top-levelindexqualsthatwerepossibly-redundantlyderivedfromECs. *Thisallowsremovalofscan_clausesthatareredundantwithsuchquals. *(Wedonotattempttodetectsuchredundanciesforqualsthatarewithin *ORsubtrees.Thiscouldbedoneinalesshackywayifwereturnedthe *indexqualsinRestrictInfoform,butthatwouldbeslowerandstillpretty *messy,sincewe'dhavetobuildnewRestrictInfosinmanycases.)
*/ static Plan *
create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual, List **indexqual, List **indexECs)
{
Plan *plan;
if (IsA(bitmapqual, BitmapAndPath))
{
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
List *subplans = NIL;
List *subquals = NIL;
List *subindexquals = NIL;
List *subindexECs = NIL;
ListCell *l;
/* *Theremaywellberedundantqualsamongthesubplans,sincea *top-levelWHEREqualmighthavegottenusedtoformseveral *differentindexquals.Wedon'ttryexceedinglyhardtoeliminate *redundancies,butwedoeliminateobviousduplicatesbyusing *list_concat_unique.
*/
foreach(l, apath->bitmapquals)
{
Plan *subplan;
List *subqual;
List *subindexqual;
List *subindexEC;
/* *Here,weonlydetectqual-freesubplans.Aqual-freesubplanwould *causeustogenerate"...ORtrue..."whichwemayaswellreduce *tojust"true".Wedonottrytoeliminateredundantsubclauses *because(a)it'snotaslikelyasintheANDcase,and(b)wemight *wellbeworkingwithhundredsoreventhousandsofORconditions, *perhapsfromalongINlist.Theperformanceoflist_append_unique *wouldbeunacceptable.
*/
foreach(l, opath->bitmapquals)
{
Plan *subplan;
List *subqual;
List *subindexqual;
List *subindexEC;
if (rinfo->pseudoconstant) continue; /* we may drop pseudoconstants here */ if (list_member_ptr(tidquals, rinfo)) continue; /* simple duplicate */ if (is_redundant_derived_clause(rinfo, tidquals)) continue; /* derived from same EquivalenceClass */
qpqual = lappend(qpqual, rinfo);
}
scan_clauses = qpqual;
}
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo lists to bare expressions; ignore pseudoconstants */
tidquals = extract_actual_clauses(tidquals, false);
scan_clauses = extract_actual_clauses(scan_clauses, false);
if (rinfo->pseudoconstant) continue; /* we may drop pseudoconstants here */ if (list_member_ptr(tidrangequals, rinfo)) continue; /* simple duplicate */
qpqual = lappend(qpqual, rinfo);
}
scan_clauses = qpqual;
}
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo lists to bare expressions; ignore pseudoconstants */
tidrangequals = extract_actual_clauses(tidrangequals, false);
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */ if (best_path->path.param_info)
{
tidrangequals = (List *)
replace_nestloop_params(root, (Node *) tidrangequals);
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses);
}
/* *create_functionscan_plan *Returnsafunctionscanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'.
*/ static FunctionScan *
create_functionscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
FunctionScan *scan_plan;
Index scan_relid = best_path->parent->relid;
RangeTblEntry *rte;
List *functions;
/* it should be a function base rel... */
Assert(scan_relid > 0);
rte = planner_rt_fetch(scan_relid, root);
Assert(rte->rtekind == RTE_FUNCTION);
functions = rte->functions;
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */ if (best_path->param_info)
{
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses); /* The function expressions could contain nestloop params, too */
functions = (List *) replace_nestloop_params(root, (Node *) functions);
}
/* *create_tablefuncscan_plan *Returnsatablefuncscanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'.
*/ static TableFuncScan *
create_tablefuncscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
TableFuncScan *scan_plan;
Index scan_relid = best_path->parent->relid;
RangeTblEntry *rte;
TableFunc *tablefunc;
/* it should be a function base rel... */
Assert(scan_relid > 0);
rte = planner_rt_fetch(scan_relid, root);
Assert(rte->rtekind == RTE_TABLEFUNC);
tablefunc = rte->tablefunc;
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */ if (best_path->param_info)
{
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses); /* The function expressions could contain nestloop params, too */
tablefunc = (TableFunc *) replace_nestloop_params(root, (Node *) tablefunc);
}
/* *create_valuesscan_plan *Returnsavaluesscanplanforthebaserelationscannedby'best_path' *withrestrictionclauses'scan_clauses'andtargetlist'tlist'.
*/ static ValuesScan *
create_valuesscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
ValuesScan *scan_plan;
Index scan_relid = best_path->parent->relid;
RangeTblEntry *rte;
List *values_lists;
/* it should be a values base rel... */
Assert(scan_relid > 0);
rte = planner_rt_fetch(scan_relid, root);
Assert(rte->rtekind == RTE_VALUES);
values_lists = rte->values_lists;
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */ if (best_path->param_info)
{
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses); /* The values lists could contain nestloop params, too */
values_lists = (List *)
replace_nestloop_params(root, (Node *) values_lists);
}
if (strcmp(cte->ctename, rte->ctename) == 0) break;
ndx++;
} if (lc == NULL) /* shouldn't happen */
elog(ERROR, "could not find CTE \"%s\"", rte->ctename); if (ndx >= list_length(cteroot->cte_plan_ids))
elog(ERROR, "could not find plan for CTE \"%s\"", rte->ctename);
plan_id = list_nth_int(cteroot->cte_plan_ids, ndx); if (plan_id <= 0)
elog(ERROR, "no plan was made for CTE \"%s\"", rte->ctename);
foreach(lc, cteroot->init_plans)
{
ctesplan = (SubPlan *) lfirst(lc); if (ctesplan->plan_id == plan_id) break;
} if (lc == NULL) /* shouldn't happen */
elog(ERROR, "could not find plan for CTE \"%s\"", rte->ctename);
/* Now, are any system columns requested from rel? */ for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
{ if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber, attrs_used))
{
scan_plan->fsSystemCol = true; break;
}
}
bms_free(attrs_used);
}
return scan_plan;
}
/* *create_customscan_plan * *TransformaCustomPathintoaPlan.
*/ static CustomScan *
create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
List *tlist, List *scan_clauses)
{
CustomScan *cplan;
RelOptInfo *rel = best_path->path.parent;
List *custom_plans = NIL;
ListCell *lc;
/* NestLoop can project, so no need to be picky about child tlists */
outer_plan = create_plan_recurse(root, best_path->jpath.outerjoinpath, 0);
/* For a nestloop, include outer relids in curOuterRels for inner side */
outerrelids = best_path->jpath.outerjoinpath->parent->relids;
root->curOuterRels = bms_union(root->curOuterRels, outerrelids);
/* Sort join qual clauses into best execution order */
joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses);
/* Get the join qual clauses (in plain expression form) */ /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jpath.jointype))
{
extract_actual_join_clauses(joinrestrictclauses,
best_path->jpath.path.parent->relids,
&joinclauses, &otherclauses);
} else
{ /* We can treat all clauses alike for an inner join */
joinclauses = extract_actual_clauses(joinrestrictclauses, false);
otherclauses = NIL;
}
/* Replace any outer-relation variables with nestloop params */ if (best_path->jpath.path.param_info)
{
joinclauses = (List *)
replace_nestloop_params(root, (Node *) joinclauses);
otherclauses = (List *)
replace_nestloop_params(root, (Node *) otherclauses);
}
if (IsA(nlp->paramval, Var)) continue; /* nothing to do for simple Vars */ /* Otherwise it must be a PHV */
phv = castNode(PlaceHolderVar, nlp->paramval);
if (tlist_member((Expr *) phv, outer_tlist)) continue; /* already available */
/* Make a shallow copy of outer_tlist, if we didn't already */ if (outer_tlist == outer_plan->targetlist)
outer_tlist = list_copy(outer_tlist); /* ... and add the needed expression */
tle = makeTargetEntry((Expr *) copyObject(phv),
list_length(outer_tlist) + 1,
NULL, true);
outer_tlist = lappend(outer_tlist, tle); /* ... and track whether tlist is (still) parallel-safe */ if (outer_parallel_safe)
outer_parallel_safe = is_parallel_safe(root, (Node *) phv);
} if (outer_tlist != outer_plan->targetlist)
outer_plan = change_plan_targetlist(outer_plan, outer_tlist,
outer_parallel_safe);
/* And finally, we can build the join plan node */
join_plan = make_nestloop(tlist,
joinclauses,
otherclauses,
nestParams,
outer_plan,
inner_plan,
best_path->jpath.jointype,
best_path->jpath.inner_unique);
static MergeJoin *
create_mergejoin_plan(PlannerInfo *root,
MergePath *best_path)
{
MergeJoin *join_plan;
Plan *outer_plan;
Plan *inner_plan;
List *tlist = build_path_tlist(root, &best_path->jpath.path);
List *joinclauses;
List *otherclauses;
List *mergeclauses;
List *outerpathkeys;
List *innerpathkeys; int nClauses;
Oid *mergefamilies;
Oid *mergecollations; bool *mergereversals; bool *mergenullsfirst;
PathKey *opathkey;
EquivalenceClass *opeclass; int i;
ListCell *lc;
ListCell *lop;
ListCell *lip;
Path *outer_path = best_path->jpath.outerjoinpath;
Path *inner_path = best_path->jpath.innerjoinpath;
/* Sort join qual clauses into best execution order */ /* NB: do NOT reorder the mergeclauses */
joinclauses = order_qual_clauses(root, best_path->jpath.joinrestrictinfo);
/* Get the join qual clauses (in plain expression form) */ /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jpath.jointype))
{
extract_actual_join_clauses(joinclauses,
best_path->jpath.path.parent->relids,
&joinclauses, &otherclauses);
} else
{ /* We can treat all clauses alike for an inner join */
joinclauses = extract_actual_clauses(joinclauses, false);
otherclauses = NIL;
}
/* *Wemustidentifythepathkeyelementsassociatedwiththisclause *bymatchingtheeclasses(whichshouldgiveauniquematch,since *thepathkeylistsshouldbecanonical).Intypicalcasesthemerge *clausesareone-to-onewiththepathkeys,butwhendealingwith *partiallyredundantqueryconditions,thingsaremorecomplicated. * *lopandlipreferencethefirstas-yet-unmatchedpathkeyelements. *Ifthey'reNULLthenallpathkeyelementshavebeenmatched. * *Theorderingoftheouterpathkeysshouldmatchthemergeclauses, *byconstruction(seefind_mergeclauses_for_outer_pathkeys()).There *couldbemorethanonemergeclauseforthesameouterpathkey,but *nopathkeymaybeentirelyskippedover.
*/ if (oeclass != opeclass) /* multiple matches are not interesting */
{ /* doesn't match the current opathkey, so must match the next */ if (lop == NULL)
elog(ERROR, "outer pathkeys do not match mergeclauses");
opathkey = (PathKey *) lfirst(lop);
opeclass = opathkey->pk_eclass;
lop = lnext(outerpathkeys, lop); if (oeclass != opeclass)
elog(ERROR, "outer pathkeys do not match mergeclauses");
}
/* *Theinnerpathkeyslikewiseshouldnothaveskipped-overkeys,but *it'spossibleforamergeclausetoreferencesomeearlierinner *pathkeyifwehadredundantpathkeys.Forexamplewemighthave *mergeclauseslike"o.a=i.xANDo.b=i.yANDo.c=i.x".The *impliedinnerorderingisthen"ORDERBYx,y,x",butthepathkey *mechanismdropsthesecondsortbyxasredundant,andthiscode *mustcope. * *It'salsopossiblefortheimpliedinner-relorderingtobelike *"ORDERBYx,y,xDESC".Westilldropthesecondinstanceofxas *redundant;butthismeansthatthesortorderingofaredundant *innerpathkeyshouldnotbeconsideredsignificant.Sowemust *detectwhetherthisisthefirstclausematchinganinnerpathkey.
*/ if (lip)
{
ipathkey = (PathKey *) lfirst(lip);
ipeclass = ipathkey->pk_eclass; if (ieclass == ipeclass)
{ /* successful first match to this inner pathkey */
lip = lnext(innerpathkeys, lip);
first_inner_match = true;
}
} if (!first_inner_match)
{ /* redundant clause ... must match something before lip */
ListCell *l2;
foreach(l2, innerpathkeys)
{ if (l2 == lip) break;
ipathkey = (PathKey *) lfirst(l2);
ipeclass = ipathkey->pk_eclass; if (ieclass == ipeclass) break;
} if (ieclass != ipeclass)
elog(ERROR, "inner pathkeys do not match mergeclauses");
}
/* *Thepathkeysshouldalwaysmatcheachotherastoopfamilyand *collation(whichaffectequality),butifwe'reconsideringa *redundantinnerpathkey,itssortorderingmightnotmatch.In *suchcaseswemayignoretheinnerpathkey'ssortorderinganduse *theouter's.(Ineffect,we'relyingtotheexecutoraboutthe *sortdirectionofthisinnercolumn,butitdoesnotmattersince *therun-timerowcomparisonswouldonlyreachthiscolumnwhen *there'sequalityfortheearliercolumncontainingthesameeclass. *Therecouldbeonlyonevalueinthiscolumnfortherangeofinner *rowshavingagivenvalueintheearliercolumn,soitdoesnot *matterwhichwayweimaginethiscolumntobeordered.)Buta *non-redundantinnerpathkeyhadbettermatchouter'sorderingtoo.
*/ if (opathkey->pk_opfamily != ipathkey->pk_opfamily ||
opathkey->pk_eclass->ec_collation != ipathkey->pk_eclass->ec_collation)
elog(ERROR, "left and right pathkeys do not match in mergejoin"); if (first_inner_match &&
(opathkey->pk_cmptype != ipathkey->pk_cmptype ||
opathkey->pk_nulls_first != ipathkey->pk_nulls_first))
elog(ERROR, "left and right pathkeys do not match in mergejoin");
/* OK, save info for executor */
mergefamilies[i] = opathkey->pk_opfamily;
mergecollations[i] = opathkey->pk_eclass->ec_collation;
mergereversals[i] = (opathkey->pk_cmptype == COMPARE_GT ? true : false);
mergenullsfirst[i] = opathkey->pk_nulls_first;
i++;
}
/* Sort join qual clauses into best execution order */
joinclauses = order_qual_clauses(root, best_path->jpath.joinrestrictinfo); /* There's no point in sorting the hash clauses ... */
/* Get the join qual clauses (in plain expression form) */ /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jpath.jointype))
{
extract_actual_join_clauses(joinclauses,
best_path->jpath.path.parent->relids,
&joinclauses, &otherclauses);
} else
{ /* We can treat all clauses alike for an inner join */
joinclauses = extract_actual_clauses(joinclauses, false);
otherclauses = NIL;
}
/* *replace_nestloop_params *Replaceouter-relationVarsandPlaceHolderVarsinthegivenexpression *withnestloopParams * *AllVarsandPlaceHolderVarsbelongingtotherelation(s)identifiedby *root->curOuterRelsarereplacedbyParams,andentriesareaddedto *root->curOuterParamsifnotalreadypresent.
*/ static Node *
replace_nestloop_params(PlannerInfo *root, Node *expr)
{ /* No setup needed for tree walk, so away we go */ return replace_nestloop_params_mutator(expr, root);
}
static Node *
replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
/* Upper-level Vars should be long gone at this point */
Assert(var->varlevelsup == 0); /* If not to be replaced, we can just return the Var unmodified */ if (IS_SPECIAL_VARNO(var->varno) ||
!bms_is_member(var->varno, root->curOuterRels)) return node; /* Replace the Var with a nestloop Param */ return (Node *) replace_nestloop_param_var(root, var);
} if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
/* Upper-level PlaceHolderVars should be long gone at this point */
Assert(phv->phlevelsup == 0);
/* Check whether we need to replace the PHV */ if (!bms_is_subset(find_placeholder_info(root, phv)->ph_eval_at,
root->curOuterRels))
{ /* *Wecan'treplacethewholePHV,butwemightstillneedto *replaceVarsorPHVswithinitsexpression,incaseitendsup *actuallygettingevaluatedhere.(Itmightgetevaluatedin *thisplannode,orsomechildnode;inthelattercasewedon't *reallyneedtoprocesstheexpressionhere,butwehaven'tgot *enoughinfototellifthat'sthecase.)Flat-copythePHV *nodeandthenrecurseonitsexpression. * *Notethatafterdoingthis,wemighthavedifferent *representationsofthecontentsofthesamePHVindifferent *partsoftheplantree.ThisisOKbecauseequal()willjust *matchonphid/phlevelsup,sosetrefs.cwillstillrecognizean *upper-levelreferencetoalower-levelcopyofthesamePHV.
*/
PlaceHolderVar *newphv = makeNode(PlaceHolderVar);
if (index->indexkeys[indexcol] != 0)
{ /* It's a simple index column */ if (IsA(node, Var) &&
((Var *) node)->varno == index->rel->relid &&
((Var *) node)->varattno == index->indexkeys[indexcol])
{
result = (Var *) copyObject(node);
result->varno = INDEX_VAR;
result->varattno = indexcol + 1; return (Node *) result;
} else
elog(ERROR, "index key does not match expected index column");
}
/* It's an index expression, so find and cross-check the expression */
indexpr_item = list_head(index->indexprs); for (pos = 0; pos < index->ncolumns; pos++)
{ if (index->indexkeys[pos] == 0)
{ if (indexpr_item == NULL)
elog(ERROR, "too few entries in indexprs list"); if (pos == indexcol)
{
Node *indexkey;
indexkey = (Node *) lfirst(indexpr_item); if (indexkey && IsA(indexkey, RelabelType))
indexkey = (Node *) ((RelabelType *) indexkey)->arg; if (equal(node, indexkey))
{
result = makeVar(INDEX_VAR, indexcol + 1,
exprType(lfirst(indexpr_item)), -1,
exprCollation(lfirst(indexpr_item)), 0); return (Node *) result;
} else
elog(ERROR, "index key does not match expected index column");
}
indexpr_item = lnext(index->indexprs, indexpr_item);
}
}
/* Oops... */
elog(ERROR, "index key does not match expected index column"); return NULL; /* keep compiler quiet */
}
/* *Sort.Wedon'tuseqsort()becauseit'snotguaranteedstablefor *equalkeys.Theexpectednumberofentriesissmallenoughthata *simpleinsertionsortshouldbegoodenough.
*/ for (i = 1; i < nitems; i++)
{
QualItem newitem = items[i]; int j;
/* insert newitem into the already-sorted subarray */ for (j = i; j > 0; j--)
{
QualItem *olditem = &items[j - 1];
static IndexScan *
make_indexscan(List *qptlist,
List *qpqual,
Index scanrelid,
Oid indexid,
List *indexqual,
List *indexqualorig,
List *indexorderby,
List *indexorderbyorig,
List *indexorderbyops,
ScanDirection indexscandir)
{
IndexScan *node = makeNode(IndexScan);
Plan *plan = &node->scan.plan;
static IndexOnlyScan *
make_indexonlyscan(List *qptlist,
List *qpqual,
Index scanrelid,
Oid indexid,
List *indexqual,
List *recheckqual,
List *indexorderby,
List *indextlist,
ScanDirection indexscandir)
{
IndexOnlyScan *node = makeNode(IndexOnlyScan);
Plan *plan = &node->scan.plan;
static BitmapIndexScan *
make_bitmap_indexscan(Index scanrelid,
Oid indexid,
List *indexqual,
List *indexqualorig)
{
BitmapIndexScan *node = makeNode(BitmapIndexScan);
Plan *plan = &node->scan.plan;
plan->targetlist = NIL; /* not used */
plan->qual = NIL; /* not used */
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->indexid = indexid;
node->indexqual = indexqual;
node->indexqualorig = indexqualorig;
return node;
}
static BitmapHeapScan *
make_bitmap_heapscan(List *qptlist,
List *qpqual,
Plan *lefttree,
List *bitmapqualorig,
Index scanrelid)
{
BitmapHeapScan *node = makeNode(BitmapHeapScan);
Plan *plan = &node->scan.plan;
static TidScan *
make_tidscan(List *qptlist,
List *qpqual,
Index scanrelid,
List *tidquals)
{
TidScan *node = makeNode(TidScan);
Plan *plan = &node->scan.plan;
static TidRangeScan *
make_tidrangescan(List *qptlist,
List *qpqual,
Index scanrelid,
List *tidrangequals)
{
TidRangeScan *node = makeNode(TidRangeScan);
Plan *plan = &node->scan.plan;
static SubqueryScan *
make_subqueryscan(List *qptlist,
List *qpqual,
Index scanrelid,
Plan *subplan)
{
SubqueryScan *node = makeNode(SubqueryScan);
Plan *plan = &node->scan.plan;
static ValuesScan *
make_valuesscan(List *qptlist,
List *qpqual,
Index scanrelid,
List *values_lists)
{
ValuesScan *node = makeNode(ValuesScan);
Plan *plan = &node->scan.plan;
static CteScan *
make_ctescan(List *qptlist,
List *qpqual,
Index scanrelid, int ctePlanId, int cteParam)
{
CteScan *node = makeNode(CteScan);
Plan *plan = &node->scan.plan;
static NamedTuplestoreScan *
make_namedtuplestorescan(List *qptlist,
List *qpqual,
Index scanrelid, char *enrname)
{
NamedTuplestoreScan *node = makeNode(NamedTuplestoreScan);
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->enrname = enrname;
return node;
}
static WorkTableScan *
make_worktablescan(List *qptlist,
List *qpqual,
Index scanrelid, int wtParam)
{
WorkTableScan *node = makeNode(WorkTableScan);
Plan *plan = &node->scan.plan;
ForeignScan *
make_foreignscan(List *qptlist,
List *qpqual,
Index scanrelid,
List *fdw_exprs,
List *fdw_private,
List *fdw_scan_tlist,
List *fdw_recheck_quals,
Plan *outer_plan)
{
ForeignScan *node = makeNode(ForeignScan);
Plan *plan = &node->scan.plan;
/* cost will be filled in by create_foreignscan_plan */
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = outer_plan;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
/* these may be overridden by the FDW's PlanDirectModify callback. */
node->operation = CMD_SELECT;
node->resultRelation = 0;
/* checkAsUser, fs_server will be filled in by create_foreignscan_plan */
node->checkAsUser = InvalidOid;
node->fs_server = InvalidOid;
node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;
node->fdw_scan_tlist = fdw_scan_tlist;
node->fdw_recheck_quals = fdw_recheck_quals; /* fs_relids, fs_base_relids will be filled by create_foreignscan_plan */
node->fs_relids = NULL;
node->fs_base_relids = NULL; /* fsSystemCol will be filled in by create_foreignscan_plan */
node->fsSystemCol = false;
return node;
}
static RecursiveUnion *
make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree, int wtParam,
List *distinctList, long numGroups)
{
RecursiveUnion *node = makeNode(RecursiveUnion);
Plan *plan = &node->plan; int numCols = list_length(distinctList);
static NestLoop *
make_nestloop(List *tlist,
List *joinclauses,
List *otherclauses,
List *nestParams,
Plan *lefttree,
Plan *righttree,
JoinType jointype, bool inner_unique)
{
NestLoop *node = makeNode(NestLoop);
Plan *plan = &node->join.plan;
static HashJoin *
make_hashjoin(List *tlist,
List *joinclauses,
List *otherclauses,
List *hashclauses,
List *hashoperators,
List *hashcollations,
List *hashkeys,
Plan *lefttree,
Plan *righttree,
JoinType jointype, bool inner_unique)
{
HashJoin *node = makeNode(HashJoin);
Plan *plan = &node->join.plan;
static MergeJoin *
make_mergejoin(List *tlist,
List *joinclauses,
List *otherclauses,
List *mergeclauses,
Oid *mergefamilies,
Oid *mergecollations, bool *mergereversals, bool *mergenullsfirst,
Plan *lefttree,
Plan *righttree,
JoinType jointype, bool inner_unique, bool skip_mark_restore)
{
MergeJoin *node = makeNode(MergeJoin);
Plan *plan = &node->join.plan;
Agg *
make_agg(List *tlist, List *qual,
AggStrategy aggstrategy, AggSplit aggsplit, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations,
List *groupingSets, List *chain, double dNumGroups,
Size transitionSpace, Plan *lefttree)
{
Agg *node = makeNode(Agg);
Plan *plan = &node->plan; long numGroups;
/* Reduce to long, but 'ware overflow! */
numGroups = clamp_cardinality_to_long(dNumGroups);
static WindowAgg *
make_windowagg(List *tlist, WindowClause *wc, int partNumCols, AttrNumber *partColIdx, Oid *partOperators, Oid *partCollations, int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations,
List *runCondition, List *qual, bool topWindow, Plan *lefttree)
{
WindowAgg *node = makeNode(WindowAgg);
Plan *plan = &node->plan;
static Group *
make_group(List *tlist,
List *qual, int numGroupCols,
AttrNumber *grpColIdx,
Oid *grpOperators,
Oid *grpCollations,
Plan *lefttree)
{
Group *node = makeNode(Group);
Plan *plan = &node->plan;
static Gather *
make_gather(List *qptlist,
List *qpqual, int nworkers, int rescan_param, bool single_copy,
Plan *subplan)
{
Gather *node = makeNode(Gather);
Plan *plan = &node->plan;
/* *groupListisalistofSortGroupClauses,identifyingthetargetlist *itemsthatshouldbeconsideredbytheSetOpfilter.Theinputplansmust *alreadybesortedaccordingly,ifwe'redoingSETOP_SORTEDmode.
*/ static SetOp *
make_setop(SetOpCmd cmd, SetOpStrategy strategy,
List *tlist, Plan *lefttree, Plan *righttree,
List *groupList, long numGroups)
{
SetOp *node = makeNode(SetOp);
Plan *plan = &node->plan; int numCols = list_length(groupList); int keyno = 0;
AttrNumber *cmpColIdx;
Oid *cmpOperators;
Oid *cmpCollations; bool *cmpNullsFirst;
ListCell *slitem;
node->plan.lefttree = subplan;
node->plan.righttree = NULL;
node->plan.qual = NIL; /* setrefs.c will fill in the targetlist, if needed */
node->plan.targetlist = NIL;
if (rte->rtekind == RTE_RELATION &&
rte->relkind == RELKIND_FOREIGN_TABLE)
{ /* Check if the access to foreign tables is restricted */ if (unlikely((restrict_nonsystem_relation_kind & RESTRICT_RELKIND_FOREIGN_TABLE) != 0))
{ /* there must not be built-in foreign tables */
Assert(rte->relid >= FirstNormalObjectId);
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("access to non-system foreign table is restricted")));
}
/* *is_projection_capable_path *CheckwhetheragivenPathnodeisabletodoprojection.
*/ bool
is_projection_capable_path(Path *path)
{ /* Most plan types can project, so just list the ones that can't */ switch (path->pathtype)
{ case T_Hash: case T_Material: case T_Memoize: case T_Sort: case T_IncrementalSort: case T_Unique: case T_SetOp: case T_LockRows: case T_Limit: case T_ModifyTable: case T_MergeAppend: case T_RecursiveUnion: returnfalse; case T_CustomScan: if (castNode(CustomPath, path)->flags & CUSTOMPATH_SUPPORT_PROJECTION) returntrue; returnfalse; case T_Append:
/* *Appendcan'tproject,butifanAppendPathisbeingusedto *representadummypath,whatwillactuallybegeneratedisa *Resultwhichcanproject.
*/ return IS_DUMMY_APPEND(path); case T_ProjectSet:
/* *is_projection_capable_plan *CheckwhetheragivenPlannodeisabletodoprojection.
*/ bool
is_projection_capable_plan(Plan *plan)
{ /* Most plan types can project, so just list the ones that can't */ switch (nodeTag(plan))
{ case T_Hash: case T_Material: case T_Memoize: case T_Sort: case T_Unique: case T_SetOp: case T_LockRows: case T_Limit: case T_ModifyTable: case T_Append: case T_MergeAppend: case T_RecursiveUnion: returnfalse; case T_CustomScan: if (((CustomScan *) plan)->flags & CUSTOMPATH_SUPPORT_PROJECTION) returntrue; returnfalse; case T_ProjectSet:
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.366Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.