📄 createplan.c
字号:
* in at runtime. * * Ideally the order should be driven by a combination of execution cost and * selectivity, but unfortunately we have so little information about * execution cost of operators that it's really hard to do anything smart. * For now, we just move any quals that contain SubPlan references (but not * InitPlan references) to the end of the list. */static List *order_qual_clauses(Query *root, List *clauses){ FastList nosubplans; FastList withsubplans; List *l; /* No need to work hard if the query is subselect-free */ if (!root->hasSubLinks) return clauses; FastListInit(&nosubplans); FastListInit(&withsubplans); foreach(l, clauses) { Node *clause = lfirst(l); if (contain_subplans(clause)) FastAppend(&withsubplans, clause); else FastAppend(&nosubplans, clause); } FastConcFast(&nosubplans, &withsubplans); return FastListValue(&nosubplans);}/* * Copy cost and size info from a Path node to the Plan node created from it. * The executor won't use this info, but it's needed by EXPLAIN. */static voidcopy_path_costsize(Plan *dest, Path *src){ if (src) { dest->startup_cost = src->startup_cost; dest->total_cost = src->total_cost; dest->plan_rows = src->parent->rows; dest->plan_width = src->parent->width; } else { dest->startup_cost = 0; dest->total_cost = 0; dest->plan_rows = 0; dest->plan_width = 0; }}/* * Copy cost and size info from a lower plan node to an inserted node. * This is not critical, since the decisions have already been made, * but it helps produce more reasonable-looking EXPLAIN output. * (Some callers alter the info after copying it.) */static voidcopy_plan_costsize(Plan *dest, Plan *src){ if (src) { dest->startup_cost = src->startup_cost; dest->total_cost = src->total_cost; dest->plan_rows = src->plan_rows; dest->plan_width = src->plan_width; } else { dest->startup_cost = 0; dest->total_cost = 0; dest->plan_rows = 0; dest->plan_width = 0; }}/***************************************************************************** * * PLAN NODE BUILDING ROUTINES * * Some of these are exported because they are called to build plan nodes * in contexts where we're not deriving the plan node from a path node. * *****************************************************************************/static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid){ SeqScan *node = makeNode(SeqScan); Plan *plan = &node->plan; /* cost should be inserted by caller */ plan->targetlist = qptlist; plan->qual = qpqual; plan->lefttree = NULL; plan->righttree = NULL; node->scanrelid = scanrelid; return node;}static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, List *indxid, List *indxqual, List *indxqualorig, ScanDirection indexscandir){ IndexScan *node = makeNode(IndexScan); 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->indxid = indxid; node->indxqual = indxqual; node->indxqualorig = indxqualorig; node->indxorderdir = indexscandir; return node;}static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval){ TidScan *node = makeNode(TidScan); 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->tideval = tideval; return node;}SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual, Index scanrelid, Plan *subplan){ SubqueryScan *node = makeNode(SubqueryScan); Plan *plan = &node->scan.plan; /* * Cost is figured here for the convenience of prepunion.c. Note this * is only correct for the case where qpqual is empty; otherwise * caller should overwrite cost with a better estimate. */ copy_plan_costsize(plan, subplan); plan->total_cost += cpu_tuple_cost * subplan->plan_rows; plan->targetlist = qptlist; plan->qual = qpqual; plan->lefttree = NULL; plan->righttree = NULL; node->scan.scanrelid = scanrelid; node->subplan = subplan; return node;}static FunctionScan *make_functionscan(List *qptlist, List *qpqual, Index scanrelid){ FunctionScan *node = makeNode(FunctionScan); 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; return node;}Append *make_append(List *appendplans, bool isTarget, List *tlist){ Append *node = makeNode(Append); Plan *plan = &node->plan; List *subnode; /* * Compute cost as sum of subplan costs. We charge nothing extra for * the Append itself, which perhaps is too optimistic, but since it * doesn't do any selection or projection, it is a pretty cheap node. */ plan->startup_cost = 0; plan->total_cost = 0; plan->plan_rows = 0; plan->plan_width = 0; foreach(subnode, appendplans) { Plan *subplan = (Plan *) lfirst(subnode); if (subnode == appendplans) /* first node? */ plan->startup_cost = subplan->startup_cost; plan->total_cost += subplan->total_cost; plan->plan_rows += subplan->plan_rows; if (plan->plan_width < subplan->plan_width) plan->plan_width = subplan->plan_width; } plan->targetlist = tlist; plan->qual = NIL; plan->lefttree = NULL; plan->righttree = NULL; node->appendplans = appendplans; node->isTarget = isTarget; return node;}static NestLoop *make_nestloop(List *tlist, List *joinclauses, List *otherclauses, Plan *lefttree, Plan *righttree, JoinType jointype){ NestLoop *node = makeNode(NestLoop); Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->targetlist = tlist; plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; node->join.jointype = jointype; node->join.joinqual = joinclauses; return node;}static HashJoin *make_hashjoin(List *tlist, List *joinclauses, List *otherclauses, List *hashclauses, Plan *lefttree, Plan *righttree, JoinType jointype){ HashJoin *node = makeNode(HashJoin); Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->targetlist = tlist; plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; node->hashclauses = hashclauses; node->join.jointype = jointype; node->join.joinqual = joinclauses; return node;}static Hash *make_hash(List *tlist, List *hashkeys, Plan *lefttree){ Hash *node = makeNode(Hash); Plan *plan = &node->plan; copy_plan_costsize(plan, lefttree); /* * For plausibility, make startup & total costs equal total cost of * input plan; this only affects EXPLAIN display not decisions. */ plan->startup_cost = plan->total_cost; plan->targetlist = tlist; plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; node->hashkeys = hashkeys; return node;}static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, Plan *lefttree, Plan *righttree, JoinType jointype){ MergeJoin *node = makeNode(MergeJoin); Plan *plan = &node->join.plan; /* cost should be inserted by caller */ plan->targetlist = tlist; plan->qual = otherclauses; plan->lefttree = lefttree; plan->righttree = righttree; node->mergeclauses = mergeclauses; node->join.jointype = jointype; node->join.joinqual = joinclauses; return node;}/* * make_sort --- basic routine to build a Sort plan node * * Caller must have built the sortColIdx and sortOperators arrays already. */static Sort *make_sort(Query *root, List *tlist, Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators){ Sort *node = makeNode(Sort); Plan *plan = &node->plan; Path sort_path; /* dummy for result of cost_sort */ copy_plan_costsize(plan, lefttree); /* only care about copying size */ cost_sort(&sort_path, root, NIL, lefttree->total_cost, lefttree->plan_rows, lefttree->plan_width); plan->startup_cost = sort_path.startup_cost; plan->total_cost = sort_path.total_cost; plan->targetlist = tlist; plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; node->numCols = numCols; node->sortColIdx = sortColIdx; node->sortOperators = sortOperators; return node;}/* * add_sort_column --- utility subroutine for building sort info arrays * * We need this routine because the same column might be selected more than * once as a sort key column; if so, the extra mentions are redundant. * * Caller is assumed to have allocated the arrays large enough for the * max possible number of columns. Return value is the new column count. */static intadd_sort_column(AttrNumber colIdx, Oid sortOp, int numCols, AttrNumber *sortColIdx, Oid *sortOperators){ int i; for (i = 0; i < numCols; i++) { if (sortColIdx[i] == colIdx) { /* Already sorting by this col, so extra sort key is useless */ return numCols; } } /* Add the column */ sortColIdx[numCols] = colIdx; sortOperators[numCols] = sortOp; return numCols + 1;}/* * make_sort_from_pathkeys * Create sort plan to sort according to given pathkeys * * 'lefttree' is the node which yields input tuples * 'pathkeys' is the list of pathkeys by which the result is to be sorted * * We must convert the pathkey information into arrays of sort key column * numbers and sort operator OIDs. * * If the pathkeys include expressions that aren't simple Vars, we will * usually need to add resjunk items to the input plan's targetlist to * compute these expressions (since the Sort node itself won't do it). * If the input plan type isn't one that can do projections, this means * adding a Result node just to do the projection. */static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree, List *pathkeys){ List *tlist = lefttree->targetlist; List *sort_tlist; List *i; int numsortkeys; AttrNumber *sortColIdx; Oid *sortOperators; /* We will need at most length(pathkeys) sort columns; possibly less */ numsortkeys = length(pathkeys); sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber)); sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid)); numsortkeys = 0; foreach(i, pathkeys) { List *keysublist = (List *) lfirst(i); PathKeyItem *pathkey = NULL; Resdom *resdom = NULL; List *j; /* * We can sort by any one of the sort key items listed in this * sublist. For now, we take the first one that corresponds to an * available Var in the tlist. If there isn't any, use the first * one that is an expression in the input's vars. * * XXX if we have a choice, is there any way of figuring out which * might be cheapest to execute? (For example, int4lt is likely * much cheaper to execute than numericlt, but both might appear * in the same pathkey sublist...) Not clear that we ever will * have a choice in practice, so it may not matter. */ foreach(j, keysublist) { pathkey = lfirst(j); Assert(IsA(pathkey, PathKeyItem)); resdom = tlist_member(pathkey->key, tlist); if (resdom) break; } if (!resdom) { /* No matching Var; look for a computable expression */ foreach(j, keysublist) { List *exprvars; List *k; pathkey = lfirst(j); exprvars = pull_var_clause(pathkey->key, false); foreach(k, exprvars) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -