📄 createplan.c
字号:
* parent-rel Vars it'll be asked to emit. */ if (best_path->subpaths == NIL) { /* Generate a Result plan with constant-FALSE gating qual */ return (Plan *) make_result(tlist, (Node *) list_make1(makeBoolConst(false, false)), NULL); } /* Normal case with multiple subpaths */ foreach(subpaths, best_path->subpaths) { Path *subpath = (Path *) lfirst(subpaths); subplans = lappend(subplans, create_plan(root, subpath)); } plan = make_append(subplans, false, tlist); return (Plan *) plan;}/* * create_result_plan * Create a Result plan for 'best_path' and (recursively) plans * for its subpaths. * * Returns a Plan node. */static Result *create_result_plan(PlannerInfo *root, ResultPath *best_path){ Result *plan; List *tlist; List *constclauses; Plan *subplan; if (best_path->path.parent) tlist = build_relation_tlist(best_path->path.parent); else tlist = NIL; /* will be filled in later */ if (best_path->subpath) subplan = create_plan(root, best_path->subpath); else subplan = NULL; constclauses = order_qual_clauses(root, best_path->constantqual); plan = make_result(tlist, (Node *) constclauses, subplan); return plan;}/* * create_material_plan * Create a Material plan for 'best_path' and (recursively) plans * for its subpaths. * * Returns a Plan node. */static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path){ Material *plan; Plan *subplan; subplan = create_plan(root, best_path->subpath); /* We don't want any excess columns in the materialized tuples */ disuse_physical_tlist(subplan, best_path->subpath); plan = make_material(subplan); copy_path_costsize(&plan->plan, (Path *) best_path); return plan;}/* * create_unique_plan * Create a Unique plan for 'best_path' and (recursively) plans * for its subpaths. * * Returns a Plan node. */static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path){ Plan *plan; Plan *subplan; List *uniq_exprs; List *newtlist; int nextresno; bool newitems; int numGroupCols; AttrNumber *groupColIdx; int groupColPos; ListCell *l; subplan = create_plan(root, best_path->subpath); /* Done if we don't need to do any actual unique-ifying */ if (best_path->umethod == UNIQUE_PATH_NOOP) return subplan; /*---------- * As constructed, the subplan has a "flat" tlist containing just the * Vars needed here and at upper levels. The values we are supposed * to unique-ify may be expressions in these variables. We have to * add any such expressions to the subplan's tlist. * * The subplan may have a "physical" tlist if it is a simple scan plan. * This should be left as-is if we don't need to add any expressions; * but if we do have to add expressions, then a projection step will be * needed at runtime anyway, and so we may as well remove unneeded items. * Therefore newtlist starts from build_relation_tlist() not just a * copy of the subplan's tlist; and we don't install it into the subplan * unless stuff has to be added. * * To find the correct list of values to unique-ify, we look in the * information saved for IN expressions. If this code is ever used in * other scenarios, some other way of finding what to unique-ify will * be needed. *---------- */ uniq_exprs = NIL; /* just to keep compiler quiet */ foreach(l, root->in_info_list) { InClauseInfo *ininfo = (InClauseInfo *) lfirst(l); if (bms_equal(ininfo->righthand, best_path->path.parent->relids)) { uniq_exprs = ininfo->sub_targetlist; break; } } if (l == NULL) /* fell out of loop? */ elog(ERROR, "could not find UniquePath in in_info_list"); /* initialize modified subplan tlist as just the "required" vars */ newtlist = build_relation_tlist(best_path->path.parent); nextresno = list_length(newtlist) + 1; newitems = false; foreach(l, uniq_exprs) { Node *uniqexpr = lfirst(l); TargetEntry *tle; tle = tlist_member(uniqexpr, newtlist); if (!tle) { tle = makeTargetEntry((Expr *) uniqexpr, nextresno, NULL, false); newtlist = lappend(newtlist, tle); nextresno++; newitems = true; } } if (newitems) { /* * If the top plan node can't do projections, we need to add a Result * node to help it along. */ if (!is_projection_capable_plan(subplan)) subplan = (Plan *) make_result(newtlist, NULL, subplan); else subplan->targetlist = newtlist; } /* * Build control information showing which subplan output columns are to * be examined by the grouping step. Unfortunately we can't merge this * with the previous loop, since we didn't then know which version of the * subplan tlist we'd end up using. */ newtlist = subplan->targetlist; numGroupCols = list_length(uniq_exprs); groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber)); groupColPos = 0; foreach(l, uniq_exprs) { Node *uniqexpr = lfirst(l); TargetEntry *tle; tle = tlist_member(uniqexpr, newtlist); if (!tle) /* shouldn't happen */ elog(ERROR, "failed to find unique expression in subplan tlist"); groupColIdx[groupColPos++] = tle->resno; } if (best_path->umethod == UNIQUE_PATH_HASH) { long numGroups; numGroups = (long) Min(best_path->rows, (double) LONG_MAX); /* * Since the Agg node is going to project anyway, we can give it the * minimum output tlist, without any stuff we might have added to the * subplan tlist. */ plan = (Plan *) make_agg(root, build_relation_tlist(best_path->path.parent), NIL, AGG_HASHED, numGroupCols, groupColIdx, numGroups, 0, subplan); } else { List *sortList = NIL; for (groupColPos = 0; groupColPos < numGroupCols; groupColPos++) { TargetEntry *tle; tle = get_tle_by_resno(subplan->targetlist, groupColIdx[groupColPos]); Assert(tle != NULL); sortList = addTargetToSortList(NULL, tle, sortList, subplan->targetlist, SORTBY_ASC, NIL, false); } plan = (Plan *) make_sort_from_sortclauses(root, sortList, subplan); plan = (Plan *) make_unique(plan, sortList); } /* Adjust output size estimate (other fields should be OK already) */ plan->plan_rows = best_path->rows; return plan;}/***************************************************************************** * * BASE-RELATION SCAN METHODS * *****************************************************************************//* * create_seqscan_plan * Returns a seqscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses){ SeqScan *scan_plan; Index scan_relid = best_path->parent->relid; /* it should be a base rel... */ Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_RELATION); /* Reduce RestrictInfo list to bare expressions */ scan_clauses = get_actual_clauses(scan_clauses); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); scan_plan = make_seqscan(tlist, scan_clauses, scan_relid); copy_path_costsize(&scan_plan->plan, best_path); return scan_plan;}/* * create_indexscan_plan * Returns an indexscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. * * The indexquals list of the path contains implicitly-ANDed qual conditions. * The list can be empty --- then no index restrictions will be applied during * the scan. * * If nonlossy_clauses isn't NULL, *nonlossy_clauses receives a list of the * nonlossy indexquals. */static IndexScan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path, List *tlist, List *scan_clauses, List **nonlossy_clauses){ List *indexquals = best_path->indexquals; Index baserelid = best_path->path.parent->relid; Oid indexoid = best_path->indexinfo->indexoid; List *qpqual; List *stripped_indexquals; List *fixed_indexquals; List *nonlossy_indexquals; List *indexstrategy; List *indexsubtype; ListCell *l; IndexScan *scan_plan; /* it should be a base rel... */ Assert(baserelid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); /* * Build "stripped" indexquals structure (no RestrictInfos) to pass to * executor as indexqualorig */ stripped_indexquals = get_actual_clauses(indexquals); /* * The executor needs a copy with the indexkey on the left of each clause * and with index attr numbers substituted for table ones. This pass also * gets strategy info and looks for "lossy" operators. */ fix_indexqual_references(indexquals, best_path, &fixed_indexquals, &nonlossy_indexquals, &indexstrategy, &indexsubtype); /* pass back nonlossy quals if caller wants 'em */ if (nonlossy_clauses) *nonlossy_clauses = nonlossy_indexquals; /* * If this is an innerjoin scan, the indexclauses will contain join * clauses that are not present in scan_clauses (since the passed-in value * is just the rel's baserestrictinfo list). We must add these clauses to * scan_clauses to ensure they get checked. In most cases we will remove * the join clauses again below, but if a join clause contains a special * operator, we need to make sure it gets into the scan_clauses. * * Note: pointer comparison should be enough to determine RestrictInfo * matches. */ if (best_path->isjoininner) scan_clauses = list_union_ptr(scan_clauses, best_path->indexclauses); /* * The qpqual list must contain all restrictions not automatically handled * by the index. All the predicates in the indexquals will be checked * (either by the index itself, or by nodeIndexscan.c), but if there are * any "special" operators involved then they must be included in qpqual. * Also, any lossy index operators must be rechecked in the qpqual. The * upshot is that qpqual must contain scan_clauses minus whatever appears * in nonlossy_indexquals. * * In normal cases simple pointer equality checks will be enough to spot * duplicate RestrictInfos, so we try that first. In some situations * (particularly with OR'd index conditions) we may have scan_clauses that * are not equal to, but are logically implied by, the index quals; so we * also try a predicate_implied_by() check to see if we can discard quals * that way. (predicate_implied_by assumes its first input contains only * immutable functions, so we have to check that.) * * We can also discard quals that are implied by a partial index's * predicate, but only in a plain SELECT; when scanning a target relation * of UPDATE/DELETE/SELECT FOR UPDATE, we must leave such quals in the * plan so that they'll be properly rechecked by EvalPlanQual testing. * * While at it, we strip off the RestrictInfos to produce a list of plain * expressions. */ qpqual = NIL; foreach(l, scan_clauses) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); Assert(IsA(rinfo, RestrictInfo)); if (list_member_ptr(nonlossy_indexquals, rinfo)) continue; if (!contain_mutable_functions((Node *) rinfo->clause)) { List *clausel = list_make1(rinfo->clause); if (predicate_implied_by(clausel, nonlossy_indexquals)) continue; if (best_path->indexinfo->indpred) { if (baserelid != root->parse->resultRelation && !list_member_int(root->parse->rowMarks, baserelid)) if (predicate_implied_by(clausel, best_path->indexinfo->indpred)) continue; } } qpqual = lappend(qpqual, rinfo->clause); } /* Sort clauses into best execution order */ qpqual = order_qual_clauses(root, qpqual); /* Finally ready to build the plan node */ scan_plan = make_indexscan(tlist, qpqual, baserelid, indexoid, fixed_indexquals, stripped_indexquals, indexstrategy, indexsubtype, best_path->indexscandir); copy_path_costsize(&scan_plan->scan.plan, &best_path->path); /* use the indexscan-specific rows estimate, not the parent rel's */ scan_plan->scan.plan.plan_rows = best_path->rows; return scan_plan;}/* * create_bitmap_scan_plan * Returns a bitmap scan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist '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 *qpqual; ListCell *l; BitmapHeapScan *scan_plan; /* it should be a base rel... */ Assert(baserelid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -