mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Remove support for OR'd indexscans internal to a single IndexScan plan
node, as this behavior is now better done as a bitmap OR indexscan. This allows considerable simplification in nodeIndexscan.c itself as well as several planner modules concerned with indexscan plan generation. Also we can improve the sharing of code between regular and bitmap indexscans, since they are now working with nigh-identical Plan nodes.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.127 2005/04/21 19:18:12 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.128 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -174,13 +174,12 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
/* Consider sequential scan */
|
||||
add_path(rel, create_seqscan_path(root, rel));
|
||||
|
||||
/* Consider index scans */
|
||||
create_index_paths(root, rel);
|
||||
|
||||
/* Consider TID scans */
|
||||
create_tidscan_paths(root, rel);
|
||||
|
||||
/* Consider index paths for both simple and OR index clauses */
|
||||
create_index_paths(root, rel);
|
||||
create_or_index_paths(root, rel);
|
||||
|
||||
/* Now find the cheapest of the paths for this rel */
|
||||
set_cheapest(rel);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.177 2005/04/23 01:57:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.178 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,10 +58,6 @@ static List *find_usable_indexes(Query *root, RelOptInfo *rel,
|
||||
List *clauses, List *outer_clauses,
|
||||
bool istoplevel, bool isjoininner,
|
||||
Relids outer_relids);
|
||||
static List *generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
|
||||
List *clauses, List *outer_clauses,
|
||||
bool isjoininner,
|
||||
Relids outer_relids);
|
||||
static Path *choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths);
|
||||
static int bitmap_path_comparator(const void *a, const void *b);
|
||||
static Cost bitmap_and_cost_est(Query *root, RelOptInfo *rel, List *paths);
|
||||
@@ -365,7 +361,7 @@ find_usable_indexes(Query *root, RelOptInfo *rel,
|
||||
* for the purpose of generating indexquals, but are not to be searched for
|
||||
* ORs. (See find_usable_indexes() for motivation.)
|
||||
*/
|
||||
static List *
|
||||
List *
|
||||
generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
|
||||
List *clauses, List *outer_clauses,
|
||||
bool isjoininner,
|
||||
@@ -520,11 +516,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths)
|
||||
paths = list_make1(patharray[0]);
|
||||
costsofar = bitmap_and_cost_est(root, rel, paths);
|
||||
if (IsA(patharray[0], IndexPath))
|
||||
{
|
||||
Assert(list_length(((IndexPath *) patharray[0])->indexclauses) == 1);
|
||||
qualsofar = (List *) linitial(((IndexPath *) patharray[0])->indexclauses);
|
||||
qualsofar = list_copy(qualsofar);
|
||||
}
|
||||
qualsofar = list_copy(((IndexPath *) patharray[0])->indexclauses);
|
||||
else
|
||||
qualsofar = NIL;
|
||||
lastcell = list_head(paths); /* for quick deletions */
|
||||
@@ -537,8 +529,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths)
|
||||
|
||||
if (IsA(newpath, IndexPath))
|
||||
{
|
||||
Assert(list_length(((IndexPath *) newpath)->indexclauses) == 1);
|
||||
newqual = (List *) linitial(((IndexPath *) newpath)->indexclauses);
|
||||
newqual = ((IndexPath *) newpath)->indexclauses;
|
||||
if (list_difference(newqual, qualsofar) == NIL)
|
||||
continue; /* redundant */
|
||||
}
|
||||
@@ -714,108 +705,6 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* group_clauses_by_indexkey_for_or
|
||||
* Generate a list of sublists of clauses that can be used with an index
|
||||
* to find rows matching an OR subclause.
|
||||
*
|
||||
* This is essentially just like group_clauses_by_indexkey() except that
|
||||
* we can use the given clause (or any AND subclauses of it) as well as
|
||||
* top-level restriction clauses of the relation. Furthermore, we demand
|
||||
* that at least one such use be made, otherwise we fail and return NIL.
|
||||
* (Any path we made without such a use would be redundant with non-OR
|
||||
* indexscans.)
|
||||
*
|
||||
* XXX When we generate an indexqual list that uses both the OR subclause
|
||||
* and top-level restriction clauses, we end up with a slightly inefficient
|
||||
* plan because create_indexscan_plan is not very bright about figuring out
|
||||
* which restriction clauses are implied by the generated indexqual condition.
|
||||
* Currently we'll end up rechecking both the OR clause and the top-level
|
||||
* restriction clause as qpquals. FIXME someday.
|
||||
*/
|
||||
List *
|
||||
group_clauses_by_indexkey_for_or(IndexOptInfo *index, Expr *orsubclause)
|
||||
{
|
||||
List *clausegroup_list = NIL;
|
||||
bool matched = false;
|
||||
int indexcol = 0;
|
||||
Oid *classes = index->classlist;
|
||||
|
||||
do
|
||||
{
|
||||
Oid curClass = classes[0];
|
||||
List *clausegroup = NIL;
|
||||
ListCell *item;
|
||||
|
||||
/* Try to match the OR subclause to the index key */
|
||||
if (IsA(orsubclause, RestrictInfo))
|
||||
{
|
||||
if (match_clause_to_indexcol(index, indexcol, curClass,
|
||||
(RestrictInfo *) orsubclause,
|
||||
NULL))
|
||||
{
|
||||
clausegroup = lappend(clausegroup, orsubclause);
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
else if (and_clause((Node *) orsubclause))
|
||||
{
|
||||
foreach(item, ((BoolExpr *) orsubclause)->args)
|
||||
{
|
||||
RestrictInfo *subsubclause = (RestrictInfo *) lfirst(item);
|
||||
|
||||
if (IsA(subsubclause, RestrictInfo) &&
|
||||
match_clause_to_indexcol(index, indexcol, curClass,
|
||||
subsubclause,
|
||||
NULL))
|
||||
{
|
||||
clausegroup = lappend(clausegroup, subsubclause);
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found no clauses for this indexkey in the OR subclause
|
||||
* itself, try looking in the rel's top-level restriction list.
|
||||
*
|
||||
* XXX should we always search the top-level list? Slower but could
|
||||
* sometimes yield a better plan.
|
||||
*/
|
||||
if (clausegroup == NIL)
|
||||
{
|
||||
foreach(item, index->rel->baserestrictinfo)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
|
||||
|
||||
if (match_clause_to_indexcol(index, indexcol, curClass,
|
||||
rinfo,
|
||||
NULL))
|
||||
clausegroup = lappend(clausegroup, rinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If still no clauses match this key, we're done; we don't want
|
||||
* to look at keys to its right.
|
||||
*/
|
||||
if (clausegroup == NIL)
|
||||
break;
|
||||
|
||||
clausegroup_list = lappend(clausegroup_list, clausegroup);
|
||||
|
||||
indexcol++;
|
||||
classes++;
|
||||
} while (!DoneMatchingIndexKeys(classes));
|
||||
|
||||
/* if OR clause was not used then forget it, per comments above */
|
||||
if (!matched)
|
||||
return NIL;
|
||||
|
||||
return clausegroup_list;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* match_clause_to_indexcol()
|
||||
* Determines whether a restriction clause matches a column of an index.
|
||||
@@ -2017,7 +1906,7 @@ find_clauses_for_join(Query *root, RelOptInfo *rel,
|
||||
* of RestrictInfos.
|
||||
*
|
||||
* This is used to flatten out the result of group_clauses_by_indexkey()
|
||||
* or one of its sibling routines, to produce an indexclauses list.
|
||||
* to produce an indexclauses list.
|
||||
*/
|
||||
List *
|
||||
flatten_clausegroups_list(List *clausegroups)
|
||||
@@ -2030,39 +1919,6 @@ flatten_clausegroups_list(List *clausegroups)
|
||||
return allclauses;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_expr_from_indexclauses()
|
||||
* Given an indexclauses structure, produce an ordinary boolean expression.
|
||||
*
|
||||
* This consists of stripping out the RestrictInfo nodes and inserting
|
||||
* explicit AND and OR nodes as needed. There's not much to it, but
|
||||
* the functionality is needed in a few places, so centralize the logic.
|
||||
*/
|
||||
Expr *
|
||||
make_expr_from_indexclauses(List *indexclauses)
|
||||
{
|
||||
List *orclauses = NIL;
|
||||
ListCell *orlist;
|
||||
|
||||
/* There's no such thing as an indexpath with zero scans */
|
||||
Assert(indexclauses != NIL);
|
||||
|
||||
foreach(orlist, indexclauses)
|
||||
{
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
|
||||
/* Strip RestrictInfos */
|
||||
andlist = get_actual_clauses(andlist);
|
||||
/* Insert AND node if needed, and add to orclauses list */
|
||||
orclauses = lappend(orclauses, make_ands_explicit(andlist));
|
||||
}
|
||||
|
||||
if (list_length(orclauses) > 1)
|
||||
return make_orclause(orclauses);
|
||||
else
|
||||
return (Expr *) linitial(orclauses);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* ---- ROUTINES TO CHECK OPERANDS ----
|
||||
@@ -2403,7 +2259,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
*
|
||||
* The input list is ordered by index key, and so the output list is too.
|
||||
* (The latter is not depended on by any part of the planner, so far as I can
|
||||
* tell; but some parts of the executor do assume that the indxqual list
|
||||
* tell; but some parts of the executor do assume that the indexqual list
|
||||
* ultimately delivered to the executor is so ordered. One such place is
|
||||
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
|
||||
* someday --- tgl 7/00)
|
||||
|
||||
@@ -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;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
pathnode = best_or_subclause_indexes(root,
|
||||
rel,
|
||||
((BoolExpr *) rinfo->orclause)->args);
|
||||
orpaths = generate_bitmap_or_paths(root, rel,
|
||||
list_make1(rinfo),
|
||||
rel->baserestrictinfo,
|
||||
false, NULL);
|
||||
|
||||
if (pathnode)
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.184 2005/04/23 01:29:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.185 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -47,13 +47,14 @@ static Plan *create_unique_plan(Query *root, UniquePath *best_path);
|
||||
static SeqScan *create_seqscan_plan(Query *root, Path *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
List *tlist, List *scan_clauses,
|
||||
List **nonlossy_clauses);
|
||||
static BitmapHeapScan *create_bitmap_scan_plan(Query *root,
|
||||
BitmapHeapPath *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual);
|
||||
static Plan *create_bitmap_subplan(Query *root, Path *bitmapqual,
|
||||
List **qual, List **indexqual);
|
||||
static List *create_bitmap_qual(Path *bitmapqual);
|
||||
static List *create_bitmap_indxqual(Path *bitmapqual);
|
||||
static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
|
||||
@@ -66,31 +67,26 @@ static MergeJoin *create_mergejoin_plan(Query *root, MergePath *best_path,
|
||||
Plan *outer_plan, Plan *inner_plan);
|
||||
static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
|
||||
Plan *outer_plan, Plan *inner_plan);
|
||||
static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals,
|
||||
List **indxstrategy,
|
||||
List **indxsubtype,
|
||||
List **indxlossy);
|
||||
static void fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
|
||||
List **fixed_quals,
|
||||
List **strategy,
|
||||
List **subtype,
|
||||
List **lossy);
|
||||
static Node *fix_indxqual_operand(Node *node, IndexOptInfo *index,
|
||||
static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals,
|
||||
List **nonlossy_indexquals,
|
||||
List **indexstrategy,
|
||||
List **indexsubtype);
|
||||
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
|
||||
Oid *opclass);
|
||||
static List *get_switched_clauses(List *clauses, Relids outerrelids);
|
||||
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);
|
||||
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
|
||||
List *indxid, List *indxqual, List *indxqualorig,
|
||||
List *indxstrategy, List *indxsubtype, List *indxlossy,
|
||||
Oid indexid, List *indexqual, List *indexqualorig,
|
||||
List *indexstrategy, List *indexsubtype,
|
||||
ScanDirection indexscandir);
|
||||
static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indxid,
|
||||
List *indxqual,
|
||||
List *indxqualorig,
|
||||
List *indxstrategy,
|
||||
List *indxsubtype);
|
||||
static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid,
|
||||
List *indexqual,
|
||||
List *indexqualorig,
|
||||
List *indexstrategy,
|
||||
List *indexsubtype);
|
||||
static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
|
||||
List *qpqual,
|
||||
Plan *lefttree,
|
||||
@@ -236,7 +232,8 @@ create_scan_plan(Query *root, Path *best_path)
|
||||
plan = (Scan *) create_indexscan_plan(root,
|
||||
(IndexPath *) best_path,
|
||||
tlist,
|
||||
scan_clauses);
|
||||
scan_clauses,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case T_BitmapHeapScan:
|
||||
@@ -701,121 +698,84 @@ create_seqscan_plan(Query *root, Path *best_path,
|
||||
* Returns an indexscan plan for the base relation scanned by 'best_path'
|
||||
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
|
||||
*
|
||||
* The indexquals list of the path contains a sublist of implicitly-ANDed
|
||||
* qual conditions for each scan of the index(es); if there is more than one
|
||||
* scan then the retrieved tuple sets are ORed together. The indexquals
|
||||
* and indexinfo lists must have the same length, ie, the number of scans
|
||||
* that will occur. Note it is possible for a qual condition sublist
|
||||
* to be empty --- then no index restrictions will be applied during that
|
||||
* scan.
|
||||
* The indexquals list of the path contains implicitly-ANDed qual conditions.
|
||||
* The list can be empty --- then no index restrictions will be applied during
|
||||
* the scan.
|
||||
*
|
||||
* If nonlossy_clauses isn't NULL, *nonlossy_clauses receives a list of the
|
||||
* nonlossy indexquals.
|
||||
*/
|
||||
static IndexScan *
|
||||
create_indexscan_plan(Query *root,
|
||||
IndexPath *best_path,
|
||||
List *tlist,
|
||||
List *scan_clauses)
|
||||
List *scan_clauses,
|
||||
List **nonlossy_clauses)
|
||||
{
|
||||
List *indxquals = best_path->indexquals;
|
||||
List *indexquals = best_path->indexquals;
|
||||
Index baserelid = best_path->path.parent->relid;
|
||||
Oid indexoid = best_path->indexinfo->indexoid;
|
||||
List *qpqual;
|
||||
Expr *indxqual_or_expr = NULL;
|
||||
List *stripped_indxquals;
|
||||
List *fixed_indxquals;
|
||||
List *indxstrategy;
|
||||
List *indxsubtype;
|
||||
List *indxlossy;
|
||||
List *indexids;
|
||||
ListCell *l;
|
||||
List *stripped_indexquals;
|
||||
List *fixed_indexquals;
|
||||
List *nonlossy_indexquals;
|
||||
List *indexstrategy;
|
||||
List *indexsubtype;
|
||||
IndexScan *scan_plan;
|
||||
|
||||
/* it should be a base rel... */
|
||||
Assert(baserelid > 0);
|
||||
Assert(best_path->path.parent->rtekind == RTE_RELATION);
|
||||
|
||||
/* Build list of index OIDs */
|
||||
indexids = NIL;
|
||||
foreach(l, best_path->indexinfo)
|
||||
{
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
|
||||
|
||||
indexids = lappend_oid(indexids, index->indexoid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build "stripped" indexquals structure (no RestrictInfos) to pass to
|
||||
* executor as indxqualorig
|
||||
* executor as indexqualorig
|
||||
*/
|
||||
stripped_indxquals = NIL;
|
||||
foreach(l, indxquals)
|
||||
{
|
||||
List *andlist = (List *) lfirst(l);
|
||||
|
||||
stripped_indxquals = lappend(stripped_indxquals,
|
||||
get_actual_clauses(andlist));
|
||||
}
|
||||
stripped_indexquals = get_actual_clauses(indexquals);
|
||||
|
||||
/*
|
||||
* The executor needs a copy with the indexkey on the left of each
|
||||
* clause and with index attr numbers substituted for table ones. This
|
||||
* pass also gets strategy info and looks for "lossy" operators.
|
||||
*/
|
||||
fix_indxqual_references(indxquals, best_path,
|
||||
&fixed_indxquals,
|
||||
&indxstrategy, &indxsubtype, &indxlossy);
|
||||
fix_indexqual_references(indexquals, best_path,
|
||||
&fixed_indexquals,
|
||||
&nonlossy_indexquals,
|
||||
&indexstrategy,
|
||||
&indexsubtype);
|
||||
|
||||
/* pass back nonlossy quals if caller wants 'em */
|
||||
if (nonlossy_clauses)
|
||||
*nonlossy_clauses = nonlossy_indexquals;
|
||||
|
||||
/*
|
||||
* If this is a innerjoin scan, the indexclauses will contain join
|
||||
* If this is an innerjoin scan, the indexclauses will contain join
|
||||
* clauses that are not present in scan_clauses (since the passed-in
|
||||
* value is just the rel's baserestrictinfo list). We must add these
|
||||
* clauses to scan_clauses to ensure they get checked. In most cases
|
||||
* we will remove the join clauses again below, but if a join clause
|
||||
* contains a special operator, we need to make sure it gets into the
|
||||
* scan_clauses.
|
||||
*
|
||||
* Note: pointer comparison should be enough to determine RestrictInfo
|
||||
* matches.
|
||||
*/
|
||||
if (best_path->isjoininner)
|
||||
{
|
||||
/*
|
||||
* We don't currently support OR indexscans in joins, so we only
|
||||
* need to worry about the plain AND case. Also, pointer
|
||||
* comparison should be enough to determine RestrictInfo matches.
|
||||
*/
|
||||
Assert(list_length(best_path->indexclauses) == 1);
|
||||
scan_clauses = list_union_ptr(scan_clauses,
|
||||
(List *) linitial(best_path->indexclauses));
|
||||
}
|
||||
|
||||
/* Reduce RestrictInfo list to bare expressions */
|
||||
scan_clauses = get_actual_clauses(scan_clauses);
|
||||
scan_clauses = list_union_ptr(scan_clauses, best_path->indexclauses);
|
||||
|
||||
/*
|
||||
* The qpqual list must contain all restrictions not automatically
|
||||
* handled by the index. All the predicates in the indexquals will be
|
||||
* checked (either by the index itself, or by nodeIndexscan.c), but if
|
||||
* there are any "special" operators involved then they must be added
|
||||
* to qpqual. The upshot is that qpquals must contain scan_clauses
|
||||
* minus whatever appears in indxquals.
|
||||
* there are any "special" operators involved then they must be included
|
||||
* in qpqual. Also, any lossy index operators must be rechecked in
|
||||
* the qpqual. The upshot is that qpquals must contain scan_clauses
|
||||
* minus whatever appears in nonlossy_indexquals.
|
||||
*/
|
||||
if (list_length(indxquals) > 1)
|
||||
{
|
||||
/*
|
||||
* Build an expression representation of the indexqual, expanding
|
||||
* the implicit OR and AND semantics of the first- and
|
||||
* second-level lists. (The odds that this will exactly match any
|
||||
* scan_clause are not great; perhaps we need more smarts here.)
|
||||
*/
|
||||
indxqual_or_expr = make_expr_from_indexclauses(indxquals);
|
||||
qpqual = list_difference(scan_clauses, list_make1(indxqual_or_expr));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Here, we can simply treat the first sublist as an independent
|
||||
* set of qual expressions, since there is no top-level OR
|
||||
* behavior.
|
||||
*/
|
||||
Assert(stripped_indxquals != NIL);
|
||||
qpqual = list_difference(scan_clauses, linitial(stripped_indxquals));
|
||||
}
|
||||
qpqual = list_difference_ptr(scan_clauses, nonlossy_indexquals);
|
||||
|
||||
/* Reduce RestrictInfo list to bare expressions */
|
||||
qpqual = get_actual_clauses(qpqual);
|
||||
|
||||
/* Sort clauses into best execution order */
|
||||
qpqual = order_qual_clauses(root, qpqual);
|
||||
@@ -824,12 +784,11 @@ create_indexscan_plan(Query *root,
|
||||
scan_plan = make_indexscan(tlist,
|
||||
qpqual,
|
||||
baserelid,
|
||||
indexids,
|
||||
fixed_indxquals,
|
||||
stripped_indxquals,
|
||||
indxstrategy,
|
||||
indxsubtype,
|
||||
indxlossy,
|
||||
indexoid,
|
||||
fixed_indexquals,
|
||||
stripped_indexquals,
|
||||
indexstrategy,
|
||||
indexsubtype,
|
||||
best_path->indexscandir);
|
||||
|
||||
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
|
||||
@@ -861,14 +820,9 @@ create_bitmap_scan_plan(Query *root,
|
||||
Assert(baserelid > 0);
|
||||
Assert(best_path->path.parent->rtekind == RTE_RELATION);
|
||||
|
||||
/* Process the bitmapqual tree into a Plan tree */
|
||||
bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual);
|
||||
|
||||
/* Process the bitmapqual tree into an expression tree, too */
|
||||
bitmapqualorig = create_bitmap_qual(best_path->bitmapqual);
|
||||
|
||||
/* Also extract the true index conditions */
|
||||
indexquals = create_bitmap_indxqual(best_path->bitmapqual);
|
||||
/* Process the bitmapqual tree into a Plan tree and qual lists */
|
||||
bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
|
||||
&bitmapqualorig, &indexquals);
|
||||
|
||||
/* Reduce RestrictInfo list to bare expressions */
|
||||
scan_clauses = get_actual_clauses(scan_clauses);
|
||||
@@ -922,70 +876,101 @@ create_bitmap_scan_plan(Query *root,
|
||||
|
||||
/*
|
||||
* Given a bitmapqual tree, generate the Plan tree that implements it
|
||||
*
|
||||
* As byproducts, we also return in *qual and *indexqual the qual lists
|
||||
* (in implicit-AND form, without RestrictInfos) describing the original index
|
||||
* conditions and the generated indexqual conditions. The latter is made to
|
||||
* exclude lossy index operators.
|
||||
*/
|
||||
static Plan *
|
||||
create_bitmap_subplan(Query *root, Path *bitmapqual)
|
||||
create_bitmap_subplan(Query *root, Path *bitmapqual,
|
||||
List **qual, List **indexqual)
|
||||
{
|
||||
Plan *plan;
|
||||
|
||||
if (IsA(bitmapqual, BitmapAndPath))
|
||||
{
|
||||
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
|
||||
List *newlist = NIL;
|
||||
List *subplans = NIL;
|
||||
List *subquals = NIL;
|
||||
List *subindexquals = NIL;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, apath->bitmapquals)
|
||||
{
|
||||
Plan *subplan = create_bitmap_subplan(root, lfirst(l));
|
||||
Plan *subplan;
|
||||
List *subqual;
|
||||
List *subindexqual;
|
||||
|
||||
newlist = lappend(newlist, subplan);
|
||||
subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
|
||||
&subqual, &subindexqual);
|
||||
subplans = lappend(subplans, subplan);
|
||||
subquals = list_concat(subquals, subqual);
|
||||
subindexquals = list_concat(subindexquals, subindexqual);
|
||||
}
|
||||
plan = (Plan *) make_bitmap_and(newlist);
|
||||
plan = (Plan *) make_bitmap_and(subplans);
|
||||
plan->startup_cost = apath->path.startup_cost;
|
||||
plan->total_cost = apath->path.total_cost;
|
||||
plan->plan_rows =
|
||||
clamp_row_est(apath->bitmapselectivity * apath->path.parent->tuples);
|
||||
plan->plan_width = 0; /* meaningless */
|
||||
*qual = subquals;
|
||||
*indexqual = subindexquals;
|
||||
}
|
||||
else if (IsA(bitmapqual, BitmapOrPath))
|
||||
{
|
||||
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
|
||||
List *newlist = NIL;
|
||||
List *subplans = NIL;
|
||||
List *subquals = NIL;
|
||||
List *subindexquals = NIL;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, opath->bitmapquals)
|
||||
{
|
||||
Plan *subplan = create_bitmap_subplan(root, lfirst(l));
|
||||
Plan *subplan;
|
||||
List *subqual;
|
||||
List *subindexqual;
|
||||
|
||||
newlist = lappend(newlist, subplan);
|
||||
subplan = create_bitmap_subplan(root, (Path *) lfirst(l),
|
||||
&subqual, &subindexqual);
|
||||
subplans = lappend(subplans, subplan);
|
||||
subquals = lappend(subquals,
|
||||
make_ands_explicit(subqual));
|
||||
subindexquals = lappend(subindexquals,
|
||||
make_ands_explicit(subindexqual));
|
||||
}
|
||||
plan = (Plan *) make_bitmap_or(newlist);
|
||||
plan = (Plan *) make_bitmap_or(subplans);
|
||||
plan->startup_cost = opath->path.startup_cost;
|
||||
plan->total_cost = opath->path.total_cost;
|
||||
plan->plan_rows =
|
||||
clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples);
|
||||
plan->plan_width = 0; /* meaningless */
|
||||
*qual = list_make1(make_orclause(subquals));
|
||||
*indexqual = list_make1(make_orclause(subindexquals));
|
||||
}
|
||||
else if (IsA(bitmapqual, IndexPath))
|
||||
{
|
||||
IndexPath *ipath = (IndexPath *) bitmapqual;
|
||||
IndexScan *iscan;
|
||||
List *nonlossy_clauses;
|
||||
|
||||
/* Use the regular indexscan plan build machinery... */
|
||||
iscan = create_indexscan_plan(root, ipath, NIL, NIL);
|
||||
Assert(list_length(iscan->indxid) == 1);
|
||||
iscan = create_indexscan_plan(root, ipath, NIL, NIL,
|
||||
&nonlossy_clauses);
|
||||
/* then convert to a bitmap indexscan */
|
||||
plan = (Plan *) make_bitmap_indexscan(iscan->scan.scanrelid,
|
||||
linitial_oid(iscan->indxid),
|
||||
linitial(iscan->indxqual),
|
||||
linitial(iscan->indxqualorig),
|
||||
linitial(iscan->indxstrategy),
|
||||
linitial(iscan->indxsubtype));
|
||||
iscan->indexid,
|
||||
iscan->indexqual,
|
||||
iscan->indexqualorig,
|
||||
iscan->indexstrategy,
|
||||
iscan->indexsubtype);
|
||||
plan->startup_cost = 0.0;
|
||||
plan->total_cost = ipath->indextotalcost;
|
||||
plan->plan_rows =
|
||||
clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
|
||||
plan->plan_width = 0; /* meaningless */
|
||||
*qual = get_actual_clauses(ipath->indexclauses);
|
||||
*indexqual = get_actual_clauses(nonlossy_clauses);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1041,8 +1026,7 @@ create_bitmap_qual(Path *bitmapqual)
|
||||
{
|
||||
IndexPath *ipath = (IndexPath *) bitmapqual;
|
||||
|
||||
Assert(list_length(ipath->indexclauses) == 1);
|
||||
result = get_actual_clauses(linitial(ipath->indexclauses));
|
||||
result = get_actual_clauses(ipath->indexclauses);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1054,132 +1038,27 @@ create_bitmap_qual(Path *bitmapqual)
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as above, except extract the indxqual conditions (which are different
|
||||
* if there are special index operators or lossy operators involved).
|
||||
*
|
||||
* The result essentially represents the conditions the indexscan guarantees
|
||||
* to enforce, which may be weaker than the original qual expressions.
|
||||
* Given a bitmapqual tree, generate the equivalent RestrictInfo list.
|
||||
*/
|
||||
static List *
|
||||
create_bitmap_indxqual(Path *bitmapqual)
|
||||
List *
|
||||
create_bitmap_restriction(Path *bitmapqual)
|
||||
{
|
||||
List *result;
|
||||
List *sublist;
|
||||
List *bitmapquals;
|
||||
List *bitmapclauses;
|
||||
ListCell *l;
|
||||
|
||||
if (IsA(bitmapqual, BitmapAndPath))
|
||||
bitmapquals = create_bitmap_qual(bitmapqual);
|
||||
|
||||
/* must convert qual list to restrictinfos ... painful ... */
|
||||
bitmapclauses = NIL;
|
||||
foreach(l, bitmapquals)
|
||||
{
|
||||
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
|
||||
|
||||
result = NIL;
|
||||
foreach(l, apath->bitmapquals)
|
||||
{
|
||||
sublist = create_bitmap_indxqual(lfirst(l));
|
||||
result = list_concat(result, sublist);
|
||||
}
|
||||
}
|
||||
else if (IsA(bitmapqual, BitmapOrPath))
|
||||
{
|
||||
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
|
||||
List *newlist = NIL;
|
||||
|
||||
foreach(l, opath->bitmapquals)
|
||||
{
|
||||
sublist = create_bitmap_indxqual(lfirst(l));
|
||||
if (sublist == NIL)
|
||||
{
|
||||
/* constant TRUE input yields constant TRUE OR result */
|
||||
return NIL;
|
||||
}
|
||||
newlist = lappend(newlist, make_ands_explicit(sublist));
|
||||
}
|
||||
result = list_make1(make_orclause(newlist));
|
||||
}
|
||||
else if (IsA(bitmapqual, IndexPath))
|
||||
{
|
||||
IndexPath *ipath = (IndexPath *) bitmapqual;
|
||||
IndexOptInfo *index;
|
||||
|
||||
Assert(list_length(ipath->indexinfo) == 1);
|
||||
index = linitial(ipath->indexinfo);
|
||||
|
||||
/*
|
||||
* We have to remove "lossy" index operators from the result, since
|
||||
* the index isn't guaranteeing they are enforced. (This will lead
|
||||
* to the operators being rechecked as qpquals of the BitmapHeapScan
|
||||
* node.)
|
||||
*
|
||||
* XXX look at restructuring to share code better with
|
||||
* fix_indxqual_references()
|
||||
*/
|
||||
result = NIL;
|
||||
Assert(list_length(ipath->indexquals) == 1);
|
||||
foreach(l, (List *) linitial(ipath->indexquals))
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
|
||||
OpExpr *clause;
|
||||
Oid opno;
|
||||
Node *indexkey;
|
||||
Oid opclass;
|
||||
int stratno;
|
||||
Oid stratsubtype;
|
||||
bool recheck;
|
||||
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
clause = (OpExpr *) rinfo->clause;
|
||||
if (!IsA(clause, OpExpr) || list_length(clause->args) != 2)
|
||||
elog(ERROR, "indexqual clause is not binary opclause");
|
||||
opno = clause->opno;
|
||||
|
||||
/*
|
||||
* Check to see if the indexkey is on the right; if so, commute
|
||||
* the operator. The indexkey should be the side that refers to
|
||||
* (only) the base relation.
|
||||
*/
|
||||
if (!bms_equal(rinfo->left_relids, index->rel->relids))
|
||||
{
|
||||
opno = get_commutator(opno);
|
||||
if (!OidIsValid(opno))
|
||||
elog(ERROR, "could not find commutator for operator %u",
|
||||
clause->opno);
|
||||
indexkey = lsecond(clause->args);
|
||||
}
|
||||
else
|
||||
indexkey = linitial(clause->args);
|
||||
|
||||
/*
|
||||
* Identify the index attribute and get the index opclass.
|
||||
* We use fix_indxqual_operand() which does a little more
|
||||
* than we really need, but it will do.
|
||||
*/
|
||||
(void) fix_indxqual_operand(indexkey,
|
||||
index,
|
||||
&opclass);
|
||||
|
||||
/*
|
||||
* Look up the (possibly commuted) operator in the operator class
|
||||
* to get its strategy numbers and the recheck indicator. This
|
||||
* also double-checks that we found an operator matching the
|
||||
* index.
|
||||
*/
|
||||
get_op_opclass_properties(opno, opclass,
|
||||
&stratno, &stratsubtype, &recheck);
|
||||
|
||||
/*
|
||||
* Finally, we can include the clause in the result if it's
|
||||
* not a lossy operator.
|
||||
*/
|
||||
if (!recheck)
|
||||
result = lappend(result, clause);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));
|
||||
result = NIL; /* keep compiler quiet */
|
||||
bitmapclauses = lappend(bitmapclauses,
|
||||
make_restrictinfo((Expr *) lfirst(l),
|
||||
true, true));
|
||||
}
|
||||
|
||||
return result;
|
||||
return bitmapclauses;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1299,10 +1178,7 @@ create_nestloop_plan(Query *root,
|
||||
* An index is being used to reduce the number of tuples scanned
|
||||
* in the inner relation. If there are join clauses being used
|
||||
* with the index, we may remove those join clauses from the list
|
||||
* of clauses that have to be checked as qpquals at the join node
|
||||
* --- but only if there's just one indexscan in the inner path
|
||||
* (otherwise, several different sets of clauses are being ORed
|
||||
* together).
|
||||
* of clauses that have to be checked as qpquals at the join node.
|
||||
*
|
||||
* We can also remove any join clauses that are redundant with those
|
||||
* being used in the index scan; prior redundancy checks will not
|
||||
@@ -1313,15 +1189,13 @@ create_nestloop_plan(Query *root,
|
||||
* not a special innerjoin path.
|
||||
*/
|
||||
IndexPath *innerpath = (IndexPath *) best_path->innerjoinpath;
|
||||
List *indexclauses = innerpath->indexclauses;
|
||||
|
||||
if (innerpath->isjoininner &&
|
||||
list_length(indexclauses) == 1) /* single indexscan? */
|
||||
if (innerpath->isjoininner)
|
||||
{
|
||||
joinrestrictclauses =
|
||||
select_nonredundant_join_clauses(root,
|
||||
joinrestrictclauses,
|
||||
linitial(indexclauses),
|
||||
innerpath->indexclauses,
|
||||
IS_OUTER_JOIN(best_path->jointype));
|
||||
}
|
||||
}
|
||||
@@ -1334,21 +1208,9 @@ create_nestloop_plan(Query *root,
|
||||
|
||||
if (innerpath->isjoininner)
|
||||
{
|
||||
List *bitmapquals;
|
||||
List *bitmapclauses;
|
||||
ListCell *l;
|
||||
|
||||
bitmapquals = create_bitmap_qual(innerpath->bitmapqual);
|
||||
|
||||
/* must convert qual list to restrictinfos ... painful ... */
|
||||
bitmapclauses = NIL;
|
||||
foreach(l, bitmapquals)
|
||||
{
|
||||
bitmapclauses = lappend(bitmapclauses,
|
||||
make_restrictinfo((Expr *) lfirst(l),
|
||||
true, true));
|
||||
}
|
||||
|
||||
bitmapclauses = create_bitmap_restriction(innerpath->bitmapqual);
|
||||
joinrestrictclauses =
|
||||
select_nonredundant_join_clauses(root,
|
||||
joinrestrictclauses,
|
||||
@@ -1542,95 +1404,54 @@ create_hashjoin_plan(Query *root,
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* fix_indxqual_references
|
||||
* fix_indexqual_references
|
||||
* Adjust indexqual clauses to the form the executor's indexqual
|
||||
* machinery needs, and check for recheckable (lossy) index conditions.
|
||||
*
|
||||
* We have four tasks here:
|
||||
* We have five tasks here:
|
||||
* * Remove RestrictInfo nodes from the input clauses.
|
||||
* * Index keys must be represented by Var nodes with varattno set to the
|
||||
* index's attribute number, not the attribute number in the original rel.
|
||||
* * If the index key is on the right, commute the clause to put it on the
|
||||
* left. (Someday the executor might not need this, but for now it does.)
|
||||
* * We must construct lists of operator strategy numbers, subtypes, and
|
||||
* recheck (lossy-operator) flags for the top-level operators of each
|
||||
* index clause.
|
||||
* left.
|
||||
* * We must construct lists of operator strategy numbers and subtypes
|
||||
* for the top-level operators of each index clause.
|
||||
* * We must detect any lossy index operators. The API is that we return
|
||||
* a list of the input clauses whose operators are NOT lossy.
|
||||
*
|
||||
* Both the input list and the "fixed" output list have the form of lists of
|
||||
* sublists of qual clauses --- the top-level list has one entry for each
|
||||
* indexscan to be performed. The semantics are OR-of-ANDs. Note however
|
||||
* that the input list contains RestrictInfos, while the output list doesn't.
|
||||
*
|
||||
* fixed_indexquals receives a modified copy of the indexqual list --- the
|
||||
* fixed_indexquals receives a modified copy of the indexquals list --- the
|
||||
* original is not changed. Note also that the copy shares no substructure
|
||||
* with the original; this is needed in case there is a subplan in it (we need
|
||||
* two separate copies of the subplan tree, or things will go awry).
|
||||
*
|
||||
* indxstrategy receives a list of integer sublists of strategy numbers.
|
||||
* indxsubtype receives a list of OID sublists of strategy subtypes.
|
||||
* indxlossy receives a list of integer sublists of lossy-operator booleans.
|
||||
* nonlossy_indexquals receives a list of the original input clauses (with
|
||||
* RestrictInfos) that contain non-lossy operators.
|
||||
*
|
||||
* indexstrategy receives an integer list of strategy numbers.
|
||||
* indexsubtype receives an OID list of strategy subtypes.
|
||||
*/
|
||||
static void
|
||||
fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals,
|
||||
List **indxstrategy,
|
||||
List **indxsubtype,
|
||||
List **indxlossy)
|
||||
{
|
||||
List *index_info = index_path->indexinfo;
|
||||
ListCell *iq,
|
||||
*ii;
|
||||
|
||||
*fixed_indexquals = NIL;
|
||||
*indxstrategy = NIL;
|
||||
*indxsubtype = NIL;
|
||||
*indxlossy = NIL;
|
||||
forboth(iq, indexquals, ii, index_info)
|
||||
{
|
||||
List *indexqual = (List *) lfirst(iq);
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(ii);
|
||||
List *fixed_qual;
|
||||
List *strategy;
|
||||
List *subtype;
|
||||
List *lossy;
|
||||
|
||||
fix_indxqual_sublist(indexqual, index,
|
||||
&fixed_qual, &strategy, &subtype, &lossy);
|
||||
*fixed_indexquals = lappend(*fixed_indexquals, fixed_qual);
|
||||
*indxstrategy = lappend(*indxstrategy, strategy);
|
||||
*indxsubtype = lappend(*indxsubtype, subtype);
|
||||
*indxlossy = lappend(*indxlossy, lossy);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix the sublist of indexquals to be used in a particular scan.
|
||||
*
|
||||
* For each qual clause, commute if needed to put the indexkey operand on the
|
||||
* left, and then fix its varattno. (We do not need to change the other side
|
||||
* of the clause.) Then determine the operator's strategy number and subtype
|
||||
* number, and check for lossy index behavior.
|
||||
*
|
||||
* Returns four lists:
|
||||
* the list of fixed indexquals
|
||||
* the integer list of strategy numbers
|
||||
* the OID list of strategy subtypes
|
||||
* the integer list of lossiness flags (1/0)
|
||||
*/
|
||||
static void
|
||||
fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
|
||||
List **fixed_quals,
|
||||
List **strategy,
|
||||
List **subtype,
|
||||
List **lossy)
|
||||
fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **fixed_indexquals,
|
||||
List **nonlossy_indexquals,
|
||||
List **indexstrategy,
|
||||
List **indexsubtype)
|
||||
{
|
||||
IndexOptInfo *index = index_path->indexinfo;
|
||||
ListCell *l;
|
||||
|
||||
*fixed_quals = NIL;
|
||||
*strategy = NIL;
|
||||
*subtype = NIL;
|
||||
*lossy = NIL;
|
||||
foreach(l, indexqual)
|
||||
*fixed_indexquals = NIL;
|
||||
*nonlossy_indexquals = NIL;
|
||||
*indexstrategy = NIL;
|
||||
*indexsubtype = NIL;
|
||||
|
||||
/*
|
||||
* For each qual clause, commute if needed to put the indexkey operand on
|
||||
* the left, and then fix its varattno. (We do not need to change the
|
||||
* other side of the clause.) Then determine the operator's strategy
|
||||
* number and subtype number, and check for lossy index behavior.
|
||||
*/
|
||||
foreach(l, indexquals)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
|
||||
OpExpr *clause;
|
||||
@@ -1642,7 +1463,8 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
|
||||
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
clause = (OpExpr *) rinfo->clause;
|
||||
if (!IsA(clause, OpExpr) ||list_length(clause->args) != 2)
|
||||
if (!IsA(clause, OpExpr) ||
|
||||
list_length(clause->args) != 2)
|
||||
elog(ERROR, "indexqual clause is not binary opclause");
|
||||
|
||||
/*
|
||||
@@ -1666,11 +1488,12 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
|
||||
* Now, determine which index attribute this is, change the
|
||||
* indexkey operand as needed, and get the index opclass.
|
||||
*/
|
||||
linitial(newclause->args) = fix_indxqual_operand(linitial(newclause->args),
|
||||
index,
|
||||
&opclass);
|
||||
linitial(newclause->args) =
|
||||
fix_indexqual_operand(linitial(newclause->args),
|
||||
index,
|
||||
&opclass);
|
||||
|
||||
*fixed_quals = lappend(*fixed_quals, newclause);
|
||||
*fixed_indexquals = lappend(*fixed_indexquals, newclause);
|
||||
|
||||
/*
|
||||
* Look up the (possibly commuted) operator in the operator class
|
||||
@@ -1681,14 +1504,17 @@ fix_indxqual_sublist(List *indexqual, IndexOptInfo *index,
|
||||
get_op_opclass_properties(newclause->opno, opclass,
|
||||
&stratno, &stratsubtype, &recheck);
|
||||
|
||||
*strategy = lappend_int(*strategy, stratno);
|
||||
*subtype = lappend_oid(*subtype, stratsubtype);
|
||||
*lossy = lappend_int(*lossy, (int) recheck);
|
||||
*indexstrategy = lappend_int(*indexstrategy, stratno);
|
||||
*indexsubtype = lappend_oid(*indexsubtype, stratsubtype);
|
||||
|
||||
/* If it's not lossy, add to nonlossy_indexquals */
|
||||
if (!recheck)
|
||||
*nonlossy_indexquals = lappend(*nonlossy_indexquals, rinfo);
|
||||
}
|
||||
}
|
||||
|
||||
static Node *
|
||||
fix_indxqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
{
|
||||
/*
|
||||
* We represent index keys by Var nodes having the varno of the base
|
||||
@@ -1923,12 +1749,11 @@ static IndexScan *
|
||||
make_indexscan(List *qptlist,
|
||||
List *qpqual,
|
||||
Index scanrelid,
|
||||
List *indxid,
|
||||
List *indxqual,
|
||||
List *indxqualorig,
|
||||
List *indxstrategy,
|
||||
List *indxsubtype,
|
||||
List *indxlossy,
|
||||
Oid indexid,
|
||||
List *indexqual,
|
||||
List *indexqualorig,
|
||||
List *indexstrategy,
|
||||
List *indexsubtype,
|
||||
ScanDirection indexscandir)
|
||||
{
|
||||
IndexScan *node = makeNode(IndexScan);
|
||||
@@ -1940,24 +1765,23 @@ make_indexscan(List *qptlist,
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->indxid = indxid;
|
||||
node->indxqual = indxqual;
|
||||
node->indxqualorig = indxqualorig;
|
||||
node->indxstrategy = indxstrategy;
|
||||
node->indxsubtype = indxsubtype;
|
||||
node->indxlossy = indxlossy;
|
||||
node->indxorderdir = indexscandir;
|
||||
node->indexid = indexid;
|
||||
node->indexqual = indexqual;
|
||||
node->indexqualorig = indexqualorig;
|
||||
node->indexstrategy = indexstrategy;
|
||||
node->indexsubtype = indexsubtype;
|
||||
node->indexorderdir = indexscandir;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static BitmapIndexScan *
|
||||
make_bitmap_indexscan(Index scanrelid,
|
||||
Oid indxid,
|
||||
List *indxqual,
|
||||
List *indxqualorig,
|
||||
List *indxstrategy,
|
||||
List *indxsubtype)
|
||||
Oid indexid,
|
||||
List *indexqual,
|
||||
List *indexqualorig,
|
||||
List *indexstrategy,
|
||||
List *indexsubtype)
|
||||
{
|
||||
BitmapIndexScan *node = makeNode(BitmapIndexScan);
|
||||
Plan *plan = &node->scan.plan;
|
||||
@@ -1968,11 +1792,11 @@ make_bitmap_indexscan(Index scanrelid,
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->indxid = indxid;
|
||||
node->indxqual = indxqual;
|
||||
node->indxqualorig = indxqualorig;
|
||||
node->indxstrategy = indxstrategy;
|
||||
node->indxsubtype = indxsubtype;
|
||||
node->indexid = indexid;
|
||||
node->indexqual = indexqual;
|
||||
node->indexqualorig = indexqualorig;
|
||||
node->indexstrategy = indexstrategy;
|
||||
node->indexsubtype = indexsubtype;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.108 2005/04/22 21:58:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.109 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -107,18 +107,18 @@ set_plan_references(Plan *plan, List *rtable)
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
fix_expr_references(plan,
|
||||
(Node *) ((IndexScan *) plan)->indxqual);
|
||||
(Node *) ((IndexScan *) plan)->indexqual);
|
||||
fix_expr_references(plan,
|
||||
(Node *) ((IndexScan *) plan)->indxqualorig);
|
||||
(Node *) ((IndexScan *) plan)->indexqualorig);
|
||||
break;
|
||||
case T_BitmapIndexScan:
|
||||
/* no need to fix targetlist and qual */
|
||||
Assert(plan->targetlist == NIL);
|
||||
Assert(plan->qual == NIL);
|
||||
fix_expr_references(plan,
|
||||
(Node *) ((BitmapIndexScan *) plan)->indxqual);
|
||||
(Node *) ((BitmapIndexScan *) plan)->indexqual);
|
||||
fix_expr_references(plan,
|
||||
(Node *) ((BitmapIndexScan *) plan)->indxqualorig);
|
||||
(Node *) ((BitmapIndexScan *) plan)->indexqualorig);
|
||||
break;
|
||||
case T_BitmapHeapScan:
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
@@ -422,31 +422,31 @@ set_inner_join_references(Plan *inner_plan,
|
||||
* var nodes to refer to the outer side of the join.
|
||||
*/
|
||||
IndexScan *innerscan = (IndexScan *) inner_plan;
|
||||
List *indxqualorig = innerscan->indxqualorig;
|
||||
List *indexqualorig = innerscan->indexqualorig;
|
||||
|
||||
/* No work needed if indxqual refers only to its own rel... */
|
||||
if (NumRelids((Node *) indxqualorig) > 1)
|
||||
/* No work needed if indexqual refers only to its own rel... */
|
||||
if (NumRelids((Node *) indexqualorig) > 1)
|
||||
{
|
||||
Index innerrel = innerscan->scan.scanrelid;
|
||||
|
||||
/* only refs to outer vars get changed in the inner qual */
|
||||
innerscan->indxqualorig = join_references(indxqualorig,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indxqual = join_references(innerscan->indxqual,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indexqualorig = join_references(indexqualorig,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indexqual = join_references(innerscan->indexqual,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
|
||||
/*
|
||||
* We must fix the inner qpqual too, if it has join
|
||||
* clauses (this could happen if special operators are
|
||||
* involved: some indxquals may get rechecked as qpquals).
|
||||
* involved: some indexquals may get rechecked as qpquals).
|
||||
*/
|
||||
if (NumRelids((Node *) inner_plan->qual) > 1)
|
||||
inner_plan->qual = join_references(inner_plan->qual,
|
||||
@@ -463,26 +463,26 @@ set_inner_join_references(Plan *inner_plan,
|
||||
* Same, but index is being used within a bitmap plan.
|
||||
*/
|
||||
BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
|
||||
List *indxqualorig = innerscan->indxqualorig;
|
||||
List *indexqualorig = innerscan->indexqualorig;
|
||||
|
||||
/* No work needed if indxqual refers only to its own rel... */
|
||||
if (NumRelids((Node *) indxqualorig) > 1)
|
||||
/* No work needed if indexqual refers only to its own rel... */
|
||||
if (NumRelids((Node *) indexqualorig) > 1)
|
||||
{
|
||||
Index innerrel = innerscan->scan.scanrelid;
|
||||
|
||||
/* only refs to outer vars get changed in the inner qual */
|
||||
innerscan->indxqualorig = join_references(indxqualorig,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indxqual = join_references(innerscan->indxqual,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indexqualorig = join_references(indexqualorig,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
innerscan->indexqual = join_references(innerscan->indexqual,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel,
|
||||
tlists_have_non_vars);
|
||||
/* no need to fix inner qpqual */
|
||||
Assert(inner_plan->qual == NIL);
|
||||
}
|
||||
@@ -512,7 +512,7 @@ set_inner_join_references(Plan *inner_plan,
|
||||
/*
|
||||
* We must fix the inner qpqual too, if it has join
|
||||
* clauses (this could happen if special operators are
|
||||
* involved: some indxquals may get rechecked as qpquals).
|
||||
* involved: some indexquals may get rechecked as qpquals).
|
||||
*/
|
||||
if (NumRelids((Node *) inner_plan->qual) > 1)
|
||||
inner_plan->qual = join_references(inner_plan->qual,
|
||||
|
||||
@@ -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.97 2005/04/19 22:35:16 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.98 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1028,21 +1028,21 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
|
||||
finalize_primnode((Node *) ((IndexScan *) plan)->indexqual,
|
||||
&context);
|
||||
|
||||
/*
|
||||
* we need not look at indxqualorig, since it will have the
|
||||
* same param references as indxqual.
|
||||
* we need not look at indexqualorig, since it will have the
|
||||
* same param references as indexqual.
|
||||
*/
|
||||
break;
|
||||
|
||||
case T_BitmapIndexScan:
|
||||
finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indxqual,
|
||||
finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual,
|
||||
&context);
|
||||
/*
|
||||
* we need not look at indxqualorig, since it will have the
|
||||
* same param references as indxqual.
|
||||
* we need not look at indexqualorig, since it will have the
|
||||
* same param references as indexqual.
|
||||
*/
|
||||
break;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.119 2005/04/22 21:58:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.120 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -475,13 +475,10 @@ create_index_path(Query *root,
|
||||
/* Flatten the clause-groups list to produce indexclauses list */
|
||||
allclauses = flatten_clausegroups_list(clause_groups);
|
||||
|
||||
/*
|
||||
* We are making a pathnode for a single-scan indexscan; therefore,
|
||||
* indexinfo etc should be single-element lists.
|
||||
*/
|
||||
pathnode->indexinfo = list_make1(index);
|
||||
pathnode->indexclauses = list_make1(allclauses);
|
||||
pathnode->indexquals = list_make1(indexquals);
|
||||
/* Fill in the pathnode */
|
||||
pathnode->indexinfo = index;
|
||||
pathnode->indexclauses = allclauses;
|
||||
pathnode->indexquals = indexquals;
|
||||
|
||||
pathnode->isjoininner = isjoininner;
|
||||
pathnode->indexscandir = indexscandir;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.33 2005/04/22 21:58:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.34 2005/04/25 01:30:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -65,55 +65,10 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere)
|
||||
is_pushed_down, valid_everywhere);
|
||||
}
|
||||
|
||||
/*
|
||||
* make_restrictinfo_from_indexclauses
|
||||
*
|
||||
* Given an indexclauses structure, convert to ordinary expression format
|
||||
* and build RestrictInfo node(s).
|
||||
*
|
||||
* The result is a List since we might need to return multiple RestrictInfos.
|
||||
*
|
||||
* This could be done as make_restrictinfo(make_expr_from_indexclauses()),
|
||||
* but if we did it that way then we would strip the original RestrictInfo
|
||||
* nodes from the index clauses and be forced to build new ones. It's better
|
||||
* to have a specialized routine that allows sharing of RestrictInfos.
|
||||
*/
|
||||
List *
|
||||
make_restrictinfo_from_indexclauses(List *indexclauses,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere)
|
||||
{
|
||||
List *withris = NIL;
|
||||
List *withoutris = NIL;
|
||||
ListCell *orlist;
|
||||
|
||||
/* Empty list probably can't happen, but here's what to do */
|
||||
if (indexclauses == NIL)
|
||||
return NIL;
|
||||
/* If single indexscan, just return the ANDed clauses */
|
||||
if (list_length(indexclauses) == 1)
|
||||
return (List *) linitial(indexclauses);
|
||||
/* Else we need an OR RestrictInfo structure */
|
||||
foreach(orlist, indexclauses)
|
||||
{
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
|
||||
/* Create AND subclause with RestrictInfos */
|
||||
withris = lappend(withris, make_ands_explicit(andlist));
|
||||
/* And one without */
|
||||
andlist = get_actual_clauses(andlist);
|
||||
withoutris = lappend(withoutris, make_ands_explicit(andlist));
|
||||
}
|
||||
return list_make1(make_restrictinfo_internal(make_orclause(withoutris),
|
||||
make_orclause(withris),
|
||||
is_pushed_down,
|
||||
valid_everywhere));
|
||||
}
|
||||
|
||||
/*
|
||||
* make_restrictinfo_internal
|
||||
*
|
||||
* Common code for the above two entry points.
|
||||
* Common code for the main entry point and the recursive cases.
|
||||
*/
|
||||
static RestrictInfo *
|
||||
make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
|
||||
Reference in New Issue
Block a user