diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 797df31..4cbccac 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,61 @@ make_subplanTargetList(PlannerInfo *root, if (!parse->hasAggs && !parse->groupClause && !parse->groupingSets && !root->hasHavingQual && !parse->hasWindowFuncs) { + if (parse->sortClause && limit_needed(parse)) { + ListCell *tl; + bool contains_non_vars = false; + *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); + contains_non_vars |= !(tle->expr && IsA(tle->expr, Var)); + } + } + + if (non_group_cols) /* there are some columns not used in order by */ + { + 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 (contains_non_vars ) + { + /* + * This optimization makes sense only if target list contains some complex expressions, + * for example functions calls. May be it is better to check cost of this expressions, + * but right now just apply this optimization if there are non-vars columns + */ + return sub_tlist; + } + } + } *need_tlist_eval = true; return tlist; } @@ -3986,8 +4049,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 +4171,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. * diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index b72e65d..25e8da1 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1208,12 +1208,13 @@ SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10; EXPLAIN (COSTS OFF) SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; - QUERY PLAN ---------------------------------------------------- - Limit - -> Index Scan using ggcircleind on gcircle_tbl - Order By: (f1 <-> '(200,300)'::point) -(3 rows) + QUERY PLAN +--------------------------------------------------------- + Result + -> Limit + -> Index Scan using ggcircleind on gcircle_tbl + Order By: (f1 <-> '(200,300)'::point) +(4 rows) SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10; circle_center | radius