aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/plan/planagg.c42
1 files changed, 32 insertions, 10 deletions
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 16d71af183d..80d01c02946 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.32 2007/04/27 22:05:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.33 2007/10/13 00:58:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "optimizer/predtest.h"
#include "optimizer/subselect.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
@@ -35,6 +36,7 @@ typedef struct
Oid aggfnoid; /* pg_proc Oid of the aggregate */
Oid aggsortop; /* Oid of its sort operator */
Expr *target; /* expression we are aggregating on */
+ Expr *notnulltest; /* expression for "target IS NOT NULL" */
IndexPath *path; /* access path for index scan */
Cost pathcost; /* estimated cost to fetch first row */
bool nulls_first; /* null ordering direction matching index */
@@ -285,8 +287,23 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
IndexPath *best_path = NULL;
Cost best_cost = 0;
bool best_nulls_first = false;
+ NullTest *ntest;
+ List *allquals;
ListCell *l;
+ /* Build "target IS NOT NULL" expression for use below */
+ ntest = makeNode(NullTest);
+ ntest->nulltesttype = IS_NOT_NULL;
+ ntest->arg = copyObject(info->target);
+ info->notnulltest = (Expr *) ntest;
+
+ /*
+ * Build list of existing restriction clauses plus the notnull test.
+ * We cheat a bit by not bothering with a RestrictInfo node for the
+ * notnull test --- predicate_implied_by() won't care.
+ */
+ allquals = list_concat(list_make1(ntest), rel->baserestrictinfo);
+
foreach(l, rel->indexlist)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
@@ -302,8 +319,13 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
if (index->relam != BTREE_AM_OID)
continue;
- /* Ignore partial indexes that do not match the query */
- if (index->indpred != NIL && !index->predOK)
+ /*
+ * Ignore partial indexes that do not match the query --- unless
+ * their predicates can be proven from the baserestrict list plus
+ * the IS NOT NULL test. In that case we can use them.
+ */
+ if (index->indpred != NIL && !index->predOK &&
+ !predicate_implied_by(index->indpred, allquals))
continue;
/*
@@ -441,7 +463,6 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
Plan *iplan;
TargetEntry *tle;
SortClause *sortcl;
- NullTest *ntest;
/*
* Generate a suitably modified query. Much of the work here is probably
@@ -487,7 +508,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
* basic indexscan, but we have to convert it to a Plan and attach a LIMIT
* node above it.
*
- * Also we must add a "WHERE foo IS NOT NULL" restriction to the
+ * Also we must add a "WHERE target IS NOT NULL" restriction to the
* indexscan, to be sure we don't return a NULL, which'd be contrary to
* the standard behavior of MIN/MAX. XXX ideally this should be done
* earlier, so that the selectivity of the restriction could be included
@@ -497,6 +518,9 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
* 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.
+ *
+ * We can skip adding the NOT NULL qual if it's redundant with either
+ * an already-given WHERE condition, or a clause of the index predicate.
*/
plan = create_plan(&subroot, (Path *) info->path);
@@ -508,11 +532,9 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
iplan = plan;
Assert(IsA(iplan, IndexScan));
- ntest = makeNode(NullTest);
- ntest->nulltesttype = IS_NOT_NULL;
- ntest->arg = copyObject(info->target);
-
- iplan->qual = lcons(ntest, iplan->qual);
+ if (!list_member(iplan->qual, info->notnulltest) &&
+ !list_member(info->path->indexinfo->indpred, info->notnulltest))
+ iplan->qual = lcons(info->notnulltest, iplan->qual);
plan = (Plan *) make_limit(plan,
subparse->limitOffset,