summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/orindxpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/orindxpath.c')
-rw-r--r--src/backend/optimizer/path/orindxpath.c301
1 files changed, 31 insertions, 270 deletions
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index c30c26562c..fb055400d4 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,32 +8,19 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.68 2005/04/21 02:28:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.69 2005/04/25 01:30:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "optimizer/clauses.h"
#include "optimizer/cost.h"
-#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
-static IndexPath *best_or_subclause_indexes(Query *root, RelOptInfo *rel,
- List *subclauses);
-static bool best_or_subclause_index(Query *root,
- RelOptInfo *rel,
- Expr *subclause,
- IndexOptInfo **retIndexInfo,
- List **retIndexClauses,
- List **retIndexQuals,
- Cost *retStartupCost,
- Cost *retTotalCost);
-
-
/*----------
* create_or_index_quals
* Examine join OR-of-AND quals to see if any useful restriction OR
@@ -94,7 +81,7 @@ static bool best_or_subclause_index(Query *root,
bool
create_or_index_quals(Query *root, RelOptInfo *rel)
{
- IndexPath *bestpath = NULL;
+ BitmapOrPath *bestpath = NULL;
RestrictInfo *bestrinfo = NULL;
List *newrinfos;
RestrictInfo *or_rinfo;
@@ -103,8 +90,7 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
ListCell *i;
/*
- * We use the best_or_subclause_indexes() machinery to locate the best
- * combination of restriction subclauses. Note we must ignore any
+ * Find potentially interesting OR joinclauses. We must ignore any
* joinclauses that are not marked valid_everywhere, because they
* cannot be pushed down due to outer-join rules.
*/
@@ -120,18 +106,31 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
if (restriction_is_or_clause(rinfo) &&
rinfo->valid_everywhere)
{
- IndexPath *pathnode;
-
- pathnode = best_or_subclause_indexes(root,
- rel,
- ((BoolExpr *) rinfo->orclause)->args);
-
- if (pathnode)
+ /*
+ * Use the generate_bitmap_or_paths() machinery to estimate
+ * the value of each OR clause. We can use regular
+ * restriction clauses along with the OR clause contents to
+ * generate indexquals. We pass outer_relids = NULL so that
+ * sub-clauses that are actually joins will be ignored.
+ */
+ List *orpaths;
+ ListCell *k;
+
+ orpaths = generate_bitmap_or_paths(root, rel,
+ list_make1(rinfo),
+ rel->baserestrictinfo,
+ false, NULL);
+
+ /* Locate the cheapest OR path */
+ foreach(k, orpaths)
{
+ BitmapOrPath *path = (BitmapOrPath *) lfirst(k);
+
+ Assert(IsA(path, BitmapOrPath));
if (bestpath == NULL ||
- pathnode->path.total_cost < bestpath->path.total_cost)
+ path->path.total_cost < bestpath->path.total_cost)
{
- bestpath = pathnode;
+ bestpath = path;
bestrinfo = rinfo;
}
}
@@ -144,13 +143,14 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
return false;
/*
- * Convert the indexclauses structure to a RestrictInfo tree, and add
- * it to the rel's restriction list.
+ * Convert the path's indexclauses structure to a RestrictInfo tree,
+ * and add it to the rel's restriction list.
*/
- newrinfos = make_restrictinfo_from_indexclauses(bestpath->indexclauses,
- true, true);
+ newrinfos = create_bitmap_restriction((Path *) bestpath);
Assert(list_length(newrinfos) == 1);
or_rinfo = (RestrictInfo *) linitial(newrinfos);
+ Assert(IsA(or_rinfo, RestrictInfo));
+
rel->baserestrictinfo = list_concat(rel->baserestrictinfo, newrinfos);
/*
@@ -176,242 +176,3 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
/* Tell caller to recompute rel's rows estimate */
return true;
}
-
-/*
- * create_or_index_paths
- * Creates multi-scan index paths for indexes that match OR clauses.
- *
- * 'rel' is the relation entry for which the paths are to be created
- *
- * Returns nothing, but adds paths to rel->pathlist via add_path().
- *
- * Note: check_partial_indexes() must have been run previously.
- */
-void
-create_or_index_paths(Query *root, RelOptInfo *rel)
-{
- ListCell *l;
-
- /*
- * Check each restriction clause to see if it is an OR clause, and if
- * so, try to make a path using it.
- */
- foreach(l, rel->baserestrictinfo)
- {
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
-
- if (restriction_is_or_clause(rinfo))
- {
- IndexPath *pathnode;
-
- pathnode = best_or_subclause_indexes(root,
- rel,
- ((BoolExpr *) rinfo->orclause)->args);
-
- if (pathnode)
- add_path(rel, (Path *) pathnode);
- }
- }
-}
-
-/*
- * best_or_subclause_indexes
- * Determine the best index to be used in conjunction with each subclause
- * of an OR clause, and build a Path for a multi-index scan.
- *
- * 'rel' is the node of the relation to be scanned
- * 'subclauses' are the subclauses of the OR clause (must be the modified
- * form that includes sub-RestrictInfo clauses)
- *
- * Returns an IndexPath if successful, or NULL if it is not possible to
- * find an index for each OR subclause.
- *
- * NOTE: we choose each scan on the basis of its total cost, ignoring startup
- * cost. This is reasonable as long as all index types have zero or small
- * startup cost, but we might have to work harder if any index types with
- * nontrivial startup cost are ever invented.
- *
- * This routine also creates the indexqual list that will be needed by
- * the executor. The indexqual list has one entry for each scan of the base
- * rel, which is a sublist of indexqual conditions to apply in that scan.
- * The implicit semantics are AND across each sublist of quals, and OR across
- * the toplevel list (note that the executor takes care not to return any
- * single tuple more than once).
- */
-static IndexPath *
-best_or_subclause_indexes(Query *root,
- RelOptInfo *rel,
- List *subclauses)
-{
- List *infos = NIL;
- List *clauses = NIL;
- List *quals = NIL;
- Cost path_startup_cost = 0;
- Cost path_total_cost = 0;
- ListCell *slist;
- IndexPath *pathnode;
-
- /* Gather info for each OR subclause */
- foreach(slist, subclauses)
- {
- Expr *subclause = lfirst(slist);
- IndexOptInfo *best_indexinfo;
- List *best_indexclauses;
- List *best_indexquals;
- Cost best_startup_cost;
- Cost best_total_cost;
-
- if (!best_or_subclause_index(root, rel, subclause,
- &best_indexinfo,
- &best_indexclauses, &best_indexquals,
- &best_startup_cost, &best_total_cost))
- return NULL; /* failed to match this subclause */
-
- infos = lappend(infos, best_indexinfo);
- clauses = lappend(clauses, best_indexclauses);
- quals = lappend(quals, best_indexquals);
-
- /*
- * Path startup_cost is the startup cost for the first index scan
- * only; startup costs for later scans will be paid later on, so
- * they just get reflected in total_cost.
- *
- * Total cost is sum of the per-scan costs.
- */
- if (slist == list_head(subclauses)) /* first scan? */
- path_startup_cost = best_startup_cost;
- path_total_cost += best_total_cost;
- }
-
- /* We succeeded, so build an IndexPath node */
- pathnode = makeNode(IndexPath);
-
- pathnode->path.pathtype = T_IndexScan;
- pathnode->path.parent = rel;
- pathnode->path.startup_cost = path_startup_cost;
- pathnode->path.total_cost = path_total_cost;
-
- /*
- * This is an IndexScan, but the overall result will consist of tuples
- * extracted in multiple passes (one for each subclause of the OR), so
- * the result cannot be claimed to have any particular ordering.
- */
- pathnode->path.pathkeys = NIL;
-
- pathnode->indexinfo = infos;
- pathnode->indexclauses = clauses;
- pathnode->indexquals = quals;
-
- /* It's not an innerjoin path. */
- pathnode->isjoininner = false;
-
- /* We don't actually care what order the index scans in. */
- pathnode->indexscandir = NoMovementScanDirection;
-
- /*
- * The number of rows is the same as the parent rel's estimate, since
- * this isn't a join inner indexscan.
- */
- pathnode->rows = rel->rows;
-
- return pathnode;
-}
-
-/*
- * best_or_subclause_index
- * Determines which is the best index to be used with a subclause of an
- * OR clause by estimating the cost of using each index and selecting
- * the least expensive (considering total cost only, for now).
- *
- * Returns FALSE if no index exists that can be used with this OR subclause;
- * in that case the output parameters are not set.
- *
- * 'rel' is the node of the relation to be scanned
- * 'subclause' is the OR subclause being considered
- *
- * '*retIndexInfo' gets the IndexOptInfo of the best index
- * '*retIndexClauses' gets a list of the index clauses for the best index
- * '*retIndexQuals' gets a list of the expanded indexquals for the best index
- * '*retStartupCost' gets the startup cost of a scan with that index
- * '*retTotalCost' gets the total cost of a scan with that index
- */
-static bool
-best_or_subclause_index(Query *root,
- RelOptInfo *rel,
- Expr *subclause,
- IndexOptInfo **retIndexInfo, /* return value */
- List **retIndexClauses, /* return value */
- List **retIndexQuals, /* return value */
- Cost *retStartupCost, /* return value */
- Cost *retTotalCost) /* return value */
-{
- bool found = false;
- ListCell *ilist;
-
- foreach(ilist, rel->indexlist)
- {
- IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
- List *indexclauses;
- List *indexquals;
- IndexPath subclause_path;
-
- /*
- * Ignore partial indexes that do not match the query. If predOK
- * is true then the index's predicate is implied by top-level
- * restriction clauses, so we can use it. However, it might also
- * be implied by the current OR subclause (perhaps in conjunction
- * with the top-level clauses), in which case we can use it for this
- * particular scan.
- *
- * XXX this code is partially redundant with logic in
- * group_clauses_by_indexkey_for_or(); consider refactoring.
- */
- if (index->indpred != NIL && !index->predOK)
- {
- List *subclauserinfos;
-
- if (and_clause((Node *) subclause))
- subclauserinfos = list_copy(((BoolExpr *) subclause)->args);
- else if (IsA(subclause, RestrictInfo))
- subclauserinfos = list_make1(subclause);
- else
- continue; /* probably can't happen */
- if (!pred_test(index->indpred,
- list_concat(subclauserinfos,
- rel->baserestrictinfo)))
- continue;
- }
-
- /* Collect index clauses usable with this index */
- indexclauses = group_clauses_by_indexkey_for_or(index, subclause);
-
- /*
- * Ignore index if it doesn't match the subclause at all; except
- * that if it's a partial index matching the current OR subclause,
- * consider it anyway, since effectively we are using the index
- * predicate to match the subclause. (Note: we exclude partial
- * indexes that are predOK; else such a partial index would be
- * considered to match *every* OR subclause, generating bogus OR
- * plans that are redundant with the basic scan on that index.)
- */
- if (indexclauses == NIL && (index->indpred == NIL || index->predOK))
- continue;
-
- /* Convert clauses to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(index, indexclauses);
-
- cost_index(&subclause_path, root, index, indexquals, false);
-
- if (!found || subclause_path.path.total_cost < *retTotalCost)
- {
- *retIndexInfo = index;
- *retIndexClauses = flatten_clausegroups_list(indexclauses);
- *retIndexQuals = indexquals;
- *retStartupCost = subclause_path.path.startup_cost;
- *retTotalCost = subclause_path.path.total_cost;
- found = true;
- }
- }
-
- return found;
-}