diff options
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 214 | ||||
-rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 71 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planagg.c | 47 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 35 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 5 |
5 files changed, 223 insertions, 149 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 1cad6574f37..7a9bb08b89c 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.211 2006/05/18 18:57:31 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.212 2006/07/01 18:38:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,11 +35,12 @@ #include "utils/syscache.h" -static Scan *create_scan_plan(PlannerInfo *root, Path *best_path); +static Plan *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(PlannerInfo *root, JoinPath *best_path); +static Plan *create_gating_plan(PlannerInfo *root, Plan *plan, List *quals); +static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); static Plan *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); @@ -74,6 +75,7 @@ static void fix_indexqual_references(List *indexquals, IndexPath *index_path, static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass); static List *get_switched_clauses(List *clauses, Relids outerrelids); +static List *order_qual_clauses(PlannerInfo *root, List *clauses); static void copy_path_costsize(Plan *dest, Path *src); static void copy_plan_costsize(Plan *dest, Plan *src); static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); @@ -146,17 +148,17 @@ create_plan(PlannerInfo *root, Path *best_path) case T_TidScan: case T_SubqueryScan: case T_FunctionScan: - plan = (Plan *) create_scan_plan(root, best_path); + plan = create_scan_plan(root, best_path); break; case T_HashJoin: case T_MergeJoin: case T_NestLoop: - plan = (Plan *) create_join_plan(root, - (JoinPath *) best_path); + plan = create_join_plan(root, + (JoinPath *) best_path); break; case T_Append: - plan = (Plan *) create_append_plan(root, - (AppendPath *) best_path); + plan = create_append_plan(root, + (AppendPath *) best_path); break; case T_Result: plan = (Plan *) create_result_plan(root, @@ -167,8 +169,8 @@ create_plan(PlannerInfo *root, Path *best_path) (MaterialPath *) best_path); break; case T_Unique: - plan = (Plan *) create_unique_plan(root, - (UniquePath *) best_path); + plan = create_unique_plan(root, + (UniquePath *) best_path); break; default: elog(ERROR, "unrecognized node type: %d", @@ -183,16 +185,14 @@ create_plan(PlannerInfo *root, Path *best_path) /* * create_scan_plan * Create a scan plan for the parent relation of 'best_path'. - * - * Returns a Plan node. */ -static Scan * +static Plan * create_scan_plan(PlannerInfo *root, Path *best_path) { RelOptInfo *rel = best_path->parent; List *tlist; List *scan_clauses; - Scan *plan; + Plan *plan; /* * For table scans, rather than using the relation targetlist (which is @@ -213,22 +213,23 @@ create_scan_plan(PlannerInfo *root, Path *best_path) tlist = build_relation_tlist(rel); /* - * Extract the relevant restriction clauses from the parent relation; the - * executor must apply all these restrictions during the scan. + * Extract the relevant restriction clauses from the parent relation. + * The executor must apply all these restrictions during the scan, + * except for pseudoconstants which we'll take care of below. */ scan_clauses = rel->baserestrictinfo; switch (best_path->pathtype) { case T_SeqScan: - plan = (Scan *) create_seqscan_plan(root, + plan = (Plan *) create_seqscan_plan(root, best_path, tlist, scan_clauses); break; case T_IndexScan: - plan = (Scan *) create_indexscan_plan(root, + plan = (Plan *) create_indexscan_plan(root, (IndexPath *) best_path, tlist, scan_clauses, @@ -236,28 +237,28 @@ create_scan_plan(PlannerInfo *root, Path *best_path) break; case T_BitmapHeapScan: - plan = (Scan *) create_bitmap_scan_plan(root, + plan = (Plan *) create_bitmap_scan_plan(root, (BitmapHeapPath *) best_path, tlist, scan_clauses); break; case T_TidScan: - plan = (Scan *) create_tidscan_plan(root, + plan = (Plan *) create_tidscan_plan(root, (TidPath *) best_path, tlist, scan_clauses); break; case T_SubqueryScan: - plan = (Scan *) create_subqueryscan_plan(root, + plan = (Plan *) create_subqueryscan_plan(root, best_path, tlist, scan_clauses); break; case T_FunctionScan: - plan = (Scan *) create_functionscan_plan(root, + plan = (Plan *) create_functionscan_plan(root, best_path, tlist, scan_clauses); @@ -270,6 +271,14 @@ create_scan_plan(PlannerInfo *root, Path *best_path) break; } + /* + * If there are any pseudoconstant clauses attached to this node, + * insert a gating Result node that evaluates the pseudoconstants + * as one-time quals. + */ + if (root->hasPseudoConstantQuals) + plan = create_gating_plan(root, plan, scan_clauses); + return plan; } @@ -366,18 +375,53 @@ disuse_physical_tlist(Plan *plan, Path *path) } /* + * create_gating_plan + * Deal with pseudoconstant qual clauses + * + * If the node's quals list includes any pseudoconstant quals, put them + * into a gating Result node atop the already-built plan. Otherwise, + * return the plan as-is. + * + * Note that we don't change cost or size estimates when doing gating. + * The costs of qual eval were already folded into the plan's startup cost. + * Leaving the size alone amounts to assuming that the gating qual will + * succeed, which is the conservative estimate for planning upper queries. + * We certainly don't want to assume the output size is zero (unless the + * gating qual is actually constant FALSE, and that case is dealt with in + * clausesel.c). Interpolating between the two cases is silly, because + * it doesn't reflect what will really happen at runtime, and besides which + * in most cases we have only a very bad idea of the probability of the gating + * qual being true. + */ +static Plan * +create_gating_plan(PlannerInfo *root, Plan *plan, List *quals) +{ + List *pseudoconstants; + + /* Pull out any pseudoconstant quals from the RestrictInfo list */ + pseudoconstants = extract_actual_clauses(quals, true); + + if (!pseudoconstants) + return plan; + + pseudoconstants = order_qual_clauses(root, pseudoconstants); + + return (Plan *) make_result((List *) copyObject(plan->targetlist), + (Node *) pseudoconstants, + plan); +} + +/* * create_join_plan * Create a join plan for 'best_path' and (recursively) plans for its * inner and outer paths. - * - * Returns a Plan node. */ -static Join * +static Plan * create_join_plan(PlannerInfo *root, JoinPath *best_path) { Plan *outer_plan; Plan *inner_plan; - Join *plan; + Plan *plan; outer_plan = create_plan(root, best_path->outerjoinpath); inner_plan = create_plan(root, best_path->innerjoinpath); @@ -385,19 +429,19 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) switch (best_path->path.pathtype) { case T_MergeJoin: - plan = (Join *) create_mergejoin_plan(root, + plan = (Plan *) create_mergejoin_plan(root, (MergePath *) best_path, outer_plan, inner_plan); break; case T_HashJoin: - plan = (Join *) create_hashjoin_plan(root, + plan = (Plan *) create_hashjoin_plan(root, (HashPath *) best_path, outer_plan, inner_plan); break; case T_NestLoop: - plan = (Join *) create_nestloop_plan(root, + plan = (Plan *) create_nestloop_plan(root, (NestPath *) best_path, outer_plan, inner_plan); @@ -409,6 +453,14 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) break; } + /* + * If there are any pseudoconstant clauses attached to this node, + * insert a gating Result node that evaluates the pseudoconstants + * as one-time quals. + */ + if (root->hasPseudoConstantQuals) + plan = create_gating_plan(root, plan, best_path->joinrestrictinfo); + #ifdef NOT_USED /* @@ -473,34 +525,24 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) /* * create_result_plan - * Create a Result plan for 'best_path' and (recursively) plans - * for its subpaths. + * Create a Result plan for 'best_path'. + * This is only used for the case of a query with an empty jointree. * * Returns a Plan node. */ static Result * create_result_plan(PlannerInfo *root, ResultPath *best_path) { - Result *plan; List *tlist; - List *constclauses; - Plan *subplan; + List *quals; - if (best_path->path.parent) - tlist = build_relation_tlist(best_path->path.parent); - else - tlist = NIL; /* will be filled in later */ - - if (best_path->subpath) - subplan = create_plan(root, best_path->subpath); - else - subplan = NULL; + /* The tlist will be installed later, since we have no RelOptInfo */ + Assert(best_path->path.parent == NULL); + tlist = NIL; - constclauses = order_qual_clauses(root, best_path->constantqual); + quals = order_qual_clauses(root, best_path->quals); - plan = make_result(tlist, (Node *) constclauses, subplan); - - return plan; + return make_result(tlist, (Node *) quals, NULL); } /* @@ -716,8 +758,8 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path, Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_RELATION); - /* Reduce RestrictInfo list to bare expressions */ - scan_clauses = get_actual_clauses(scan_clauses); + /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ + scan_clauses = extract_actual_clauses(scan_clauses, false); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); @@ -824,7 +866,8 @@ create_indexscan_plan(PlannerInfo *root, * plan so that they'll be properly rechecked by EvalPlanQual testing. * * While at it, we strip off the RestrictInfos to produce a list of plain - * expressions. + * expressions (this loop replaces extract_actual_clauses used in the + * other routines in this file). We have to ignore pseudoconstants. */ qpqual = NIL; foreach(l, scan_clauses) @@ -832,6 +875,8 @@ create_indexscan_plan(PlannerInfo *root, RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); Assert(IsA(rinfo, RestrictInfo)); + if (rinfo->pseudoconstant) + continue; if (list_member_ptr(nonlossy_indexquals, rinfo)) continue; if (!contain_mutable_functions((Node *) rinfo->clause)) @@ -900,8 +945,8 @@ create_bitmap_scan_plan(PlannerInfo *root, bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual, &bitmapqualorig, &indexquals); - /* Reduce RestrictInfo list to bare expressions */ - scan_clauses = get_actual_clauses(scan_clauses); + /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ + scan_clauses = extract_actual_clauses(scan_clauses, false); /* * If this is a innerjoin scan, the indexclauses will contain join clauses @@ -1183,8 +1228,8 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path, Assert(scan_relid > 0); Assert(best_path->path.parent->rtekind == RTE_RELATION); - /* Reduce RestrictInfo list to bare expressions */ - scan_clauses = get_actual_clauses(scan_clauses); + /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ + scan_clauses = extract_actual_clauses(scan_clauses, false); /* * Remove any clauses that are TID quals. This is a bit tricky since @@ -1224,8 +1269,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path, Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_SUBQUERY); - /* Reduce RestrictInfo list to bare expressions */ - scan_clauses = get_actual_clauses(scan_clauses); + /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ + scan_clauses = extract_actual_clauses(scan_clauses, false); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); @@ -1256,8 +1301,8 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path, Assert(scan_relid > 0); Assert(best_path->parent->rtekind == RTE_FUNCTION); - /* Reduce RestrictInfo list to bare expressions */ - scan_clauses = get_actual_clauses(scan_clauses); + /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ + scan_clauses = extract_actual_clauses(scan_clauses, false); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); @@ -1348,15 +1393,16 @@ create_nestloop_plan(PlannerInfo *root, } /* Get the join qual clauses (in plain expression form) */ + /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jointype)) { - get_actual_join_clauses(joinrestrictclauses, - &joinclauses, &otherclauses); + extract_actual_join_clauses(joinrestrictclauses, + &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ - joinclauses = get_actual_clauses(joinrestrictclauses); + joinclauses = extract_actual_clauses(joinrestrictclauses, false); otherclauses = NIL; } @@ -1389,15 +1435,17 @@ create_mergejoin_plan(PlannerInfo *root, MergeJoin *join_plan; /* Get the join qual clauses (in plain expression form) */ + /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jpath.jointype)) { - get_actual_join_clauses(best_path->jpath.joinrestrictinfo, - &joinclauses, &otherclauses); + extract_actual_join_clauses(best_path->jpath.joinrestrictinfo, + &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ - joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo); + joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo, + false); otherclauses = NIL; } @@ -1473,15 +1521,17 @@ create_hashjoin_plan(PlannerInfo *root, Hash *hash_plan; /* Get the join qual clauses (in plain expression form) */ + /* Any pseudoconstant clauses are ignored here */ if (IS_OUTER_JOIN(best_path->jpath.jointype)) { - get_actual_join_clauses(best_path->jpath.joinrestrictinfo, - &joinclauses, &otherclauses); + extract_actual_join_clauses(best_path->jpath.joinrestrictinfo, + &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ - joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo); + joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo, + false); otherclauses = NIL; } @@ -1831,7 +1881,7 @@ get_switched_clauses(List *clauses, Relids outerrelids) * For now, we just move any quals that contain SubPlan references (but not * InitPlan references) to the end of the list. */ -List * +static List * order_qual_clauses(PlannerInfo *root, List *clauses) { List *nosubplans; @@ -2880,6 +2930,15 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount, return node; } +/* + * make_result + * Build a Result plan node + * + * If we have a subplan, assume that any evaluation costs for the gating qual + * were already factored into the subplan's startup cost, and just copy the + * subplan cost. If there's no subplan, we should include the qual eval + * cost. In either case, tlist eval cost is not to be included here. + */ Result * make_result(List *tlist, Node *resconstantqual, @@ -2895,17 +2954,16 @@ make_result(List *tlist, plan->startup_cost = 0; plan->total_cost = cpu_tuple_cost; plan->plan_rows = 1; /* wrong if we have a set-valued function? */ - plan->plan_width = 0; /* XXX try to be smarter? */ - } - - if (resconstantqual) - { - QualCost qual_cost; + plan->plan_width = 0; /* XXX is it worth being smarter? */ + if (resconstantqual) + { + QualCost qual_cost; - cost_qual_eval(&qual_cost, (List *) resconstantqual); - /* resconstantqual is evaluated once at startup */ - plan->startup_cost += qual_cost.startup + qual_cost.per_tuple; - plan->total_cost += qual_cost.startup + qual_cost.per_tuple; + cost_qual_eval(&qual_cost, (List *) resconstantqual); + /* resconstantqual is evaluated once at startup */ + plan->startup_cost += qual_cost.startup + qual_cost.per_tuple; + plan->total_cost += qual_cost.startup + qual_cost.per_tuple; + } } plan->targetlist = tlist; diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 1c04a8784d2..bf8e67d0dcd 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.117 2006/03/14 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.118 2006/07/01 18:38:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" +#include "optimizer/prep.h" #include "optimizer/restrictinfo.h" #include "optimizer/tlist.h" #include "optimizer/var.h" @@ -72,6 +73,9 @@ static void check_hashjoinable(RestrictInfo *restrictinfo); * the base relations (ie, table, subquery, and function RTEs) * appearing in the jointree. * + * The initial invocation must pass root->parse->jointree as the value of + * jtnode. Internally, the function recurses through the jointree. + * * At the end of this process, there should be one baserel RelOptInfo for * every non-join RTE that is used in the query. Therefore, this routine * is the only place that should call build_simple_rel with reloptkind @@ -578,6 +582,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, { Relids relids; bool outerjoin_delayed; + bool pseudoconstant = false; bool maybe_equijoin; bool maybe_outer_join; RestrictInfo *restrictinfo; @@ -599,16 +604,57 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, elog(ERROR, "JOIN qualification may not refer to other relations"); /* - * If the clause is variable-free, we force it to be evaluated at its - * original syntactic level. Note that this should not happen for - * top-level clauses, because query_planner() special-cases them. But it - * will happen for variable-free JOIN/ON clauses. We don't have to be - * real smart about such a case, we just have to be correct. Also note - * that for an outer-join clause, we must force it to the OJ's semantic - * level, not the syntactic scope. + * If the clause is variable-free, our normal heuristic for pushing it + * down to just the mentioned rels doesn't work, because there are none. + * + * If the clause is an outer-join clause, we must force it to the OJ's + * semantic level to preserve semantics. + * + * Otherwise, when the clause contains volatile functions, we force it + * to be evaluated at its original syntactic level. This preserves the + * expected semantics. + * + * When the clause contains no volatile functions either, it is actually + * a pseudoconstant clause that will not change value during any one + * execution of the plan, and hence can be used as a one-time qual in + * a gating Result plan node. We put such a clause into the regular + * RestrictInfo lists for the moment, but eventually createplan.c will + * pull it out and make a gating Result node immediately above whatever + * plan node the pseudoconstant clause is assigned to. It's usually + * best to put a gating node as high in the plan tree as possible. + * If we are not below an outer join, we can actually push the + * pseudoconstant qual all the way to the top of the tree. If we are + * below an outer join, we leave the qual at its original syntactic level + * (we could push it up to just below the outer join, but that seems more + * complex than it's worth). */ if (bms_is_empty(relids)) - relids = ojscope ? ojscope : qualscope; + { + if (ojscope) + { + /* clause is attached to outer join, eval it there */ + relids = ojscope; + /* mustn't use as gating qual, so don't mark pseudoconstant */ + } + else + { + /* eval at original syntactic level */ + relids = qualscope; + if (!contain_volatile_functions(clause)) + { + /* mark as gating qual */ + pseudoconstant = true; + /* tell createplan.c to check for gating quals */ + root->hasPseudoConstantQuals = true; + /* if not below outer join, push it to top of tree */ + if (!below_outer_join) + { + relids = get_relids_in_jointree((Node *) root->parse->jointree); + is_pushed_down = true; + } + } + } + } /* * Check to see if clause application must be delayed by outer-join @@ -624,6 +670,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, */ Assert(bms_equal(relids, qualscope)); Assert(!ojscope); + Assert(!pseudoconstant); /* Needn't feed it back for more deductions */ outerjoin_delayed = false; maybe_equijoin = false; @@ -647,6 +694,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, Assert(ojscope); relids = ojscope; outerjoin_delayed = true; + Assert(!pseudoconstant); /* * We can't use such a clause to deduce equijoin (the left and right @@ -738,6 +786,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, restrictinfo = make_restrictinfo((Expr *) clause, is_pushed_down, outerjoin_delayed, + pseudoconstant, relids); /* @@ -1179,6 +1228,8 @@ check_mergejoinable(RestrictInfo *restrictinfo) leftOp, rightOp; + if (restrictinfo->pseudoconstant) + return; if (!is_opclause(clause)) return; if (list_length(((OpExpr *) clause)->args) != 2) @@ -1212,6 +1263,8 @@ check_hashjoinable(RestrictInfo *restrictinfo) Expr *clause = restrictinfo->clause; Oid opno; + if (restrictinfo->pseudoconstant) + return; if (!is_opclause(clause)) return; if (list_length(((OpExpr *) clause)->args) != 2) diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index c567f8b6b74..7a61b3fb17f 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.15 2006/06/06 17:59:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.16 2006/07/01 18:38:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -46,8 +46,7 @@ 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(PlannerInfo *root, MinMaxAggInfo *info, - List *constant_quals); +static void make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info); static Node *replace_aggs_with_params_mutator(Node *node, List **context); static Oid fetch_agg_sort_op(Oid aggfnoid); @@ -81,7 +80,6 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path) Plan *plan; Node *hqual; QualCost tlist_cost; - List *constant_quals; /* Nothing to do if query has no aggregates */ if (!parse->hasAggs) @@ -164,27 +162,13 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path) return NULL; /* too expensive */ /* - * OK, we are going to generate an optimized plan. The first thing we - * need to do is look for any non-variable WHERE clauses that - * query_planner might have removed from the basic plan. (Normal WHERE - * clauses will be properly incorporated into the sub-plans by - * create_plan.) If there are any, they will be in a gating Result node - * atop the best_path. They have to be incorporated into a gating Result - * in each sub-plan in order to produce the semantically correct result. + * OK, we are going to generate an optimized plan. */ - if (IsA(best_path, ResultPath)) - { - constant_quals = ((ResultPath *) best_path)->constantqual; - /* no need to do this more than once: */ - constant_quals = order_qual_clauses(root, constant_quals); - } - else - constant_quals = NIL; /* Pass 3: generate subplans and output Param nodes */ foreach(l, aggs_list) { - make_agg_subplan(root, (MinMaxAggInfo *) lfirst(l), constant_quals); + make_agg_subplan(root, (MinMaxAggInfo *) lfirst(l)); } /* @@ -434,11 +418,12 @@ 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(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals) +make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info) { PlannerInfo subroot; Query *subparse; Plan *plan; + Plan *iplan; TargetEntry *tle; SortClause *sortcl; NullTest *ntest; @@ -482,8 +467,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals) /* * Generate the plan for the subquery. We already have a Path for the * basic indexscan, but we have to convert it to a Plan and attach a LIMIT - * node above it. We might need a gating Result, too, to handle any - * non-variable qual clauses. + * node above it. * * Also we must add a "WHERE foo IS NOT NULL" restriction to the * indexscan, to be sure we don't return a NULL, which'd be contrary to @@ -491,21 +475,26 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals) * earlier, so that the selectivity of the restriction could be included * in our cost estimates. But that looks painful, and in most cases the * fraction of NULLs isn't high enough to change the decision. + * + * The NOT NULL qual has to go on the actual indexscan; create_plan + * might have stuck a gating Result atop that, if there were any + * pseudoconstant quals. */ plan = create_plan(&subroot, (Path *) info->path); plan->targetlist = copyObject(subparse->targetList); + if (IsA(plan, Result)) + iplan = plan->lefttree; + else + iplan = plan; + Assert(IsA(iplan, IndexScan)); + ntest = makeNode(NullTest); ntest->nulltesttype = IS_NOT_NULL; ntest->arg = copyObject(info->target); - plan->qual = lcons(ntest, plan->qual); - - if (constant_quals) - plan = (Plan *) make_result(copyObject(plan->targetlist), - copyObject(constant_quals), - plan); + iplan->qual = lcons(ntest, iplan->qual); plan = (Plan *) make_limit(plan, subparse->limitOffset, diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index bc1438a4672..2ad786ce646 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.93 2006/03/05 15:58:29 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.94 2006/07/01 18:38:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -82,7 +82,6 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, double *num_groups) { Query *parse = root->parse; - List *constant_quals; List *joinlist; RelOptInfo *final_rel; Path *cheapestpath; @@ -99,27 +98,13 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, */ if (parse->jointree->fromlist == NIL) { - *cheapest_path = (Path *) create_result_path(NULL, NULL, - (List *) parse->jointree->quals); + *cheapest_path = (Path *) + create_result_path((List *) parse->jointree->quals); *sorted_path = NULL; return; } /* - * Pull out any non-variable WHERE clauses so these can be put in a - * toplevel "Result" node, where they will gate execution of the whole - * plan (the Result will not invoke its descendant plan unless the quals - * are true). Note that any *really* non-variable quals will have been - * optimized away by eval_const_expressions(). What we're mostly - * interested in here is quals that depend only on outer-level vars, - * although if the qual reduces to "WHERE FALSE" this path will also be - * taken. - */ - parse->jointree->quals = (Node *) - pull_constant_clauses((List *) parse->jointree->quals, - &constant_quals); - - /* * Init planner lists to empty, and set up the array to hold RelOptInfos * for "simple" rels. * @@ -324,20 +309,6 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, } } - /* - * If we have constant quals, add a toplevel Result step to process them. - */ - if (constant_quals) - { - cheapestpath = (Path *) create_result_path(final_rel, - cheapestpath, - constant_quals); - if (sortedpath) - sortedpath = (Path *) create_result_path(final_rel, - sortedpath, - constant_quals); - } - *cheapest_path = cheapestpath; *sorted_path = sortedpath; } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index da1cadcd0db..160310c56d6 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.200 2006/06/28 20:04:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.201 2006/07/01 18:38:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -270,6 +270,9 @@ subquery_planner(Query *parse, double tuple_fraction, */ root->hasHavingQual = (parse->havingQual != NULL); + /* Clear this flag; might get set in distribute_qual_to_rels */ + root->hasPseudoConstantQuals = false; + /* * Do expression preprocessing on targetlist and quals. */ |