planner.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,553 行 · 第 1/4 页
C
1,553 行
numAggs, result_plan); /* Hashed aggregation produces randomly-ordered results */ current_pathkeys = NIL; } else if (parse->hasAggs) { /* Plain aggregate plan --- sort if needed */ AggStrategy aggstrategy; if (parse->groupClause) { if (!pathkeys_contained_in(group_pathkeys, current_pathkeys)) { result_plan = (Plan *) make_sort_from_groupcols(parse, parse->groupClause, groupColIdx, result_plan); current_pathkeys = group_pathkeys; } aggstrategy = AGG_SORTED; /* * The AGG node will not change the sort ordering of its * groups, so current_pathkeys describes the result too. */ } else { aggstrategy = AGG_PLAIN; /* Result will be only one row anyway; no sort order */ current_pathkeys = NIL; } result_plan = (Plan *) make_agg(parse, tlist, (List *) parse->havingQual, aggstrategy, numGroupCols, groupColIdx, numGroups, numAggs, result_plan); } else { /* * If there are no Aggs, we shouldn't have any HAVING qual * anymore */ Assert(parse->havingQual == NULL); /* * If we have a GROUP BY clause, insert a group node (plus the * appropriate sort node, if necessary). */ if (parse->groupClause) { /* * Add an explicit sort if we couldn't make the path come * out the way the GROUP node needs it. */ if (!pathkeys_contained_in(group_pathkeys, current_pathkeys)) { result_plan = (Plan *) make_sort_from_groupcols(parse, parse->groupClause, groupColIdx, result_plan); current_pathkeys = group_pathkeys; } result_plan = (Plan *) make_group(parse, tlist, numGroupCols, groupColIdx, dNumGroups, result_plan); /* The Group node won't change sort ordering */ } } } /* end of if (setOperations) */ /* * If we were not able to make the plan come out in the right order, * add an explicit sort step. */ if (parse->sortClause) { if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys)) { result_plan = (Plan *) make_sort_from_sortclauses(parse, tlist, result_plan, parse->sortClause); current_pathkeys = sort_pathkeys; } } /* * If there is a DISTINCT clause, add the UNIQUE node. */ if (parse->distinctClause) { result_plan = (Plan *) make_unique(tlist, result_plan, parse->distinctClause); /* * If there was grouping or aggregation, leave plan_rows as-is * (ie, assume the result was already mostly unique). If not, * it's reasonable to assume the UNIQUE filter has effects * comparable to GROUP BY. */ if (!parse->groupClause && !parse->hasAggs) { List *distinctExprs; distinctExprs = get_sortgrouplist_exprs(parse->distinctClause, parse->targetList); result_plan->plan_rows = estimate_num_groups(parse, distinctExprs, result_plan->plan_rows); } } /* * Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node. */ if (parse->limitOffset || parse->limitCount) { result_plan = (Plan *) make_limit(tlist, result_plan, parse->limitOffset, parse->limitCount); } /* * Return the actual output ordering in query_pathkeys for possible * use by an outer query level. */ parse->query_pathkeys = current_pathkeys; return result_plan;}/* * hash_safe_grouping - are grouping operators hashable? * * We assume hashed aggregation will work if the datatype's equality operator * is marked hashjoinable. */static boolhash_safe_grouping(Query *parse){ List *gl; foreach(gl, parse->groupClause) { GroupClause *grpcl = (GroupClause *) lfirst(gl); TargetEntry *tle = get_sortgroupclause_tle(grpcl, parse->targetList); Operator optup; bool oprcanhash; optup = equality_oper(tle->resdom->restype, true); if (!optup) return false; oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash; ReleaseSysCache(optup); if (!oprcanhash) return false; } return true;}/*--------------- * make_subplanTargetList * Generate appropriate target list when grouping is required. * * When grouping_planner inserts Aggregate or Group plan nodes above * the result of query_planner, we typically want to pass a different * target list to query_planner than the outer plan nodes should have. * This routine generates the correct target list for the subplan. * * The initial target list passed from the parser already contains entries * for all ORDER BY and GROUP BY expressions, but it will not have entries * for variables used only in HAVING clauses; so we need to add those * variables to the subplan target list. Also, if we are doing either * grouping or aggregation, we flatten all expressions except GROUP BY items * into their component variables; the other expressions will be computed by * the inserted nodes rather than by the subplan. For example, * given a query like * SELECT a+b,SUM(c+d) FROM table GROUP BY a+b; * we want to pass this targetlist to the subplan: * a,b,c,d,a+b * where the a+b target will be used by the Sort/Group steps, and the * other targets will be used for computing the final results. (In the * above example we could theoretically suppress the a and b targets and * pass down only c,d,a+b, but it's not really worth the trouble to * eliminate simple var references from the subplan. We will avoid doing * the extra computation to recompute a+b at the outer level; see * replace_vars_with_subplan_refs() in setrefs.c.) * * If we are grouping or aggregating, *and* there are no non-Var grouping * expressions, then the returned tlist is effectively dummy; we do not * need to force it to be evaluated, because all the Vars it contains * should be present in the output of query_planner anyway. * * 'parse' is the query being processed. * 'tlist' is the query's target list. * 'groupColIdx' receives an array of column numbers for the GROUP BY * expressions (if there are any) in the subplan's target list. * 'need_tlist_eval' is set true if we really need to evaluate the * result tlist. * * The result is the targetlist to be passed to the subplan. *--------------- */static List *make_subplanTargetList(Query *parse, List *tlist, AttrNumber **groupColIdx, bool *need_tlist_eval){ List *sub_tlist; List *extravars; int numCols; *groupColIdx = NULL; /* * If we're not grouping or aggregating, nothing to do here; * query_planner should receive the unmodified target list. */ if (!parse->hasAggs && !parse->groupClause) { *need_tlist_eval = true; return tlist; } /* * Otherwise, start with a "flattened" tlist (having just the vars * mentioned in the targetlist and HAVING qual --- but not upper- * level Vars; they will be replaced by Params later on). */ sub_tlist = flatten_tlist(tlist); extravars = pull_var_clause(parse->havingQual, false); sub_tlist = add_to_flat_tlist(sub_tlist, extravars); freeList(extravars); *need_tlist_eval = false; /* only eval if not flat tlist */ /* * If grouping, create sub_tlist entries for all GROUP BY expressions * (GROUP BY items that are simple Vars should be in the list * already), and make an array showing where the group columns are in * the sub_tlist. */ numCols = length(parse->groupClause); if (numCols > 0) { int keyno = 0; AttrNumber *grpColIdx; List *gl; grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols); *groupColIdx = grpColIdx; foreach(gl, parse->groupClause) { GroupClause *grpcl = (GroupClause *) lfirst(gl); Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist); TargetEntry *te = NULL; List *sl; /* Find or make a matching sub_tlist entry */ foreach(sl, sub_tlist) { te = (TargetEntry *) lfirst(sl); if (equal(groupexpr, te->expr)) break; } if (!sl) { te = makeTargetEntry(makeResdom(length(sub_tlist) + 1, exprType(groupexpr), exprTypmod(groupexpr), NULL, false), (Expr *) groupexpr); sub_tlist = lappend(sub_tlist, te); *need_tlist_eval = true; /* it's not flat anymore */ } /* and save its resno */ grpColIdx[keyno++] = te->resdom->resno; } } return sub_tlist;}/* * locate_grouping_columns * Locate grouping columns in the tlist chosen by query_planner. * * This is only needed if we don't use the sub_tlist chosen by * make_subplanTargetList. We have to forget the column indexes found * by that routine and re-locate the grouping vars in the real sub_tlist. */static voidlocate_grouping_columns(Query *parse, List *tlist, List *sub_tlist, AttrNumber *groupColIdx){ int keyno = 0; List *gl; /* * No work unless grouping. */ if (!parse->groupClause) { Assert(groupColIdx == NULL); return; } Assert(groupColIdx != NULL); foreach(gl, parse->groupClause) { GroupClause *grpcl = (GroupClause *) lfirst(gl); Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist); TargetEntry *te = NULL; List *sl; foreach(sl, sub_tlist) { te = (TargetEntry *) lfirst(sl); if (equal(groupexpr, te->expr)) break; } if (!sl) elog(ERROR, "failed to locate grouping columns"); groupColIdx[keyno++] = te->resdom->resno; }}/* * postprocess_setop_tlist * Fix up targetlist returned by plan_set_operations(). * * We need to transpose sort key info from the orig_tlist into new_tlist. * NOTE: this would not be good enough if we supported resjunk sort keys * for results of set operations --- then, we'd need to project a whole * new tlist to evaluate the resjunk columns. For now, just ereport if we * find any resjunk columns in orig_tlist. */static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist){ List *l; foreach(l, new_tlist) { TargetEntry *new_tle = (TargetEntry *) lfirst(l); TargetEntry *orig_tle; /* ignore resjunk columns in setop result */ if (new_tle->resdom->resjunk) continue; Assert(orig_tlist != NIL); orig_tle = (TargetEntry *) lfirst(orig_tlist); orig_tlist = lnext(orig_tlist); if (orig_tle->resdom->resjunk) /* should not happen */ elog(ERROR, "resjunk output columns are not implemented"); Assert(new_tle->resdom->resno == orig_tle->resdom->resno); Assert(new_tle->resdom->restype == orig_tle->resdom->restype); new_tle->resdom->ressortgroupref = orig_tle->resdom->ressortgroupref; } if (orig_tlist != NIL) elog(ERROR, "resjunk output columns are not implemented"); return new_tlist;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?