]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/plan/planner.c
Error message editing in backend/optimizer, backend/rewrite.
[postgresql] / src / backend / optimizer / plan / planner.c
index ad68253109d7cb1da979680970db17ad3e0ace81..1896982f02eacd96a81a4f3c9ed56ad3e362ddb7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.144 2003/02/04 00:50:00 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.157 2003/07/25 00:01:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
+#include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #ifdef OPTIMIZER_DEBUG
@@ -46,7 +47,8 @@
 #define EXPRKIND_QUAL  0
 #define EXPRKIND_TARGET        1
 #define EXPRKIND_RTFUNC        2
-#define EXPRKIND_ININFO        3
+#define EXPRKIND_LIMIT 3
+#define EXPRKIND_ININFO        4
 
 
 static Node *preprocess_expression(Query *parse, Node *expr, int kind);
@@ -60,10 +62,6 @@ static void locate_grouping_columns(Query *parse,
                                                                        List *tlist,
                                                                        List *sub_tlist,
                                                                        AttrNumber *groupColIdx);
-static Plan *make_groupsortplan(Query *parse,
-                                                               List *groupClause,
-                                                               AttrNumber *grpColIdx,
-                                                               Plan *subplan);
 static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
 
 
@@ -73,11 +71,12 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
  *
  *****************************************************************************/
 Plan *
-planner(Query *parse)
+planner(Query *parse, bool isCursor, int cursorOptions)
 {
+       double          tuple_fraction;
        Plan       *result_plan;
        Index           save_PlannerQueryLevel;
-       List       *save_PlannerParamVar;
+       List       *save_PlannerParamList;
 
        /*
         * The planner can be called recursively (an example is when
@@ -93,26 +92,53 @@ planner(Query *parse)
         * subquery_planner, not here.
         */
        save_PlannerQueryLevel = PlannerQueryLevel;
-       save_PlannerParamVar = PlannerParamVar;
+       save_PlannerParamList = PlannerParamList;
 
        /* Initialize state for handling outer-level references and params */
        PlannerQueryLevel = 0;          /* will be 1 in top-level subquery_planner */
-       PlannerParamVar = NIL;
+       PlannerParamList = NIL;
+
+       /* Determine what fraction of the plan is likely to be scanned */
+       if (isCursor)
+       {
+               /*
+                * We have no real idea how many tuples the user will ultimately
+                * FETCH from a cursor, but it seems a good bet that he
+                * doesn't want 'em all.  Optimize for 10% retrieval (you
+                * gotta better number?  Should this be a SETtable parameter?)
+                */
+               tuple_fraction = 0.10;
+       }
+       else
+       {
+               /* Default assumption is we need all the tuples */
+               tuple_fraction = 0.0;
+       }
 
        /* primary planning entry point (may recurse for subqueries) */
-       result_plan = subquery_planner(parse, -1.0 /* default case */ );
+       result_plan = subquery_planner(parse, tuple_fraction);
 
        Assert(PlannerQueryLevel == 0);
 
+       /*
+        * If creating a plan for a scrollable cursor, make sure it can
+        * run backwards on demand.  Add a Material node at the top at need.
+        */
+       if (isCursor && (cursorOptions & CURSOR_OPT_SCROLL))
+       {
+               if (!ExecSupportsBackwardScan(result_plan))
+                       result_plan = materialize_finished_plan(result_plan);
+       }
+
        /* executor wants to know total number of Params used overall */
-       result_plan->nParamExec = length(PlannerParamVar);
+       result_plan->nParamExec = length(PlannerParamList);
 
        /* final cleanup of the plan */
        set_plan_references(result_plan, parse->rtable);
 
        /* restore state for outer planner, if any */
        PlannerQueryLevel = save_PlannerQueryLevel;
-       PlannerParamVar = save_PlannerParamVar;
+       PlannerParamList = save_PlannerParamList;
 
        return result_plan;
 }
@@ -144,6 +170,7 @@ subquery_planner(Query *parse, double tuple_fraction)
 {
        List       *saved_initplan = PlannerInitPlan;
        int                     saved_planid = PlannerPlanId;
+       bool            hasOuterJoins;
        Plan       *plan;
        List       *newHaving;
        List       *lst;
@@ -172,10 +199,12 @@ subquery_planner(Query *parse, double tuple_fraction)
 
        /*
         * Detect whether any rangetable entries are RTE_JOIN kind; if not,
-        * we can avoid the expense of doing flatten_join_alias_vars().
+        * we can avoid the expense of doing flatten_join_alias_vars().  Also
+        * check for outer joins --- if none, we can skip reduce_outer_joins().
         * This must be done after we have done pull_up_subqueries, of course.
         */
        parse->hasJoinRTEs = false;
+       hasOuterJoins = false;
        foreach(lst, parse->rtable)
        {
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(lst);
@@ -183,7 +212,12 @@ subquery_planner(Query *parse, double tuple_fraction)
                if (rte->rtekind == RTE_JOIN)
                {
                        parse->hasJoinRTEs = true;
-                       break;
+                       if (IS_OUTER_JOIN(rte->jointype))
+                       {
+                               hasOuterJoins = true;
+                               /* Can quit scanning once we find an outer join */
+                               break;
+                       }
                }
        }
 
@@ -199,6 +233,11 @@ subquery_planner(Query *parse, double tuple_fraction)
        parse->havingQual = preprocess_expression(parse, parse->havingQual,
                                                                                          EXPRKIND_QUAL);
 
+       parse->limitOffset = preprocess_expression(parse, parse->limitOffset,
+                                                                                          EXPRKIND_LIMIT);
+       parse->limitCount = preprocess_expression(parse, parse->limitCount,
+                                                                                         EXPRKIND_LIMIT);
+
        parse->in_info_list = (List *)
                preprocess_expression(parse, (Node *) parse->in_info_list,
                                                          EXPRKIND_ININFO);
@@ -228,8 +267,7 @@ subquery_planner(Query *parse, double tuple_fraction)
         *
         * Note that both havingQual and parse->jointree->quals are in
         * implicitly-ANDed-list form at this point, even though they are
-        * declared as Node *.  Also note that contain_agg_clause does not
-        * recurse into sub-selects, which is exactly what we need here.
+        * declared as Node *.
         */
        newHaving = NIL;
        foreach(lst, (List *) parse->havingQual)
@@ -244,15 +282,23 @@ subquery_planner(Query *parse, double tuple_fraction)
        }
        parse->havingQual = (Node *) newHaving;
 
+       /*
+        * If we have any outer joins, try to reduce them to plain inner joins.
+        * This step is most easily done after we've done expression preprocessing.
+        */
+       if (hasOuterJoins)
+               reduce_outer_joins(parse);
+
        /*
         * See if we can simplify the jointree; opportunities for this may come
         * from having pulled up subqueries, or from flattening explicit JOIN
         * syntax.  We must do this after flattening JOIN alias variables, since
         * eliminating explicit JOIN nodes from the jointree will cause
-        * get_relids_for_join() to fail.
+        * get_relids_for_join() to fail.  But it should happen after
+        * reduce_outer_joins, anyway.
         */
        parse->jointree = (FromExpr *)
-               preprocess_jointree(parse, (Node *) parse->jointree);
+               simplify_jointree(parse, (Node *) parse->jointree);
 
        /*
         * Do the main planning.  If we have an inherited target relation,
@@ -260,22 +306,22 @@ subquery_planner(Query *parse, double tuple_fraction)
         * grouping_planner.
         */
        if (parse->resultRelation &&
-        (lst = expand_inherted_rtentry(parse, parse->resultRelation, false))
-               != NIL)
+               (lst = expand_inherited_rtentry(parse, parse->resultRelation,
+                                                                               false)) != NIL)
                plan = inheritance_planner(parse, lst);
        else
                plan = grouping_planner(parse, tuple_fraction);
 
        /*
         * If any subplans were generated, or if we're inside a subplan, build
-        * initPlan, extParam and locParam lists for plan nodes.
+        * initPlan list and extParam/allParam sets for plan nodes.
         */
        if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
        {
                Cost    initplan_cost = 0;
 
-               /* Prepare extParam/locParam data for all nodes in tree */
-               (void) SS_finalize_plan(plan, parse->rtable);
+               /* Prepare extParam/allParam sets for all nodes in tree */
+               SS_finalize_plan(plan, parse->rtable);
 
                /*
                 * SS_finalize_plan doesn't handle initPlans, so we have to manually
@@ -293,8 +339,8 @@ subquery_planner(Query *parse, double tuple_fraction)
                {
                        SubPlan    *initplan = (SubPlan *) lfirst(lst);
 
-                       plan->extParam = set_unioni(plan->extParam,
-                                                                               initplan->plan->extParam);
+                       plan->extParam = bms_add_members(plan->extParam,
+                                                                                        initplan->plan->extParam);
                        initplan_cost += initplan->plan->total_cost;
                }
 
@@ -356,6 +402,11 @@ preprocess_expression(Query *parse, Node *expr, int kind)
        if (parse->hasSubLinks)
                expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
 
+       /*
+        * XXX do not insert anything here unless you have grokked the comments
+        * in SS_replace_correlation_vars ...
+        */
+
        /* Replace uplevel vars with Param nodes */
        if (PlannerQueryLevel > 1)
                expr = SS_replace_correlation_vars(expr);
@@ -397,8 +448,8 @@ preprocess_qual_conditions(Query *parse, Node *jtnode)
                j->quals = preprocess_expression(parse, j->quals, EXPRKIND_QUAL);
        }
        else
-               elog(ERROR, "preprocess_qual_conditions: unexpected node type %d",
-                        nodeTag(jtnode));
+               elog(ERROR, "unrecognized node type: %d",
+                        (int) nodeTag(jtnode));
 }
 
 /*--------------------
@@ -427,6 +478,7 @@ inheritance_planner(Query *parse, List *inheritlist)
 {
        int                     parentRTindex = parse->resultRelation;
        Oid                     parentOID = getrelid(parentRTindex, parse->rtable);
+       int                     mainrtlength = length(parse->rtable);
        List       *subplans = NIL;
        List       *tlist = NIL;
        List       *l;
@@ -435,6 +487,7 @@ inheritance_planner(Query *parse, List *inheritlist)
        {
                int                     childRTindex = lfirsti(l);
                Oid                     childOID = getrelid(childRTindex, parse->rtable);
+               int                     subrtlength;
                Query      *subquery;
                Plan       *subplan;
 
@@ -445,6 +498,24 @@ inheritance_planner(Query *parse, List *inheritlist)
                /* Generate plan */
                subplan = grouping_planner(subquery, 0.0 /* retrieve all tuples */ );
                subplans = lappend(subplans, subplan);
+               /*
+                * It's possible that additional RTEs got added to the rangetable
+                * due to expansion of inherited source tables (see allpaths.c).
+                * If so, we must copy 'em back to the main parse tree's rtable.
+                *
+                * XXX my goodness this is ugly.  Really need to think about ways
+                * to rein in planner's habit of scribbling on its input.
+                */
+               subrtlength = length(subquery->rtable);
+               if (subrtlength > mainrtlength)
+               {
+                       List   *subrt = subquery->rtable;
+
+                       while (mainrtlength-- > 0) /* wish we had nthcdr() */
+                               subrt = lnext(subrt);
+                       parse->rtable = nconc(parse->rtable, subrt);
+                       mainrtlength = subrtlength;
+               }
                /* Save preprocessed tlist from first rel for use in Append */
                if (tlist == NIL)
                        tlist = subplan->targetlist;
@@ -453,6 +524,9 @@ inheritance_planner(Query *parse, List *inheritlist)
        /* Save the target-relations list for the executor, too */
        parse->resultRelations = inheritlist;
 
+       /* Mark result as unordered (probably unnecessary) */
+       parse->query_pathkeys = NIL;
+
        return (Plan *) make_append(subplans, true, tlist);
 }
 
@@ -466,16 +540,14 @@ inheritance_planner(Query *parse, List *inheritlist)
  * tuple_fraction is the fraction of tuples we expect will be retrieved
  *
  * tuple_fraction is interpreted as follows:
- *       < 0: determine fraction by inspection of query (normal case)
- *       0: expect all tuples to be retrieved
+ *       0: expect all tuples to be retrieved (normal case)
  *       0 < tuple_fraction < 1: expect the given fraction of tuples available
  *             from the plan to be retrieved
  *       tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
  *             expected to be retrieved (ie, a LIMIT specification)
- * The normal case is to pass -1, but some callers pass values >= 0 to
- * override this routine's determination of the appropriate fraction.
  *
- * Returns a query plan.
+ * Returns a query plan.  Also, parse->query_pathkeys is returned as the
+ * actual output ordering of the plan (in pathkey format).
  *--------------------
  */
 static Plan *
@@ -510,7 +582,9 @@ grouping_planner(Query *parse, double tuple_fraction)
                 * already, but let's make sure).
                 */
                if (parse->rowMarks)
-                       elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
 
                /*
                 * We set current_pathkeys NIL indicating we do not know sort
@@ -574,7 +648,9 @@ grouping_planner(Query *parse, double tuple_fraction)
                         * level
                         */
                        if (PlannerQueryLevel > 1)
-                               elog(ERROR, "SELECT FOR UPDATE is not allowed in subselects");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("SELECT FOR UPDATE is not allowed in subselects")));
 
                        foreach(l, parse->rowMarks)
                        {
@@ -653,29 +729,6 @@ grouping_planner(Query *parse, double tuple_fraction)
                else
                        parse->query_pathkeys = NIL;
 
-               /*
-                * Figure out whether we expect to retrieve all the tuples that
-                * the plan can generate, or to stop early due to outside factors
-                * such as a cursor.  If the caller passed a value >= 0, believe
-                * that value, else do our own examination of the query context.
-                */
-               if (tuple_fraction < 0.0)
-               {
-                       /* Initial assumption is we need all the tuples */
-                       tuple_fraction = 0.0;
-
-                       /*
-                        * Check for retrieve-into-portal, ie DECLARE CURSOR.
-                        *
-                        * We have no real idea how many tuples the user will ultimately
-                        * FETCH from a cursor, but it seems a good bet that he
-                        * doesn't want 'em all.  Optimize for 10% retrieval (you
-                        * gotta better number?  Should this be a SETtable parameter?)
-                        */
-                       if (parse->isPortal)
-                               tuple_fraction = 0.10;
-               }
-
                /*
                 * Adjust tuple_fraction if we see that we are going to apply
                 * limiting/grouping/aggregation/etc.  This is not overridable by
@@ -851,6 +904,24 @@ grouping_planner(Query *parse, double tuple_fraction)
                if (parse->groupClause)
                {
                        List   *groupExprs;
+                       double  cheapest_path_rows;
+                       int             cheapest_path_width;
+
+                       /*
+                        * Beware in this section of the possibility that
+                        * cheapest_path->parent is NULL.  This could happen if user
+                        * does something silly like SELECT 'foo' GROUP BY 1;
+                        */
+                       if (cheapest_path->parent)
+                       {
+                               cheapest_path_rows = cheapest_path->parent->rows;
+                               cheapest_path_width = cheapest_path->parent->width;
+                       }
+                       else
+                       {
+                               cheapest_path_rows = 1; /* assume non-set result */
+                               cheapest_path_width = 100; /* arbitrary */
+                       }
 
                        /*
                         * Always estimate the number of groups.  We can't do this until
@@ -860,7 +931,7 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                                                                 parse->targetList);
                        dNumGroups = estimate_num_groups(parse,
                                                                                         groupExprs,
-                                                                                        cheapest_path->parent->rows);
+                                                                                        cheapest_path_rows);
                        /* Also want it as a long int --- but 'ware overflow! */
                        numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
 
@@ -893,8 +964,7 @@ grouping_planner(Query *parse, double tuple_fraction)
                                 * assume it is 100 bytes.  Also set the overhead per hashtable
                                 * entry at 64 bytes.
                                 */
-                               int             hashentrysize = cheapest_path->parent->width + 64 +
-                                       numAggs * 100;
+                               int             hashentrysize = cheapest_path_width + 64 + numAggs * 100;
 
                                if (hashentrysize * dNumGroups <= SortMem * 1024L)
                                {
@@ -921,13 +991,13 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                         numGroupCols, dNumGroups,
                                                         cheapest_path->startup_cost,
                                                         cheapest_path->total_cost,
-                                                        cheapest_path->parent->rows);
+                                                        cheapest_path_rows);
                                        /* Result of hashed agg is always unsorted */
                                        if (sort_pathkeys)
                                                cost_sort(&hashed_p, parse, sort_pathkeys,
                                                                  hashed_p.total_cost,
                                                                  dNumGroups,
-                                                                 cheapest_path->parent->width);
+                                                                 cheapest_path_width);
 
                                        if (sorted_path)
                                        {
@@ -946,8 +1016,8 @@ grouping_planner(Query *parse, double tuple_fraction)
                                        {
                                                cost_sort(&sorted_p, parse, group_pathkeys,
                                                                  sorted_p.total_cost,
-                                                                 cheapest_path->parent->rows,
-                                                                 cheapest_path->parent->width);
+                                                                 cheapest_path_rows,
+                                                                 cheapest_path_width);
                                                current_pathkeys = group_pathkeys;
                                        }
                                        if (parse->hasAggs)
@@ -956,13 +1026,13 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                                 numGroupCols, dNumGroups,
                                                                 sorted_p.startup_cost,
                                                                 sorted_p.total_cost,
-                                                                cheapest_path->parent->rows);
+                                                                cheapest_path_rows);
                                        else
                                                cost_group(&sorted_p, parse,
                                                                   numGroupCols, dNumGroups,
                                                                   sorted_p.startup_cost,
                                                                   sorted_p.total_cost,
-                                                                  cheapest_path->parent->rows);
+                                                                  cheapest_path_rows);
                                        /* The Agg or Group node will preserve ordering */
                                        if (sort_pathkeys &&
                                                !pathkeys_contained_in(sort_pathkeys,
@@ -971,7 +1041,7 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                cost_sort(&sorted_p, parse, sort_pathkeys,
                                                                  sorted_p.total_cost,
                                                                  dNumGroups,
-                                                                 cheapest_path->parent->width);
+                                                                 cheapest_path_width);
                                        }
 
                                        /*
@@ -983,7 +1053,7 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                tuple_fraction /= dNumGroups;
 
                                        if (compare_fractional_path_costs(&hashed_p, &sorted_p,
-                                                                                                         tuple_fraction) <= 0)
+                                                                                                         tuple_fraction) < 0)
                                        {
                                                /* Hashed is cheaper, so use it */
                                                use_hashed_grouping = true;
@@ -1102,10 +1172,11 @@ grouping_planner(Query *parse, double tuple_fraction)
                        {
                                if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
                                {
-                                       result_plan = make_groupsortplan(parse,
-                                                                                                        parse->groupClause,
-                                                                                                        groupColIdx,
-                                                                                                        result_plan);
+                                       result_plan = (Plan *)
+                                               make_sort_from_groupcols(parse,
+                                                                                                parse->groupClause,
+                                                                                                groupColIdx,
+                                                                                                result_plan);
                                        current_pathkeys = group_pathkeys;
                                }
                                aggstrategy = AGG_SORTED;
@@ -1150,10 +1221,11 @@ grouping_planner(Query *parse, double tuple_fraction)
                                 */
                                if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
                                {
-                                       result_plan = make_groupsortplan(parse,
-                                                                                                        parse->groupClause,
-                                                                                                        groupColIdx,
-                                                                                                        result_plan);
+                                       result_plan = (Plan *)
+                                               make_sort_from_groupcols(parse,
+                                                                                                parse->groupClause,
+                                                                                                groupColIdx,
+                                                                                                result_plan);
                                        current_pathkeys = group_pathkeys;
                                }
 
@@ -1175,10 +1247,14 @@ grouping_planner(Query *parse, double tuple_fraction)
        if (parse->sortClause)
        {
                if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
-                       result_plan = (Plan *) make_sort_from_sortclauses(parse,
-                                                                                                                         tlist,
-                                                                                                                         result_plan,
-                                                                                                                         parse->sortClause);
+               {
+                       result_plan = (Plan *)
+                               make_sort_from_sortclauses(parse,
+                                                                                  tlist,
+                                                                                  result_plan,
+                                                                                  parse->sortClause);
+                       current_pathkeys = sort_pathkeys;
+               }
        }
 
        /*
@@ -1216,6 +1292,12 @@ grouping_planner(Query *parse, double tuple_fraction)
                                                                                  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;
 }
 
@@ -1305,7 +1387,7 @@ make_subplanTargetList(Query *parse,
         * If we're not grouping or aggregating, nothing to do here;
         * query_planner should receive the unmodified target list.
         */
-       if (!parse->hasAggs && !parse->groupClause && !parse->havingQual)
+       if (!parse->hasAggs && !parse->groupClause)
        {
                *need_tlist_eval = true;
                return tlist;
@@ -1413,57 +1495,12 @@ locate_grouping_columns(Query *parse,
                                break;
                }
                if (!sl)
-                       elog(ERROR, "locate_grouping_columns: failed");
+                       elog(ERROR, "failed to locate grouping columns");
 
                groupColIdx[keyno++] = te->resdom->resno;
        }
 }
 
-/*
- * make_groupsortplan
- *             Add a Sort node to explicitly sort according to the GROUP BY clause.
- *
- * Note: the Sort node always just takes a copy of the subplan's tlist
- * plus ordering information.  (This might seem inefficient if the
- * subplan contains complex GROUP BY expressions, but in fact Sort
- * does not evaluate its targetlist --- it only outputs the same
- * tuples in a new order.  So the expressions we might be copying
- * are just dummies with no extra execution cost.)
- */
-static Plan *
-make_groupsortplan(Query *parse,
-                                  List *groupClause,
-                                  AttrNumber *grpColIdx,
-                                  Plan *subplan)
-{
-       List       *sort_tlist = new_unsorted_tlist(subplan->targetlist);
-       int                     keyno = 0;
-       List       *gl;
-
-       foreach(gl, groupClause)
-       {
-               GroupClause *grpcl = (GroupClause *) lfirst(gl);
-               TargetEntry *te = nth(grpColIdx[keyno] - 1, sort_tlist);
-               Resdom     *resdom = te->resdom;
-
-               /*
-                * Check for the possibility of duplicate group-by clauses ---
-                * the parser should have removed 'em, but the Sort executor
-                * will get terribly confused if any get through!
-                */
-               if (resdom->reskey == 0)
-               {
-                       /* OK, insert the ordering info needed by the executor. */
-                       resdom->reskey = ++keyno;
-                       resdom->reskeyop = grpcl->sortop;
-               }
-       }
-
-       Assert(keyno > 0);
-
-       return (Plan *) make_sort(parse, sort_tlist, subplan, keyno);
-}
-
 /*
  * postprocess_setop_tlist
  *       Fix up targetlist returned by plan_set_operations().
@@ -1471,7 +1508,7 @@ make_groupsortplan(Query *parse,
  * 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 elog if we
+ * new tlist to evaluate the resjunk columns.  For now, just ereport if we
  * find any resjunk columns in orig_tlist.
  */
 static List *
@@ -1491,13 +1528,13 @@ postprocess_setop_tlist(List *new_tlist, List *orig_tlist)
                Assert(orig_tlist != NIL);
                orig_tle = (TargetEntry *) lfirst(orig_tlist);
                orig_tlist = lnext(orig_tlist);
-               if (orig_tle->resdom->resjunk)
-                       elog(ERROR, "postprocess_setop_tlist: resjunk output columns not implemented");
+               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, "postprocess_setop_tlist: resjunk output columns not implemented");
+               elog(ERROR, "resjunk output columns are not implemented");
        return new_tlist;
 }