diff options
Diffstat (limited to 'src/backend/optimizer/plan')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 107 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 28 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planagg.c | 85 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planmain.c | 30 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 241 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 41 |
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); |
