diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 797df31..c87db15 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -106,6 +106,7 @@ static bool choose_hashed_distinct(PlannerInfo *root, static List *make_subplanTargetList(PlannerInfo *root, List *tlist, AttrNumber **groupColIdx, bool *need_tlist_eval); static int get_grouping_column_index(Query *parse, TargetEntry *tle); +static int get_sort_column_index(Query *parse, TargetEntry *tle); static void locate_grouping_columns(PlannerInfo *root, List *tlist, List *sub_tlist, @@ -2402,6 +2403,13 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) parse->limitCount, offset_est, count_est); + if (parse->sortClause && tlist != result_plan->targetlist) + { + result_plan = (Plan *) make_result(root, + tlist, + NULL, + result_plan); + } } /* @@ -3964,8 +3972,8 @@ make_subplanTargetList(PlannerInfo *root, bool *need_tlist_eval) { Query *parse = root->parse; - List *sub_tlist; - List *non_group_cols; + List *sub_tlist = NIL; + List *non_group_cols = NIL; List *non_group_vars; int numCols; @@ -3978,6 +3986,53 @@ make_subplanTargetList(PlannerInfo *root, if (!parse->hasAggs && !parse->groupClause && !parse->groupingSets && !root->hasHavingQual && !parse->hasWindowFuncs) { + if (parse->sortClause && limit_needed(parse)) { + ListCell *tl; + *need_tlist_eval = false; /* only eval if not flat tlist */ + foreach(tl, tlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(tl); + int colno; + + colno = get_sort_column_index(parse, tle); + if (colno >= 0) + { + TargetEntry *newtle; + + newtle = makeTargetEntry(tle->expr, + list_length(sub_tlist) + 1, + NULL, + false); + sub_tlist = lappend(sub_tlist, newtle); + if (!(newtle->expr && IsA(newtle->expr, Var))) + *need_tlist_eval = true; /* tlist contains non Vars */ + } + else + { + /* + * Non-sorting column, so just remember the expression for + * later call to pull_var_clause. There's no need for + * pull_var_clause to examine the TargetEntry node itself. + */ + non_group_cols = lappend(non_group_cols, tle->expr); + } + } + if (non_group_cols && sub_tlist != NIL) + { + non_group_vars = pull_var_clause((Node *) non_group_cols, + PVC_RECURSE_AGGREGATES, + PVC_INCLUDE_PLACEHOLDERS); + sub_tlist = add_to_flat_tlist(sub_tlist, non_group_vars); + + /* clean up cruft */ + list_free(non_group_vars); + list_free(non_group_cols); + + if (sub_tlist->length < tlist->length) { + return sub_tlist; + } + } + } *need_tlist_eval = true; return tlist; } @@ -3986,8 +4041,6 @@ make_subplanTargetList(PlannerInfo *root, * Otherwise, we must build a tlist containing all grouping columns, plus * any other Vars mentioned in the targetlist and HAVING qual. */ - sub_tlist = NIL; - non_group_cols = NIL; *need_tlist_eval = false; /* only eval if not flat tlist */ numCols = list_length(parse->groupClause); @@ -4110,6 +4163,37 @@ get_grouping_column_index(Query *parse, TargetEntry *tle) } /* + * get_sort_column_index + * Get the ORDER BY column position, if any, of a targetlist entry. + * + * Returns the index (counting from 0) of the TLE in the ORDER BY list, or -1 + * if it's not a sorting column. Note: the result is unique because the + * parser won't make multiple sortClause entries for the same TLE. + */ +static int +get_sort_column_index(Query *parse, TargetEntry *tle) +{ + int colno = 0; + Index ressortgroupref = tle->ressortgroupref; + ListCell *gl; + + /* No need to search groupClause if TLE hasn't got a sortgroupref */ + if (ressortgroupref == 0) + return -1; + + foreach(gl, parse->sortClause) + { + SortGroupClause *sortcl = (SortGroupClause *) lfirst(gl); + + if (sortcl->tleSortGroupRef == ressortgroupref) + return colno; + colno++; + } + + return -1; +} + +/* * locate_grouping_columns * Locate grouping columns in the tlist chosen by create_plan. *