📄 createplan.c
字号:
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(Query *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->targetlist, 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(Query *root, UniquePath *best_path){ Plan *plan; Plan *subplan; List *uniq_exprs; int numGroupCols; AttrNumber *groupColIdx; int groupColPos; List *newtlist; int nextresno; bool newitems; List *my_tlist; List *l; subplan = create_plan(root, best_path->subpath); /* * 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. We then build * control information showing which subplan output columns are to be * examined by the grouping step. (Since we do not remove any * existing subplan outputs, not all the output columns may be used * for grouping.) * * Note: the reason we don't remove any subplan outputs is that there are * scenarios where a Var is needed at higher levels even though it is * not one of the nominal outputs of an IN clause. Consider WHERE x * IN (SELECT y FROM t1,t2 WHERE y = z) Implied equality deduction * will generate an "x = z" clause, which may get used instead of "x = * y" in the upper join step. Therefore the sub-select had better * deliver both y and z in its targetlist. It is sufficient to * unique-ify on y, however. * * 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 == NIL) /* fell out of loop? */ elog(ERROR, "could not find UniquePath in in_info_list"); /* set up to record positions of unique columns */ numGroupCols = length(uniq_exprs); groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber)); groupColPos = 0; /* not sure if tlist might be shared with other nodes, so copy */ newtlist = copyObject(subplan->targetlist); nextresno = length(newtlist) + 1; newitems = false; foreach(l, uniq_exprs) { Node *uniqexpr = lfirst(l); TargetEntry *tle; tle = tlistentry_member(uniqexpr, newtlist); if (!tle) { tle = makeTargetEntry(makeResdom(nextresno, exprType(uniqexpr), exprTypmod(uniqexpr), NULL, false), (Expr *) uniqexpr); newtlist = lappend(newtlist, tle); nextresno++; newitems = true; } groupColIdx[groupColPos++] = tle->resdom->resno; } if (newitems) { /* * If the top plan node can't do projections, we need to add a * Result node to help it along. * * Currently, the only non-projection-capable plan type we can see * here is Append. */ if (IsA(subplan, Append)) subplan = (Plan *) make_result(newtlist, NULL, subplan); else subplan->targetlist = newtlist; } /* Copy tlist again to make one we can put sorting labels on */ my_tlist = copyObject(subplan->targetlist); if (best_path->use_hash) { long numGroups; numGroups = (long) Min(best_path->rows, (double) LONG_MAX); plan = (Plan *) make_agg(root, my_tlist, 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(my_tlist, groupColIdx[groupColPos]); Assert(tle != NULL); sortList = addTargetToSortList(NULL, tle, sortList, my_tlist, SORTBY_ASC, NIL, false); } plan = (Plan *) make_sort_from_sortclauses(root, my_tlist, subplan, sortList); plan = (Plan *) make_unique(my_tlist, plan, sortList); } 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(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); scan_plan = make_seqscan(tlist, scan_clauses, scan_relid); copy_path_costsize(&scan_plan->plan, best_path); return scan_plan;}/* * create_indexscan_plan * Returns a indexscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. * * The indexqual of the path contains a sublist of implicitly-ANDed qual * conditions for each scan of the index(es); if there is more than one * scan then the retrieved tuple sets are ORed together. The indexqual * and indexinfo lists must have the same length, ie, the number of scans * that will occur. Note it is possible for a qual condition sublist * to be empty --- then no index restrictions will be applied during that * scan. */static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path, List *tlist, List *scan_clauses){ List *indxqual = best_path->indexqual; Index baserelid = best_path->path.parent->relid; List *qpqual; Expr *indxqual_or_expr = NULL; List *fixed_indxqual; List *recheck_indxqual; FastList indexids; List *ixinfo; IndexScan *scan_plan; /* it should be a base rel... */ Assert(baserelid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); /* * Build list of index OIDs. */ FastListInit(&indexids); foreach(ixinfo, best_path->indexinfo) { IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo); FastAppendo(&indexids, index->indexoid); } /* * The qpqual list must contain all restrictions not automatically * handled by the index. Normally the predicates in the indxqual are * checked fully by the index, but if the index is "lossy" for a * particular operator (as signaled by the amopreqcheck flag in * pg_amop), then we need to double-check that predicate in qpqual, * because the index may return more tuples than match the predicate. * * Since the indexquals were generated from the restriction clauses given * by scan_clauses, there will normally be some duplications between * the lists. We get rid of the duplicates, then add back if lossy. */ if (length(indxqual) > 1) { /* * Build an expression representation of the indexqual, expanding * the implicit OR and AND semantics of the first- and * second-level lists. */ FastList orclauses; List *orclause; FastListInit(&orclauses); foreach(orclause, indxqual) FastAppend(&orclauses, make_ands_explicit(lfirst(orclause))); indxqual_or_expr = make_orclause(FastListValue(&orclauses)); qpqual = set_difference(scan_clauses, makeList1(indxqual_or_expr)); } else if (indxqual != NIL) { /* * Here, we can simply treat the first sublist as an independent * set of qual expressions, since there is no top-level OR * behavior. */ qpqual = set_difference(scan_clauses, lfirst(indxqual)); } else qpqual = scan_clauses; /* * 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 looks for "lossy" operators. */ fix_indxqual_references(indxqual, best_path, &fixed_indxqual, &recheck_indxqual); /* * If there were any "lossy" operators, need to add back the * appropriate qual clauses to the qpqual. When there is just one * indexscan being performed (ie, we have simple AND semantics), we * can just add the lossy clauses themselves to qpqual. If we have * OR-of-ANDs, we'd better add the entire original indexqual to make * sure that the semantics are correct. */ if (recheck_indxqual != NIL) { if (indxqual_or_expr) { /* Better do a deep copy of the original scanclauses */ qpqual = lappend(qpqual, copyObject(indxqual_or_expr)); } else { /* Subroutine already copied quals, so just append to list */ Assert(length(recheck_indxqual) == 1); qpqual = nconc(qpqual, (List *) lfirst(recheck_indxqual)); } } /* Finally ready to build the plan node */ scan_plan = make_indexscan(tlist, qpqual, baserelid, FastListValue(&indexids), fixed_indxqual, indxqual, 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_tidscan_plan * Returns a tidscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses){ TidScan *scan_plan; Index scan_relid = best_path->path.parent->relid; /* it should be a base rel... */ Assert(scan_relid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); scan_plan = make_tidscan(tlist, scan_clauses, scan_relid, best_path->tideval); copy_path_costsize(&scan_plan->scan.plan, &best_path->path); return scan_plan;}/* * create_subqueryscan_plan * Returns a subqueryscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static SubqueryScan *create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses){ SubqueryScan *scan_plan; Index scan_relid = best_path->parent->relid; /* it should be a subquery base rel... */ Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_SUBQUERY); scan_plan = make_subqueryscan(tlist, scan_clauses, scan_relid, best_path->parent->subplan); copy_path_costsize(&scan_plan->scan.plan, best_path); return scan_plan;}/* * create_functionscan_plan * Returns a functionscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */static FunctionScan *create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses){ FunctionScan *scan_plan; Index scan_relid = best_path->parent->relid; /* it should be a function base rel... */ Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_FUNCTION); scan_plan = make_functionscan(tlist, scan_clauses, scan_relid); copy_path_costsize(&scan_plan->scan.plan, best_path); return scan_plan;}/***************************************************************************** * * JOIN METHODS * *****************************************************************************/static NestLoop *create_nestloop_plan(Query *root, NestPath *best_path, Plan *outer_plan, Plan *inner_plan){ List *tlist = build_relation_tlist(best_path->path.parent); List *joinrestrictclauses = best_path->joinrestrictinfo; List *joinclauses; List *otherclauses; NestLoop *join_plan; if (IsA(best_path->innerjoinpath, IndexPath)) { /* * An index is being used to reduce the number of tuples scanned * in the inner relation. If there are join clauses being used * with the index, we may remove those join clauses from the list * of clauses that have to be checked as qpquals at the join node * --- but only if there's just one indexscan in the inner path * (otherwise, several different sets of clauses are being ORed * together). * * We can also remove any join clauses that are redundant with those * being used in the index scan; prior redundancy checks will not * have caught this case because the join clauses would never have * been put in the same joininfo list. * * This would be a waste of time if the indexpath was an ordinary * indexpath and not a special innerjoin path. We will skip it in * that case since indexjoinclauses is NIL in an ordinary * indexpath. */ IndexPath *innerpath = (IndexPath *) best_path->innerjoinpath; List *indexjoinclauses = innerpath->indexjoinclauses; if (length(indexjoinclauses) == 1) /* single indexscan? */ { joinrestrictclauses = select_nonredundant_join_clauses(root, joinrestrictclauses, lfirst(indexjoinclauses), best_path->jointype);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -