summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c116
1 files changed, 21 insertions, 95 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 032818423f6..ddd23878409 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -54,7 +54,6 @@
#include "optimizer/tlist.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
-#include "parser/parse_clause.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "partitioning/partdesc.h"
@@ -120,15 +119,12 @@ typedef struct
{
List *activeWindows; /* active windows, if any */
grouping_sets_data *gset_data; /* grouping sets data, if any */
- SetOperationStmt *setop; /* parent set operation or NULL if not a
- * subquery belonging to a set operation */
} standard_qp_extra;
/* Local functions */
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
-static void grouping_planner(PlannerInfo *root, double tuple_fraction,
- SetOperationStmt *setops);
+static void grouping_planner(PlannerInfo *root, double tuple_fraction);
static grouping_sets_data *preprocess_grouping_sets(PlannerInfo *root);
static List *remap_to_groupclause_idx(List *groupClause, List *gsets,
int *tleref_to_colnum_map);
@@ -253,8 +249,6 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
List *targetList,
List *groupClause);
static int common_prefix_cmp(const void *a, const void *b);
-static List *generate_setop_child_grouplist(SetOperationStmt *op,
- List *targetlist);
/*****************************************************************************
@@ -412,7 +406,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
}
/* primary planning entry point (may recurse for subqueries) */
- root = subquery_planner(glob, parse, NULL, false, tuple_fraction, NULL);
+ root = subquery_planner(glob, parse, NULL,
+ false, tuple_fraction);
/* Select best Path and turn it into a Plan */
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@@ -603,10 +598,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
* hasRecursion is true if this is a recursive WITH query.
* tuple_fraction is the fraction of tuples we expect will be retrieved.
* tuple_fraction is interpreted as explained for grouping_planner, below.
- * setops is used for set operation subqueries to provide the subquery with
- * the context in which it's being used so that Paths correctly sorted for the
- * set operation can be generated. NULL when not planning a set operation
- * child.
*
* Basically, this routine does the stuff that should only be done once
* per Query object. It then calls grouping_planner. At one time,
@@ -625,9 +616,9 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*--------------------
*/
PlannerInfo *
-subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
- bool hasRecursion, double tuple_fraction,
- SetOperationStmt *setops)
+subquery_planner(PlannerGlobal *glob, Query *parse,
+ PlannerInfo *parent_root,
+ bool hasRecursion, double tuple_fraction)
{
PlannerInfo *root;
List *newWithCheckOptions;
@@ -1086,7 +1077,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
/*
* Do the main planning.
*/
- grouping_planner(root, tuple_fraction, setops);
+ grouping_planner(root, tuple_fraction);
/*
* Capture the set of outer-level param IDs we have access to, for use in
@@ -1284,11 +1275,7 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
* 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).
- * setops is used for set operation subqueries to provide the subquery with
- * the context in which it's being used so that Paths correctly sorted for the
- * set operation can be generated. NULL when not planning a set operation
- * child.
+ * expected to be retrieved (ie, a LIMIT specification)
*
* Returns nothing; the useful output is in the Paths we attach to the
* (UPPERREL_FINAL, NULL) upperrel in *root. In addition,
@@ -1299,8 +1286,7 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
*--------------------
*/
static void
-grouping_planner(PlannerInfo *root, double tuple_fraction,
- SetOperationStmt *setops)
+grouping_planner(PlannerInfo *root, double tuple_fraction)
{
Query *parse = root->parse;
int64 offset_est = 0;
@@ -1336,6 +1322,17 @@ grouping_planner(PlannerInfo *root, double tuple_fraction,
if (parse->setOperations)
{
/*
+ * If there's a top-level ORDER BY, assume we have to fetch all the
+ * tuples. This might be too simplistic given all the hackery below
+ * to possibly avoid the sort; but the odds of accurate estimates here
+ * are pretty low anyway. XXX try to get rid of this in favor of
+ * letting plan_set_operations generate both fast-start and
+ * cheapest-total paths.
+ */
+ if (parse->sortClause)
+ root->tuple_fraction = 0.0;
+
+ /*
* Construct Paths for set operations. The results will not need any
* work except perhaps a top-level sort and/or LIMIT. Note that any
* special work for recursive unions is the responsibility of
@@ -1505,12 +1502,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction,
qp_extra.gset_data = gset_data;
/*
- * If we're a subquery for a set operation, store the SetOperationStmt
- * in qp_extra.
- */
- qp_extra.setop = setops;
-
- /*
* Generate the best unsorted and presorted paths for the scan/join
* portion of this Query, ie the processing represented by the
* FROM/WHERE clauses. (Note there may not be any presorted paths.)
@@ -3462,27 +3453,6 @@ standard_qp_callback(PlannerInfo *root, void *extra)
parse->sortClause,
tlist);
- /* setting setop_pathkeys might be useful to the union planner */
- if (qp_extra->setop != NULL &&
- set_operation_ordered_results_useful(qp_extra->setop))
- {
- List *groupClauses;
- bool sortable;
-
- groupClauses = generate_setop_child_grouplist(qp_extra->setop, tlist);
-
- root->setop_pathkeys =
- make_pathkeys_for_sortclauses_extended(root,
- &groupClauses,
- tlist,
- false,
- &sortable);
- if (!sortable)
- root->setop_pathkeys = NIL;
- }
- else
- root->setop_pathkeys = NIL;
-
/*
* Figure out whether we want a sorted result from query_planner.
*
@@ -3492,9 +3462,7 @@ standard_qp_callback(PlannerInfo *root, void *extra)
* sortable DISTINCT clause that's more rigorous than the ORDER BY clause,
* we try to produce output that's sufficiently well sorted for the
* DISTINCT. Otherwise, if there is an ORDER BY clause, we want to sort
- * by the ORDER BY clause. Otherwise, if we're a subquery being planned
- * for a set operation which can benefit from presorted results and have a
- * sortable targetlist, we want to sort by the target list.
+ * by the ORDER BY clause.
*
* Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset
* of GROUP BY, it would be tempting to request sort by ORDER BY --- but
@@ -3512,8 +3480,6 @@ standard_qp_callback(PlannerInfo *root, void *extra)
root->query_pathkeys = root->distinct_pathkeys;
else if (root->sort_pathkeys)
root->query_pathkeys = root->sort_pathkeys;
- else if (root->setop_pathkeys != NIL)
- root->query_pathkeys = root->setop_pathkeys;
else
root->query_pathkeys = NIL;
}
@@ -7957,43 +7923,3 @@ group_by_has_partkey(RelOptInfo *input_rel,
return true;
}
-
-/*
- * generate_setop_child_grouplist
- * Build a SortGroupClause list defining the sort/grouping properties
- * of the child of a set operation.
- *
- * This is similar to generate_setop_grouplist() but differs as the setop
- * child query's targetlist entries may already have a tleSortGroupRef
- * assigned for other purposes, such as GROUP BYs. Here we keep the
- * SortGroupClause list in the same order as 'op' groupClauses and just adjust
- * the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'.
- */
-static List *
-generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist)
-{
- List *grouplist = copyObject(op->groupClauses);
- ListCell *lg;
- ListCell *lt;
-
- lg = list_head(grouplist);
- foreach(lt, targetlist)
- {
- TargetEntry *tle = (TargetEntry *) lfirst(lt);
- SortGroupClause *sgc;
-
- /* resjunk columns could have sortgrouprefs. Leave these alone */
- if (tle->resjunk)
- continue;
-
- /* we expect every non-resjunk target to have a SortGroupClause */
- Assert(lg != NULL);
- sgc = (SortGroupClause *) lfirst(lg);
- lg = lnext(grouplist, lg);
-
- /* assign a tleSortGroupRef, or reuse the existing one */
- sgc->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
- }
- Assert(lg == NULL);
- return grouplist;
-}