aboutsummaryrefslogtreecommitdiff
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.c214
-rw-r--r--src/backend/optimizer/plan/initsplan.c71
-rw-r--r--src/backend/optimizer/plan/planagg.c47
-rw-r--r--src/backend/optimizer/plan/planmain.c35
-rw-r--r--src/backend/optimizer/plan/planner.c5
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.
*/