summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/createplan.c107
-rw-r--r--src/backend/optimizer/plan/initsplan.c28
-rw-r--r--src/backend/optimizer/plan/planagg.c85
-rw-r--r--src/backend/optimizer/plan/planmain.c30
-rw-r--r--src/backend/optimizer/plan/planner.c241
-rw-r--r--src/backend/optimizer/plan/subselect.c41
6 files changed, 272 insertions, 260 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index b743c8348e..5c1142cd0e 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.190 2005/05/30 18:55:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.191 2005/06/05 22:32:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,36 +35,36 @@
#include "utils/syscache.h"
-static Scan *create_scan_plan(Query *root, Path *best_path);
+static Scan *create_scan_plan(PlannerInfo *root, Path *best_path);
static List *build_relation_tlist(RelOptInfo *rel);
static bool use_physical_tlist(RelOptInfo *rel);
static void disuse_physical_tlist(Plan *plan, Path *path);
-static Join *create_join_plan(Query *root, JoinPath *best_path);
-static Append *create_append_plan(Query *root, AppendPath *best_path);
-static Result *create_result_plan(Query *root, ResultPath *best_path);
-static Material *create_material_plan(Query *root, MaterialPath *best_path);
-static Plan *create_unique_plan(Query *root, UniquePath *best_path);
-static SeqScan *create_seqscan_plan(Query *root, Path *best_path,
+static Join *create_join_plan(PlannerInfo *root, JoinPath *best_path);
+static Append *create_append_plan(PlannerInfo *root, AppendPath *best_path);
+static Result *create_result_plan(PlannerInfo *root, ResultPath *best_path);
+static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path);
+static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path);
+static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses);
-static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
+static IndexScan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path,
List *tlist, List *scan_clauses,
List **nonlossy_clauses);
-static BitmapHeapScan *create_bitmap_scan_plan(Query *root,
+static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root,
BitmapHeapPath *best_path,
List *tlist, List *scan_clauses);
-static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual,
+static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual, List **indexqual);
-static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
+static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses);
-static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
+static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses);
-static FunctionScan *create_functionscan_plan(Query *root, Path *best_path,
+static FunctionScan *create_functionscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses);
-static NestLoop *create_nestloop_plan(Query *root, NestPath *best_path,
+static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path,
Plan *outer_plan, Plan *inner_plan);
-static MergeJoin *create_mergejoin_plan(Query *root, MergePath *best_path,
+static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path,
Plan *outer_plan, Plan *inner_plan);
-static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
+static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path,
Plan *outer_plan, Plan *inner_plan);
static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
List **fixed_indexquals,
@@ -112,9 +112,9 @@ static MergeJoin *make_mergejoin(List *tlist,
List *mergeclauses,
Plan *lefttree, Plan *righttree,
JoinType jointype);
-static Sort *make_sort(Query *root, Plan *lefttree, int numCols,
+static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
AttrNumber *sortColIdx, Oid *sortOperators);
-static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
+static Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
List *pathkeys);
@@ -134,7 +134,7 @@ static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
* Returns a Plan tree.
*/
Plan *
-create_plan(Query *root, Path *best_path)
+create_plan(PlannerInfo *root, Path *best_path)
{
Plan *plan;
@@ -187,7 +187,7 @@ create_plan(Query *root, Path *best_path)
* Returns a Plan node.
*/
static Scan *
-create_scan_plan(Query *root, Path *best_path)
+create_scan_plan(PlannerInfo *root, Path *best_path)
{
RelOptInfo *rel = best_path->parent;
List *tlist;
@@ -376,7 +376,7 @@ disuse_physical_tlist(Plan *plan, Path *path)
* Returns a Plan node.
*/
static Join *
-create_join_plan(Query *root, JoinPath *best_path)
+create_join_plan(PlannerInfo *root, JoinPath *best_path)
{
Plan *outer_plan;
Plan *inner_plan;
@@ -436,7 +436,7 @@ create_join_plan(Query *root, JoinPath *best_path)
* Returns a Plan node.
*/
static Append *
-create_append_plan(Query *root, AppendPath *best_path)
+create_append_plan(PlannerInfo *root, AppendPath *best_path)
{
Append *plan;
List *tlist = build_relation_tlist(best_path->path.parent);
@@ -463,7 +463,7 @@ create_append_plan(Query *root, AppendPath *best_path)
* Returns a Plan node.
*/
static Result *
-create_result_plan(Query *root, ResultPath *best_path)
+create_result_plan(PlannerInfo *root, ResultPath *best_path)
{
Result *plan;
List *tlist;
@@ -495,7 +495,7 @@ create_result_plan(Query *root, ResultPath *best_path)
* Returns a Plan node.
*/
static Material *
-create_material_plan(Query *root, MaterialPath *best_path)
+create_material_plan(PlannerInfo *root, MaterialPath *best_path)
{
Material *plan;
Plan *subplan;
@@ -520,7 +520,7 @@ create_material_plan(Query *root, MaterialPath *best_path)
* Returns a Plan node.
*/
static Plan *
-create_unique_plan(Query *root, UniquePath *best_path)
+create_unique_plan(PlannerInfo *root, UniquePath *best_path)
{
Plan *plan;
Plan *subplan;
@@ -535,7 +535,7 @@ create_unique_plan(Query *root, UniquePath *best_path)
subplan = create_plan(root, best_path->subpath);
- /*
+ /*----------
* As constructed, the subplan has a "flat" tlist containing just the
* Vars needed here and at upper levels. The values we are supposed
* to unique-ify may be expressions in these variables. We have to
@@ -545,19 +545,20 @@ create_unique_plan(Query *root, UniquePath *best_path)
* existing subplan outputs, not all the output columns may be used
* for grouping.)
*
- * Note: the reason we don't remove any subplan outputs is that there are
- * scenarios where a Var is needed at higher levels even though it is
- * not one of the nominal outputs of an IN clause. Consider WHERE x
- * IN (SELECT y FROM t1,t2 WHERE y = z) Implied equality deduction
- * will generate an "x = z" clause, which may get used instead of "x =
- * y" in the upper join step. Therefore the sub-select had better
- * deliver both y and z in its targetlist. It is sufficient to
- * unique-ify on y, however.
+ * Note: the reason we don't remove any subplan outputs is that there
+ * are scenarios where a Var is needed at higher levels even though
+ * it is not one of the nominal outputs of an IN clause. Consider
+ * WHERE x IN (SELECT y FROM t1,t2 WHERE y = z)
+ * Implied equality deduction will generate an "x = z" clause, which may
+ * get used instead of "x = y" in the upper join step. Therefore the
+ * sub-select had better deliver both y and z in its targetlist.
+ * It is sufficient to unique-ify on y, however.
*
* To find the correct list of values to unique-ify, we look in the
* information saved for IN expressions. If this code is ever used in
* other scenarios, some other way of finding what to unique-ify will
* be needed.
+ *----------
*/
uniq_exprs = NIL; /* just to keep compiler quiet */
foreach(l, root->in_info_list)
@@ -672,7 +673,7 @@ create_unique_plan(Query *root, UniquePath *best_path)
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static SeqScan *
-create_seqscan_plan(Query *root, Path *best_path,
+create_seqscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
SeqScan *scan_plan;
@@ -710,7 +711,7 @@ create_seqscan_plan(Query *root, Path *best_path,
* nonlossy indexquals.
*/
static IndexScan *
-create_indexscan_plan(Query *root,
+create_indexscan_plan(PlannerInfo *root,
IndexPath *best_path,
List *tlist,
List *scan_clauses,
@@ -827,7 +828,7 @@ create_indexscan_plan(Query *root,
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static BitmapHeapScan *
-create_bitmap_scan_plan(Query *root,
+create_bitmap_scan_plan(PlannerInfo *root,
BitmapHeapPath *best_path,
List *tlist,
List *scan_clauses)
@@ -925,7 +926,7 @@ create_bitmap_scan_plan(Query *root,
* exclude lossy index operators.
*/
static Plan *
-create_bitmap_subplan(Query *root, Path *bitmapqual,
+create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual, List **indexqual)
{
Plan *plan;
@@ -1029,7 +1030,7 @@ create_bitmap_subplan(Query *root, Path *bitmapqual,
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static TidScan *
-create_tidscan_plan(Query *root, TidPath *best_path,
+create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses)
{
TidScan *scan_plan;
@@ -1061,7 +1062,7 @@ create_tidscan_plan(Query *root, TidPath *best_path,
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static SubqueryScan *
-create_subqueryscan_plan(Query *root, Path *best_path,
+create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
SubqueryScan *scan_plan;
@@ -1093,7 +1094,7 @@ create_subqueryscan_plan(Query *root, Path *best_path,
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static FunctionScan *
-create_functionscan_plan(Query *root, Path *best_path,
+create_functionscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses)
{
FunctionScan *scan_plan;
@@ -1123,7 +1124,7 @@ create_functionscan_plan(Query *root, Path *best_path,
*****************************************************************************/
static NestLoop *
-create_nestloop_plan(Query *root,
+create_nestloop_plan(PlannerInfo *root,
NestPath *best_path,
Plan *outer_plan,
Plan *inner_plan)
@@ -1213,7 +1214,7 @@ create_nestloop_plan(Query *root,
}
static MergeJoin *
-create_mergejoin_plan(Query *root,
+create_mergejoin_plan(PlannerInfo *root,
MergePath *best_path,
Plan *outer_plan,
Plan *inner_plan)
@@ -1296,7 +1297,7 @@ create_mergejoin_plan(Query *root,
}
static HashJoin *
-create_hashjoin_plan(Query *root,
+create_hashjoin_plan(PlannerInfo *root,
HashPath *best_path,
Plan *outer_plan,
Plan *inner_plan)
@@ -1608,14 +1609,14 @@ get_switched_clauses(List *clauses, Relids outerrelids)
* InitPlan references) to the end of the list.
*/
List *
-order_qual_clauses(Query *root, List *clauses)
+order_qual_clauses(PlannerInfo *root, List *clauses)
{
List *nosubplans;
List *withsubplans;
ListCell *l;
/* No need to work hard if the query is subselect-free */
- if (!root->hasSubLinks)
+ if (!root->parse->hasSubLinks)
return clauses;
nosubplans = NIL;
@@ -2018,7 +2019,7 @@ make_mergejoin(List *tlist,
* Caller must have built the sortColIdx and sortOperators arrays already.
*/
static Sort *
-make_sort(Query *root, Plan *lefttree, int numCols,
+make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
AttrNumber *sortColIdx, Oid *sortOperators)
{
Sort *node = makeNode(Sort);
@@ -2090,7 +2091,7 @@ add_sort_column(AttrNumber colIdx, Oid sortOp,
* adding a Result node just to do the projection.
*/
static Sort *
-make_sort_from_pathkeys(Query *root, Plan *lefttree, List *pathkeys)
+make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
{
List *tlist = lefttree->targetlist;
ListCell *i;
@@ -2201,7 +2202,7 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree, List *pathkeys)
* 'lefttree' is the node which yields input tuples
*/
Sort *
-make_sort_from_sortclauses(Query *root, List *sortcls, Plan *lefttree)
+make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
{
List *sub_tlist = lefttree->targetlist;
ListCell *l;
@@ -2253,7 +2254,7 @@ make_sort_from_sortclauses(Query *root, List *sortcls, Plan *lefttree)
* GroupClause entries.
*/
Sort *
-make_sort_from_groupcols(Query *root,
+make_sort_from_groupcols(PlannerInfo *root,
List *groupcls,
AttrNumber *grpColIdx,
Plan *lefttree)
@@ -2347,7 +2348,7 @@ materialize_finished_plan(Plan *subplan)
}
Agg *
-make_agg(Query *root, List *tlist, List *qual,
+make_agg(PlannerInfo *root, List *tlist, List *qual,
AggStrategy aggstrategy,
int numGroupCols, AttrNumber *grpColIdx,
long numGroups, int numAggs,
@@ -2412,7 +2413,7 @@ make_agg(Query *root, List *tlist, List *qual,
}
Group *
-make_group(Query *root,
+make_group(PlannerInfo *root,
List *tlist,
List *qual,
int numGroupCols,
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 22878c0099..c5b0276379 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.105 2005/04/28 21:47:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.106 2005/06/05 22:32:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,16 +34,16 @@
#include "utils/syscache.h"
-static void mark_baserels_for_outer_join(Query *root, Relids rels,
+static void mark_baserels_for_outer_join(PlannerInfo *root, Relids rels,
Relids outerrels);
-static void distribute_qual_to_rels(Query *root, Node *clause,
+static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
bool is_pushed_down,
bool isdeduced,
Relids outerjoin_nonnullable,
Relids qualscope);
-static void add_vars_to_targetlist(Query *root, List *vars,
+static void add_vars_to_targetlist(PlannerInfo *root, List *vars,
Relids where_needed);
-static bool qual_is_redundant(Query *root, RestrictInfo *restrictinfo,
+static bool qual_is_redundant(PlannerInfo *root, RestrictInfo *restrictinfo,
List *restrictlist);
static void check_mergejoinable(RestrictInfo *restrictinfo);
static void check_hashjoinable(RestrictInfo *restrictinfo);
@@ -68,7 +68,7 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
* will be used later to build rels for inheritance children.
*/
void
-add_base_rels_to_query(Query *root, Node *jtnode)
+add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
{
if (jtnode == NULL)
return;
@@ -114,7 +114,7 @@ add_base_rels_to_query(Query *root, Node *jtnode)
* propagate up through all join plan steps.
*/
void
-build_base_rel_tlists(Query *root, List *final_tlist)
+build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
{
List *tlist_vars = pull_var_clause((Node *) final_tlist, false);
@@ -133,7 +133,7 @@ build_base_rel_tlists(Query *root, List *final_tlist)
* where_needed includes "relation 0").
*/
static void
-add_vars_to_targetlist(Query *root, List *vars, Relids where_needed)
+add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
{
ListCell *temp;
@@ -189,7 +189,7 @@ add_vars_to_targetlist(Query *root, List *vars, Relids where_needed)
* internal convenience; no outside callers pay attention to the result.
*/
Relids
-distribute_quals_to_rels(Query *root, Node *jtnode)
+distribute_quals_to_rels(PlannerInfo *root, Node *jtnode)
{
Relids result = NULL;
@@ -306,7 +306,7 @@ distribute_quals_to_rels(Query *root, Node *jtnode)
* Mark all base rels listed in 'rels' as having the given outerjoinset.
*/
static void
-mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
+mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels)
{
Relids tmprelids;
int relno;
@@ -333,7 +333,7 @@ mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
*/
if (rel->outerjoinset == NULL)
{
- if (list_member_int(root->rowMarks, relno))
+ if (list_member_int(root->parse->rowMarks, relno))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join")));
@@ -367,7 +367,7 @@ mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
* 'is_pushed_down' will be TRUE.
*/
static void
-distribute_qual_to_rels(Query *root, Node *clause,
+distribute_qual_to_rels(PlannerInfo *root, Node *clause,
bool is_pushed_down,
bool isdeduced,
Relids outerjoin_nonnullable,
@@ -626,7 +626,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
* for more details.
*/
void
-process_implied_equality(Query *root,
+process_implied_equality(PlannerInfo *root,
Node *item1, Node *item2,
Oid sortop1, Oid sortop2,
Relids item1_relids, Relids item2_relids,
@@ -796,7 +796,7 @@ process_implied_equality(Query *root,
* all the "var = const" quals.
*/
static bool
-qual_is_redundant(Query *root,
+qual_is_redundant(PlannerInfo *root,
RestrictInfo *restrictinfo,
List *restrictlist)
{
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 38c859dfbc..0a47799707 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.4 2005/04/22 21:58:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.5 2005/06/05 22:32:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,11 +42,11 @@ typedef struct
} MinMaxAggInfo;
static bool find_minmax_aggs_walker(Node *node, List **context);
-static bool build_minmax_path(Query *root, RelOptInfo *rel,
+static bool build_minmax_path(PlannerInfo *root, RelOptInfo *rel,
MinMaxAggInfo *info);
static ScanDirection match_agg_to_index_col(MinMaxAggInfo *info,
IndexOptInfo *index, int indexcol);
-static void make_agg_subplan(Query *root, MinMaxAggInfo *info,
+static void make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info,
List *constant_quals);
static Node *replace_aggs_with_params_mutator(Node *node, List **context);
static Oid fetch_agg_sort_op(Oid aggfnoid);
@@ -61,15 +61,16 @@ static Oid fetch_agg_sort_op(Oid aggfnoid);
* Given a suitable index on tab.col, this can be much faster than the
* generic scan-all-the-rows plan.
*
- * We are passed the Query, the preprocessed tlist, and the best path
+ * We are passed the preprocessed tlist, and the best path
* devised for computing the input of a standard Agg node. If we are able
* to optimize all the aggregates, and the result is estimated to be cheaper
* than the generic aggregate method, then generate and return a Plan that
* does it that way. Otherwise, return NULL.
*/
Plan *
-optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
+optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
{
+ Query *parse = root->parse;
RangeTblRef *rtr;
RangeTblEntry *rte;
RelOptInfo *rel;
@@ -83,11 +84,11 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
List *constant_quals;
/* Nothing to do if query has no aggregates */
- if (!root->hasAggs)
+ if (!parse->hasAggs)
return NULL;
- Assert(!root->setOperations); /* shouldn't get here if a setop */
- Assert(root->rowMarks == NIL); /* nor if FOR UPDATE */
+ Assert(!parse->setOperations); /* shouldn't get here if a setop */
+ Assert(parse->rowMarks == NIL); /* nor if FOR UPDATE */
/*
* Reject unoptimizable cases.
@@ -96,7 +97,7 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
* grouping require looking at all the rows anyway, and so there's not
* much point in optimizing MIN/MAX.
*/
- if (root->groupClause)
+ if (parse->groupClause)
return NULL;
/*
@@ -105,13 +106,13 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
* handle a query containing cartesian-product joins, but it hardly
* seems worth the trouble.)
*/
- Assert(root->jointree != NULL && IsA(root->jointree, FromExpr));
- if (list_length(root->jointree->fromlist) != 1)
+ Assert(parse->jointree != NULL && IsA(parse->jointree, FromExpr));
+ if (list_length(parse->jointree->fromlist) != 1)
return NULL;
- rtr = (RangeTblRef *) linitial(root->jointree->fromlist);
+ rtr = (RangeTblRef *) linitial(parse->jointree->fromlist);
if (!IsA(rtr, RangeTblRef))
return NULL;
- rte = rt_fetch(rtr->rtindex, root->rtable);
+ rte = rt_fetch(rtr->rtindex, parse->rtable);
if (rte->rtekind != RTE_RELATION)
return NULL;
rel = find_base_rel(root, rtr->rtindex);
@@ -121,8 +122,8 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
* This may be overly paranoid, but it's not entirely clear if the
* transformation is safe then.
*/
- if (contain_subplans(root->jointree->quals) ||
- contain_volatile_functions(root->jointree->quals))
+ if (contain_subplans(parse->jointree->quals) ||
+ contain_volatile_functions(parse->jointree->quals))
return NULL;
/*
@@ -143,7 +144,7 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
aggs_list = NIL;
if (find_minmax_aggs_walker((Node *) tlist, &aggs_list))
return NULL;
- if (find_minmax_aggs_walker(root->havingQual, &aggs_list))
+ if (find_minmax_aggs_walker(parse->havingQual, &aggs_list))
return NULL;
/* Pass 2: see if each one is optimizable */
@@ -202,7 +203,7 @@ optimize_minmax_aggregates(Query *root, List *tlist, Path *best_path)
*/
tlist = (List *) replace_aggs_with_params_mutator((Node *) tlist,
&aggs_list);
- hqual = replace_aggs_with_params_mutator(root->havingQual,
+ hqual = replace_aggs_with_params_mutator(parse->havingQual,
&aggs_list);
/*
@@ -298,7 +299,7 @@ find_minmax_aggs_walker(Node *node, List **context)
* Note: check_partial_indexes() must have been run previously.
*/
static bool
-build_minmax_path(Query *root, RelOptInfo *rel, MinMaxAggInfo *info)
+build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
{
IndexPath *best_path = NULL;
Cost best_cost = 0;
@@ -441,46 +442,48 @@ match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
* Construct a suitable plan for a converted aggregate query
*/
static void
-make_agg_subplan(Query *root, MinMaxAggInfo *info, List *constant_quals)
+make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals)
{
- Query *subquery;
+ PlannerInfo subroot;
+ Query *subparse;
Plan *plan;
TargetEntry *tle;
SortClause *sortcl;
NullTest *ntest;
/*
- * Generate a suitably modified Query node. Much of the work here is
+ * Generate a suitably modified query. Much of the work here is
* probably unnecessary in the normal case, but we want to make it look
* good if someone tries to EXPLAIN the result.
*/
- subquery = (Query *) copyObject(root);
- subquery->commandType = CMD_SELECT;
- subquery->resultRelation = 0;
- subquery->resultRelations = NIL;
- subquery->into = NULL;
- subquery->hasAggs = false;
- subquery->groupClause = NIL;
- subquery->havingQual = NULL;
- subquery->hasHavingQual = false;
- subquery->distinctClause = NIL;
+ memcpy(&subroot, root, sizeof(PlannerInfo));
+ subroot.parse = subparse = (Query *) copyObject(root->parse);
+ subparse->commandType = CMD_SELECT;
+ subparse->resultRelation = 0;
+ subparse->resultRelations = NIL;
+ subparse->into = NULL;
+ subparse->hasAggs = false;
+ subparse->groupClause = NIL;
+ subparse->havingQual = NULL;
+ subparse->distinctClause = NIL;
+ subroot.hasHavingQual = false;
/* single tlist entry that is the aggregate target */
tle = makeTargetEntry(copyObject(info->target),
1,
pstrdup("agg_target"),
false);
- subquery->targetList = list_make1(tle);
+ subparse->targetList = list_make1(tle);
/* set up the appropriate ORDER BY entry */
sortcl = makeNode(SortClause);
- sortcl->tleSortGroupRef = assignSortGroupRef(tle, subquery->targetList);
+ sortcl->tleSortGroupRef = assignSortGroupRef(tle, subparse->targetList);
sortcl->sortop = info->aggsortop;
- subquery->sortClause = list_make1(sortcl);
+ subparse->sortClause = list_make1(sortcl);
/* set up LIMIT 1 */
- subquery->limitOffset = NULL;
- subquery->limitCount = (Node *) makeConst(INT4OID, sizeof(int4),
+ subparse->limitOffset = NULL;
+ subparse->limitCount = (Node *) makeConst(INT4OID, sizeof(int4),
Int32GetDatum(1),
false, true);
@@ -498,9 +501,9 @@ make_agg_subplan(Query *root, MinMaxAggInfo *info, List *constant_quals)
* most cases the fraction of NULLs isn't high enough to change the
* decision.
*/
- plan = create_plan(subquery, (Path *) info->path);
+ plan = create_plan(&subroot, (Path *) info->path);
- plan->targetlist = copyObject(subquery->targetList);
+ plan->targetlist = copyObject(subparse->targetList);
ntest = makeNode(NullTest);
ntest->nulltesttype = IS_NOT_NULL;
@@ -514,13 +517,13 @@ make_agg_subplan(Query *root, MinMaxAggInfo *info, List *constant_quals)
plan);
plan = (Plan *) make_limit(plan,
- subquery->limitOffset,
- subquery->limitCount);
+ subparse->limitOffset,
+ subparse->limitCount);
/*
* Convert the plan into an InitPlan, and make a Param for its result.
*/
- info->param = SS_make_initplan_from_plan(subquery, plan,
+ info->param = SS_make_initplan_from_plan(&subroot, plan,
exprType((Node *) tle->expr),
-1);
}
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 78b2d127fa..79a28cae3a 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.81 2004/12/31 22:00:09 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.82 2005/06/05 22:32:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,8 +42,9 @@
* will make the final decision about which to use.
*
* Input parameters:
- * root is the query to plan
- * tlist is the target list the query should produce (NOT root->targetList!)
+ * root describes the query to plan
+ * tlist is the target list the query should produce
+ * (this is NOT necessarily root->parse->targetList!)
* tuple_fraction is the fraction of tuples we expect will be retrieved
*
* Output parameters:
@@ -51,14 +52,14 @@
* *sorted_path receives the cheapest presorted path for the query,
* if any (NULL if there is no useful presorted path)
*
- * Note: the Query node also includes a query_pathkeys field, which is both
- * an input and an output of query_planner(). The input value signals
+ * Note: the PlannerInfo node also includes a query_pathkeys field, which is
+ * both an input and an output of query_planner(). The input value signals
* query_planner that the indicated sort order is wanted in the final output
* plan. But this value has not yet been "canonicalized", since the needed
* info does not get computed until we scan the qual clauses. We canonicalize
* it as soon as that task is done. (The main reason query_pathkeys is a
- * Query field and not a passed parameter is that the low-level routines in
- * indxpath.c need to see it.)
+ * PlannerInfo field and not a passed parameter is that the low-level routines
+ * in indxpath.c need to see it.)
*
* tuple_fraction is interpreted as follows:
* 0: expect all tuples to be retrieved (normal case)
@@ -69,9 +70,10 @@
*--------------------
*/
void
-query_planner(Query *root, List *tlist, double tuple_fraction,
+query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
Path **cheapest_path, Path **sorted_path)
{
+ Query *parse = root->parse;
List *constant_quals;
RelOptInfo *final_rel;
Path *cheapestpath;
@@ -81,10 +83,10 @@ query_planner(Query *root, List *tlist, double tuple_fraction,
* If the query has an empty join tree, then it's something easy like
* "SELECT 2+2;" or "INSERT ... VALUES()". Fall through quickly.
*/
- if (root->jointree->fromlist == NIL)
+ if (parse->jointree->fromlist == NIL)
{
*cheapest_path = (Path *) create_result_path(NULL, NULL,
- (List *) root->jointree->quals);
+ (List *) parse->jointree->quals);
*sorted_path = NULL;
return;
}
@@ -99,8 +101,8 @@ query_planner(Query *root, List *tlist, double tuple_fraction,
* vars, although if the qual reduces to "WHERE FALSE" this path will
* also be taken.
*/
- root->jointree->quals = (Node *)
- pull_constant_clauses((List *) root->jointree->quals,
+ parse->jointree->quals = (Node *)
+ pull_constant_clauses((List *) parse->jointree->quals,
&constant_quals);
/*
@@ -116,7 +118,7 @@ query_planner(Query *root, List *tlist, double tuple_fraction,
/*
* Construct RelOptInfo nodes for all base relations in query.
*/
- add_base_rels_to_query(root, (Node *) root->jointree);
+ add_base_rels_to_query(root, (Node *) parse->jointree);
/*
* Examine the targetlist and qualifications, adding entries to
@@ -133,7 +135,7 @@ query_planner(Query *root, List *tlist, double tuple_fraction,
*/
build_base_rel_tlists(root, tlist);
- (void) distribute_quals_to_rels(root, (Node *) root->jointree);
+ (void) distribute_quals_to_rels(root, (Node *) parse->jointree);
/*
* Use the completed lists of equijoined keys to deduce any implied
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 858f960aaf..76ffe04078 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.187 2005/05/30 01:04:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.188 2005/06/05 22:32:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,18 +54,18 @@ ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
#define EXPRKIND_ININFO 4
-static Node *preprocess_expression(Query *parse, Node *expr, int kind);
-static void preprocess_qual_conditions(Query *parse, Node *jtnode);
-static Plan *inheritance_planner(Query *parse, List *inheritlist);
-static Plan *grouping_planner(Query *parse, double tuple_fraction);
-static bool choose_hashed_grouping(Query *parse, double tuple_fraction,
+static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
+static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
+static Plan *inheritance_planner(PlannerInfo *root, List *inheritlist);
+static Plan *grouping_planner(PlannerInfo *root, double tuple_fraction);
+static bool choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
Path *cheapest_path, Path *sorted_path,
List *sort_pathkeys, List *group_pathkeys,
double dNumGroups, AggClauseCounts *agg_counts);
-static bool hash_safe_grouping(Query *parse);
-static List *make_subplanTargetList(Query *parse, List *tlist,
+static bool hash_safe_grouping(PlannerInfo *root);
+static List *make_subplanTargetList(PlannerInfo *root, List *tlist,
AttrNumber **groupColIdx, bool *need_tlist_eval);
-static void locate_grouping_columns(Query *parse,
+static void locate_grouping_columns(PlannerInfo *root,
List *tlist,
List *sub_tlist,
AttrNumber *groupColIdx);
@@ -92,10 +92,10 @@ planner(Query *parse, bool isCursor, int cursorOptions,
* eval_const_expressions tries to pre-evaluate an SQL function). So,
* these global state variables must be saved and restored.
*
- * Query level and the param list cannot be moved into the Query
- * structure since their whole purpose is communication across
- * multiple sub-Queries. Also, boundParams is explicitly info from
- * outside the Query, and so is likewise better handled as a global
+ * Query level and the param list cannot be moved into the per-query
+ * PlannerInfo structure since their whole purpose is communication
+ * across multiple sub-queries. Also, boundParams is explicitly info
+ * from outside the query, and so is likewise better handled as a global
* variable.
*
* Note we do NOT save and restore PlannerPlanId: it exists to assign
@@ -130,8 +130,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
}
/* primary planning entry point (may recurse for subqueries) */
- result_plan = subquery_planner(parse, tuple_fraction);
+ result_plan = subquery_planner(parse, tuple_fraction, NULL);
+ /* check we popped out the right number of levels */
Assert(PlannerQueryLevel == 0);
/*
@@ -168,6 +169,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
* tuple_fraction is the fraction of tuples we expect will be retrieved.
* tuple_fraction is interpreted as explained for grouping_planner, below.
*
+ * If subquery_pathkeys isn't NULL, it receives a list of pathkeys indicating
+ * the output sort ordering of the completed plan.
+ *
* Basically, this routine does the stuff that should only be done once
* per Query object. It then calls grouping_planner. At one time,
* grouping_planner could be invoked recursively on the same Query object;
@@ -181,12 +185,14 @@ planner(Query *parse, bool isCursor, int cursorOptions,
*--------------------
*/
Plan *
-subquery_planner(Query *parse, double tuple_fraction)
+subquery_planner(Query *parse, double tuple_fraction,
+ List **subquery_pathkeys)
{
List *saved_initplan = PlannerInitPlan;
int saved_planid = PlannerPlanId;
- bool hasOuterJoins;
+ PlannerInfo *root;
Plan *plan;
+ bool hasOuterJoins;
List *newHaving;
List *lst;
ListCell *l;
@@ -195,23 +201,27 @@ subquery_planner(Query *parse, double tuple_fraction)
PlannerQueryLevel++;
PlannerInitPlan = NIL;
+ /* Create a PlannerInfo data structure for this subquery */
+ root = makeNode(PlannerInfo);
+ root->parse = parse;
+
/*
* Look for IN clauses at the top level of WHERE, and transform them
* into joins. Note that this step only handles IN clauses originally
* at top level of WHERE; if we pull up any subqueries in the next
* step, their INs are processed just before pulling them up.
*/
- parse->in_info_list = NIL;
+ root->in_info_list = NIL;
if (parse->hasSubLinks)
- parse->jointree->quals = pull_up_IN_clauses(parse,
- parse->jointree->quals);
+ parse->jointree->quals = pull_up_IN_clauses(root,
+ parse->jointree->quals);
/*
* Check to see if any subqueries in the rangetable can be merged into
* this query.
*/
parse->jointree = (FromExpr *)
- pull_up_subqueries(parse, (Node *) parse->jointree, false);
+ pull_up_subqueries(root, (Node *) parse->jointree, false);
/*
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we
@@ -220,7 +230,7 @@ subquery_planner(Query *parse, double tuple_fraction)
* reduce_outer_joins(). This must be done after we have done
* pull_up_subqueries, of course.
*/
- parse->hasJoinRTEs = false;
+ root->hasJoinRTEs = false;
hasOuterJoins = false;
foreach(l, parse->rtable)
{
@@ -228,7 +238,7 @@ subquery_planner(Query *parse, double tuple_fraction)
if (rte->rtekind == RTE_JOIN)
{
- parse->hasJoinRTEs = true;
+ root->hasJoinRTEs = true;
if (IS_OUTER_JOIN(rte->jointype))
{
hasOuterJoins = true;
@@ -243,27 +253,27 @@ subquery_planner(Query *parse, double tuple_fraction)
* because preprocess_expression will reduce a constant-true condition
* to an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
*/
- parse->hasHavingQual = (parse->havingQual != NULL);
+ root->hasHavingQual = (parse->havingQual != NULL);
/*
* Do expression preprocessing on targetlist and quals.
*/
parse->targetList = (List *)
- preprocess_expression(parse, (Node *) parse->targetList,
+ preprocess_expression(root, (Node *) parse->targetList,
EXPRKIND_TARGET);
- preprocess_qual_conditions(parse, (Node *) parse->jointree);
+ preprocess_qual_conditions(root, (Node *) parse->jointree);
- parse->havingQual = preprocess_expression(parse, parse->havingQual,
+ parse->havingQual = preprocess_expression(root, parse->havingQual,
EXPRKIND_QUAL);
- parse->limitOffset = preprocess_expression(parse, parse->limitOffset,
+ parse->limitOffset = preprocess_expression(root, parse->limitOffset,
EXPRKIND_LIMIT);
- parse->limitCount = preprocess_expression(parse, parse->limitCount,
+ parse->limitCount = preprocess_expression(root, parse->limitCount,
EXPRKIND_LIMIT);
- parse->in_info_list = (List *)
- preprocess_expression(parse, (Node *) parse->in_info_list,
+ root->in_info_list = (List *)
+ preprocess_expression(root, (Node *) root->in_info_list,
EXPRKIND_ININFO);
/* Also need to preprocess expressions for function RTEs */
@@ -272,7 +282,7 @@ subquery_planner(Query *parse, double tuple_fraction)
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
if (rte->rtekind == RTE_FUNCTION)
- rte->funcexpr = preprocess_expression(parse, rte->funcexpr,
+ rte->funcexpr = preprocess_expression(root, rte->funcexpr,
EXPRKIND_RTFUNC);
}
@@ -336,7 +346,7 @@ subquery_planner(Query *parse, double tuple_fraction)
* preprocessing.
*/
if (hasOuterJoins)
- reduce_outer_joins(parse);
+ reduce_outer_joins(root);
/*
* See if we can simplify the jointree; opportunities for this may
@@ -347,7 +357,7 @@ subquery_planner(Query *parse, double tuple_fraction)
* after reduce_outer_joins, anyway.
*/
parse->jointree = (FromExpr *)
- simplify_jointree(parse, (Node *) parse->jointree);
+ simplify_jointree(root, (Node *) parse->jointree);
/*
* Do the main planning. If we have an inherited target relation,
@@ -355,10 +365,10 @@ subquery_planner(Query *parse, double tuple_fraction)
* grouping_planner.
*/
if (parse->resultRelation &&
- (lst = expand_inherited_rtentry(parse, parse->resultRelation)) != NIL)
- plan = inheritance_planner(parse, lst);
+ (lst = expand_inherited_rtentry(root, parse->resultRelation)) != NIL)
+ plan = inheritance_planner(root, lst);
else
- plan = grouping_planner(parse, tuple_fraction);
+ plan = grouping_planner(root, tuple_fraction);
/*
* If any subplans were generated, or if we're inside a subplan, build
@@ -368,6 +378,10 @@ subquery_planner(Query *parse, double tuple_fraction)
if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
SS_finalize_plan(plan, parse->rtable);
+ /* Return sort ordering info if caller wants it */
+ if (subquery_pathkeys)
+ *subquery_pathkeys = root->query_pathkeys;
+
/* Return to outer subquery context */
PlannerQueryLevel--;
PlannerInitPlan = saved_initplan;
@@ -383,7 +397,7 @@ subquery_planner(Query *parse, double tuple_fraction)
* conditions), or a HAVING clause.
*/
static Node *
-preprocess_expression(Query *parse, Node *expr, int kind)
+preprocess_expression(PlannerInfo *root, Node *expr, int kind)
{
/*
* Fall out quickly if expression is empty. This occurs often enough
@@ -399,8 +413,8 @@ preprocess_expression(Query *parse, Node *expr, int kind)
* else sublinks expanded out from join aliases wouldn't get
* processed.
*/
- if (parse->hasJoinRTEs)
- expr = flatten_join_alias_vars(parse, expr);
+ if (root->hasJoinRTEs)
+ expr = flatten_join_alias_vars(root, expr);
/*
* Simplify constant expressions.
@@ -418,7 +432,7 @@ preprocess_expression(Query *parse, Node *expr, int kind)
* still must do it for quals (to get AND/OR flatness); and if we are
* in a subquery we should not assume it will be done only once.
*/
- if (parse->jointree->fromlist != NIL ||
+ if (root->parse->jointree->fromlist != NIL ||
kind == EXPRKIND_QUAL ||
PlannerQueryLevel > 1)
expr = eval_const_expressions(expr);
@@ -437,7 +451,7 @@ preprocess_expression(Query *parse, Node *expr, int kind)
}
/* Expand SubLinks to SubPlans */
- if (parse->hasSubLinks)
+ if (root->parse->hasSubLinks)
expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
/*
@@ -467,7 +481,7 @@ preprocess_expression(Query *parse, Node *expr, int kind)
* preprocessing work on each qual condition found therein.
*/
static void
-preprocess_qual_conditions(Query *parse, Node *jtnode)
+preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
{
if (jtnode == NULL)
return;
@@ -481,18 +495,18 @@ preprocess_qual_conditions(Query *parse, Node *jtnode)
ListCell *l;
foreach(l, f->fromlist)
- preprocess_qual_conditions(parse, lfirst(l));
+ preprocess_qual_conditions(root, lfirst(l));
- f->quals = preprocess_expression(parse, f->quals, EXPRKIND_QUAL);
+ f->quals = preprocess_expression(root, f->quals, EXPRKIND_QUAL);
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
- preprocess_qual_conditions(parse, j->larg);
- preprocess_qual_conditions(parse, j->rarg);
+ preprocess_qual_conditions(root, j->larg);
+ preprocess_qual_conditions(root, j->rarg);
- j->quals = preprocess_expression(parse, j->quals, EXPRKIND_QUAL);
+ j->quals = preprocess_expression(root, j->quals, EXPRKIND_QUAL);
}
else
elog(ERROR, "unrecognized node type: %d",
@@ -514,15 +528,15 @@ preprocess_qual_conditions(Query *parse, Node *jtnode)
* can never be the nullable side of an outer join, so it's OK to generate
* the plan this way.
*
- * parse is the querytree produced by the parser & rewriter.
* inheritlist is an integer list of RT indexes for the result relation set.
*
* Returns a query plan.
*--------------------
*/
static Plan *
-inheritance_planner(Query *parse, List *inheritlist)
+inheritance_planner(PlannerInfo *root, List *inheritlist)
{
+ Query *parse = root->parse;
int parentRTindex = parse->resultRelation;
Oid parentOID = getrelid(parentRTindex, parse->rtable);
int mainrtlength = list_length(parse->rtable);
@@ -534,15 +548,27 @@ inheritance_planner(Query *parse, List *inheritlist)
{
int childRTindex = lfirst_int(l);
Oid childOID = getrelid(childRTindex, parse->rtable);
- Query *subquery;
+ PlannerInfo subroot;
Plan *subplan;
- /* Generate modified query with this rel as target */
- subquery = (Query *) adjust_inherited_attrs((Node *) parse,
- parentRTindex, parentOID,
- childRTindex, childOID);
+ /*
+ * Generate modified query with this rel as target. We have to
+ * be prepared to translate varnos in in_info_list as well as in
+ * the Query proper.
+ */
+ memcpy(&subroot, root, sizeof(PlannerInfo));
+ subroot.parse = (Query *)
+ adjust_inherited_attrs((Node *) parse,
+ parentRTindex, parentOID,
+ childRTindex, childOID);
+ subroot.in_info_list = (List *)
+ adjust_inherited_attrs((Node *) root->in_info_list,
+ parentRTindex, parentOID,
+ childRTindex, childOID);
+
/* Generate plan */
- subplan = grouping_planner(subquery, 0.0 /* retrieve all tuples */ );
+ subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );
+
subplans = lappend(subplans, subplan);
/*
@@ -565,16 +591,16 @@ inheritance_planner(Query *parse, List *inheritlist)
* rangetables will be the same each time. Did I say this is ugly?)
*/
if (lnext(l) == NULL)
- parse->rtable = subquery->rtable;
+ parse->rtable = subroot.parse->rtable;
else
{
- int subrtlength = list_length(subquery->rtable);
+ int subrtlength = list_length(subroot.parse->rtable);
if (subrtlength > mainrtlength)
{
List *subrt;
- subrt = list_copy_tail(subquery->rtable, mainrtlength);
+ subrt = list_copy_tail(subroot.parse->rtable, mainrtlength);
parse->rtable = list_concat(parse->rtable, subrt);
mainrtlength = subrtlength;
}
@@ -589,7 +615,7 @@ inheritance_planner(Query *parse, List *inheritlist)
parse->resultRelations = inheritlist;
/* Mark result as unordered (probably unnecessary) */
- parse->query_pathkeys = NIL;
+ root->query_pathkeys = NIL;
return (Plan *) make_append(subplans, true, tlist);
}
@@ -600,7 +626,6 @@ inheritance_planner(Query *parse, List *inheritlist)
* This primarily means adding top-level processing to the basic
* query plan produced by query_planner.
*
- * parse is the querytree produced by the parser & rewriter.
* tuple_fraction is the fraction of tuples we expect will be retrieved
*
* tuple_fraction is interpreted as follows:
@@ -610,13 +635,14 @@ inheritance_planner(Query *parse, List *inheritlist)
* tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
* expected to be retrieved (ie, a LIMIT specification)
*
- * Returns a query plan. Also, parse->query_pathkeys is returned as the
+ * Returns a query plan. Also, root->query_pathkeys is returned as the
* actual output ordering of the plan (in pathkey format).
*--------------------
*/
static Plan *
-grouping_planner(Query *parse, double tuple_fraction)
+grouping_planner(PlannerInfo *root, double tuple_fraction)
{
+ Query *parse = root->parse;
List *tlist = parse->targetList;
Plan *result_plan;
List *current_pathkeys;
@@ -630,7 +656,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* Construct the plan for set operations. The result will not
* need any work except perhaps a top-level sort and/or LIMIT.
*/
- result_plan = plan_set_operations(parse,
+ result_plan = plan_set_operations(root,
&set_sortclauses);
/*
@@ -640,7 +666,7 @@ grouping_planner(Query *parse, double tuple_fraction)
*/
current_pathkeys = make_pathkeys_for_sortclauses(set_sortclauses,
result_plan->targetlist);
- current_pathkeys = canonicalize_pathkeys(parse, current_pathkeys);
+ current_pathkeys = canonicalize_pathkeys(root, current_pathkeys);
/*
* We should not need to call preprocess_targetlist, since we must
@@ -667,7 +693,7 @@ grouping_planner(Query *parse, double tuple_fraction)
*/
sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause,
tlist);
- sort_pathkeys = canonicalize_pathkeys(parse, sort_pathkeys);
+ sort_pathkeys = canonicalize_pathkeys(root, sort_pathkeys);
}
else
{
@@ -690,13 +716,13 @@ grouping_planner(Query *parse, double tuple_fraction)
MemSet(&agg_counts, 0, sizeof(AggClauseCounts));
/* Preprocess targetlist */
- tlist = preprocess_targetlist(parse, tlist);
+ tlist = preprocess_targetlist(root, tlist);
/*
* Generate appropriate target list for subplan; may be different
* from tlist if grouping or aggregation is needed.
*/
- sub_tlist = make_subplanTargetList(parse, tlist,
+ sub_tlist = make_subplanTargetList(root, tlist,
&groupColIdx, &need_tlist_eval);
/*
@@ -737,11 +763,11 @@ grouping_planner(Query *parse, double tuple_fraction)
* Needs more thought...)
*/
if (parse->groupClause)
- parse->query_pathkeys = group_pathkeys;
+ root->query_pathkeys = group_pathkeys;
else if (parse->sortClause)
- parse->query_pathkeys = sort_pathkeys;
+ root->query_pathkeys = sort_pathkeys;
else
- parse->query_pathkeys = NIL;
+ root->query_pathkeys = NIL;
/*
* Adjust tuple_fraction if we see that we are going to apply
@@ -902,15 +928,15 @@ grouping_planner(Query *parse, double tuple_fraction)
* Generate the best unsorted and presorted paths for this Query
* (but note there may not be any presorted path).
*/
- query_planner(parse, sub_tlist, sub_tuple_fraction,
+ query_planner(root, sub_tlist, sub_tuple_fraction,
&cheapest_path, &sorted_path);
/*
* We couldn't canonicalize group_pathkeys and sort_pathkeys
* before running query_planner(), so do it now.
*/
- group_pathkeys = canonicalize_pathkeys(parse, group_pathkeys);
- sort_pathkeys = canonicalize_pathkeys(parse, sort_pathkeys);
+ group_pathkeys = canonicalize_pathkeys(root, group_pathkeys);
+ sort_pathkeys = canonicalize_pathkeys(root, sort_pathkeys);
/*
* If grouping, estimate the number of groups. (We can't do this
@@ -934,14 +960,14 @@ grouping_planner(Query *parse, double tuple_fraction)
groupExprs = get_sortgrouplist_exprs(parse->groupClause,
parse->targetList);
- dNumGroups = estimate_num_groups(parse,
+ dNumGroups = estimate_num_groups(root,
groupExprs,
cheapest_path_rows);
/* Also want it as a long int --- but 'ware overflow! */
numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
use_hashed_grouping =
- choose_hashed_grouping(parse, tuple_fraction,
+ choose_hashed_grouping(root, tuple_fraction,
cheapest_path, sorted_path,
sort_pathkeys, group_pathkeys,
dNumGroups, &agg_counts);
@@ -963,7 +989,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* "regular" path ... but we had to do it anyway to be able to
* tell which way is cheaper.
*/
- result_plan = optimize_minmax_aggregates(parse,
+ result_plan = optimize_minmax_aggregates(root,
tlist,
best_path);
if (result_plan != NULL)
@@ -980,7 +1006,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* Normal case --- create a plan according to query_planner's
* results.
*/
- result_plan = create_plan(parse, best_path);
+ result_plan = create_plan(root, best_path);
current_pathkeys = best_path->pathkeys;
/*
@@ -1042,7 +1068,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* make_subplanTargetList calculated, we have to refigure any
* grouping-column indexes make_subplanTargetList computed.
*/
- locate_grouping_columns(parse, tlist, result_plan->targetlist,
+ locate_grouping_columns(root, tlist, result_plan->targetlist,
groupColIdx);
}
@@ -1055,7 +1081,7 @@ grouping_planner(Query *parse, double tuple_fraction)
if (use_hashed_grouping)
{
/* Hashed aggregate plan --- no sort needed */
- result_plan = (Plan *) make_agg(parse,
+ result_plan = (Plan *) make_agg(root,
tlist,
(List *) parse->havingQual,
AGG_HASHED,
@@ -1078,7 +1104,7 @@ grouping_planner(Query *parse, double tuple_fraction)
current_pathkeys))
{
result_plan = (Plan *)
- make_sort_from_groupcols(parse,
+ make_sort_from_groupcols(root,
parse->groupClause,
groupColIdx,
result_plan);
@@ -1098,7 +1124,7 @@ grouping_planner(Query *parse, double tuple_fraction)
current_pathkeys = NIL;
}
- result_plan = (Plan *) make_agg(parse,
+ result_plan = (Plan *) make_agg(root,
tlist,
(List *) parse->havingQual,
aggstrategy,
@@ -1120,14 +1146,14 @@ grouping_planner(Query *parse, double tuple_fraction)
if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
{
result_plan = (Plan *)
- make_sort_from_groupcols(parse,
+ make_sort_from_groupcols(root,
parse->groupClause,
groupColIdx,
result_plan);
current_pathkeys = group_pathkeys;
}
- result_plan = (Plan *) make_group(parse,
+ result_plan = (Plan *) make_group(root,
tlist,
(List *) parse->havingQual,
numGroupCols,
@@ -1136,7 +1162,7 @@ grouping_planner(Query *parse, double tuple_fraction)
result_plan);
/* The Group node won't change sort ordering */
}
- else if (parse->hasHavingQual)
+ else if (root->hasHavingQual)
{
/*
* No aggregates, and no GROUP BY, but we have a HAVING qual.
@@ -1165,7 +1191,7 @@ grouping_planner(Query *parse, double tuple_fraction)
if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
{
result_plan = (Plan *)
- make_sort_from_sortclauses(parse,
+ make_sort_from_sortclauses(root,
parse->sortClause,
result_plan);
current_pathkeys = sort_pathkeys;
@@ -1185,13 +1211,13 @@ grouping_planner(Query *parse, double tuple_fraction)
* it's reasonable to assume the UNIQUE filter has effects
* comparable to GROUP BY.
*/
- if (!parse->groupClause && !parse->hasHavingQual && !parse->hasAggs)
+ if (!parse->groupClause && !root->hasHavingQual && !parse->hasAggs)
{
List *distinctExprs;
distinctExprs = get_sortgrouplist_exprs(parse->distinctClause,
parse->targetList);
- result_plan->plan_rows = estimate_num_groups(parse,
+ result_plan->plan_rows = estimate_num_groups(root,
distinctExprs,
result_plan->plan_rows);
}
@@ -1211,7 +1237,7 @@ grouping_planner(Query *parse, double tuple_fraction)
* Return the actual output ordering in query_pathkeys for possible
* use by an outer query level.
*/
- parse->query_pathkeys = current_pathkeys;
+ root->query_pathkeys = current_pathkeys;
return result_plan;
}
@@ -1220,12 +1246,12 @@ grouping_planner(Query *parse, double tuple_fraction)
* choose_hashed_grouping - should we use hashed grouping?
*/
static bool
-choose_hashed_grouping(Query *parse, double tuple_fraction,
+choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
Path *cheapest_path, Path *sorted_path,
List *sort_pathkeys, List *group_pathkeys,
double dNumGroups, AggClauseCounts *agg_counts)
{
- int numGroupCols = list_length(parse->groupClause);
+ int numGroupCols = list_length(root->parse->groupClause);
double cheapest_path_rows;
int cheapest_path_width;
Size hashentrysize;
@@ -1245,7 +1271,7 @@ choose_hashed_grouping(Query *parse, double tuple_fraction,
return false;
if (agg_counts->numDistinctAggs != 0)
return false;
- if (!hash_safe_grouping(parse))
+ if (!hash_safe_grouping(root))
return false;
/*
@@ -1296,13 +1322,13 @@ choose_hashed_grouping(Query *parse, double tuple_fraction,
* These path variables are dummies that just hold cost fields; we don't
* make actual Paths for these steps.
*/
- cost_agg(&hashed_p, parse, AGG_HASHED, agg_counts->numAggs,
+ cost_agg(&hashed_p, root, AGG_HASHED, agg_counts->numAggs,
numGroupCols, dNumGroups,
cheapest_path->startup_cost, cheapest_path->total_cost,
cheapest_path_rows);
/* Result of hashed agg is always unsorted */
if (sort_pathkeys)
- cost_sort(&hashed_p, parse, sort_pathkeys, hashed_p.total_cost,
+ cost_sort(&hashed_p, root, sort_pathkeys, hashed_p.total_cost,
dNumGroups, cheapest_path_width);
if (sorted_path)
@@ -1320,24 +1346,24 @@ choose_hashed_grouping(Query *parse, double tuple_fraction,
if (!pathkeys_contained_in(group_pathkeys,
current_pathkeys))
{
- cost_sort(&sorted_p, parse, group_pathkeys, sorted_p.total_cost,
+ cost_sort(&sorted_p, root, group_pathkeys, sorted_p.total_cost,
cheapest_path_rows, cheapest_path_width);
current_pathkeys = group_pathkeys;
}
- if (parse->hasAggs)
- cost_agg(&sorted_p, parse, AGG_SORTED, agg_counts->numAggs,
+ if (root->parse->hasAggs)
+ cost_agg(&sorted_p, root, AGG_SORTED, agg_counts->numAggs,
numGroupCols, dNumGroups,
sorted_p.startup_cost, sorted_p.total_cost,
cheapest_path_rows);
else
- cost_group(&sorted_p, parse, numGroupCols, dNumGroups,
+ cost_group(&sorted_p, root, numGroupCols, dNumGroups,
sorted_p.startup_cost, sorted_p.total_cost,
cheapest_path_rows);
/* The Agg or Group node will preserve ordering */
if (sort_pathkeys &&
!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
- cost_sort(&sorted_p, parse, sort_pathkeys, sorted_p.total_cost,
+ cost_sort(&sorted_p, root, sort_pathkeys, sorted_p.total_cost,
dNumGroups, cheapest_path_width);
/*
@@ -1363,14 +1389,15 @@ choose_hashed_grouping(Query *parse, double tuple_fraction,
* is marked hashjoinable.
*/
static bool
-hash_safe_grouping(Query *parse)
+hash_safe_grouping(PlannerInfo *root)
{
ListCell *gl;
- foreach(gl, parse->groupClause)
+ foreach(gl, root->parse->groupClause)
{
GroupClause *grpcl = (GroupClause *) lfirst(gl);
- TargetEntry *tle = get_sortgroupclause_tle(grpcl, parse->targetList);
+ TargetEntry *tle = get_sortgroupclause_tle(grpcl,
+ root->parse->targetList);
Operator optup;
bool oprcanhash;
@@ -1417,7 +1444,6 @@ hash_safe_grouping(Query *parse)
* 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.
@@ -1428,11 +1454,12 @@ hash_safe_grouping(Query *parse)
*---------------
*/
static List *
-make_subplanTargetList(Query *parse,
+make_subplanTargetList(PlannerInfo *root,
List *tlist,
AttrNumber **groupColIdx,
bool *need_tlist_eval)
{
+ Query *parse = root->parse;
List *sub_tlist;
List *extravars;
int numCols;
@@ -1443,7 +1470,7 @@ make_subplanTargetList(Query *parse,
* If we're not grouping or aggregating, there's nothing to do here;
* query_planner should receive the unmodified target list.
*/
- if (!parse->hasAggs && !parse->groupClause && !parse->hasHavingQual)
+ if (!parse->hasAggs && !parse->groupClause && !root->hasHavingQual)
{
*need_tlist_eval = true;
return tlist;
@@ -1517,7 +1544,7 @@ make_subplanTargetList(Query *parse,
* by that routine and re-locate the grouping vars in the real sub_tlist.
*/
static void
-locate_grouping_columns(Query *parse,
+locate_grouping_columns(PlannerInfo *root,
List *tlist,
List *sub_tlist,
AttrNumber *groupColIdx)
@@ -1528,14 +1555,14 @@ locate_grouping_columns(Query *parse,
/*
* No work unless grouping.
*/
- if (!parse->groupClause)
+ if (!root->parse->groupClause)
{
Assert(groupColIdx == NULL);
return;
}
Assert(groupColIdx != NULL);
- foreach(gl, parse->groupClause)
+ foreach(gl, root->parse->groupClause)
{
GroupClause *grpcl = (GroupClause *) lfirst(gl);
Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 0865feae26..ec037db514 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.98 2005/04/25 01:30:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.99 2005/06/05 22:32:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -292,7 +292,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
/*
* Generate the plan for the subquery.
*/
- node->plan = plan = subquery_planner(subquery, tuple_fraction);
+ node->plan = plan = subquery_planner(subquery, tuple_fraction, NULL);
node->plan_id = PlannerPlanId++; /* Assign unique ID to this
* SubPlan */
@@ -417,10 +417,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
* top of the subplan, to reduce the cost of reading it
* repeatedly. This is pointless for a direct-correlated subplan,
* since we'd have to recompute its results each time anyway. For
- * uncorrelated/undirect correlated subplans, we add MATERIAL if
- * the subplan's top plan node is anything more complicated than a
- * plain sequential scan, and we do it even for seqscan if the
- * qual appears selective enough to eliminate many tuples.
+ * uncorrelated/undirect correlated subplans, we add MATERIAL unless
+ * the subplan's top plan node would materialize its output anyway.
*/
else if (node->parParam == NIL)
{
@@ -428,29 +426,9 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
switch (nodeTag(plan))
{
- case T_SeqScan:
- if (plan->initPlan)
- use_material = true;
- else
- {
- Selectivity qualsel;
-
- qualsel = clauselist_selectivity(subquery,
- plan->qual,
- 0, JOIN_INNER);
- /* Is 10% selectivity a good threshold?? */
- use_material = qualsel < 0.10;
- }
- break;
case T_Material:
case T_FunctionScan:
case T_Sort:
-
- /*
- * Don't add another Material node if there's one
- * already, nor if the top node is any other type that
- * materializes its output anyway.
- */
use_material = false;
break;
default:
@@ -678,8 +656,9 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
* its in_info_list.
*/
Node *
-convert_IN_to_join(Query *parse, SubLink *sublink)
+convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
{
+ Query *parse = root->parse;
Query *subselect = (Query *) sublink->subselect;
Relids left_varnos;
int rtindex;
@@ -746,7 +725,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
ininfo = makeNode(InClauseInfo);
ininfo->lefthand = left_varnos;
ininfo->righthand = bms_make_singleton(rtindex);
- parse->in_info_list = lcons(ininfo, parse->in_info_list);
+ root->in_info_list = lappend(root->in_info_list, ininfo);
/*
* Build the result qual expressions. As a side effect,
@@ -1252,7 +1231,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
* We assume the plan hasn't been put through SS_finalize_plan.
*/
Param *
-SS_make_initplan_from_plan(Query *root, Plan *plan,
+SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
Oid resulttype, int32 resulttypmod)
{
List *saved_initplan = PlannerInitPlan;
@@ -1271,7 +1250,7 @@ SS_make_initplan_from_plan(Query *root, Plan *plan,
/*
* Build extParam/allParam sets for plan nodes.
*/
- SS_finalize_plan(plan, root->rtable);
+ SS_finalize_plan(plan, root->parse->rtable);
/* Return to outer subquery context */
PlannerQueryLevel--;
@@ -1286,7 +1265,7 @@ SS_make_initplan_from_plan(Query *root, Plan *plan,
node->plan_id = PlannerPlanId++; /* Assign unique ID to this
* SubPlan */
- node->rtable = root->rtable;
+ node->rtable = root->parse->rtable;
PlannerInitPlan = lappend(PlannerInitPlan, node);