*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/list.c,v 1.64 2005/03/17 05:47:01 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/list.c,v 1.65 2005/07/28 20:26:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* The returned list is newly-allocated, although the content of the
* cells is the same (i.e. any pointed-to objects are not copied).
*
- * NB: Bizarrely, this function will NOT remove any duplicates that
- * are present in list1 (so it is not really a union at all!). Also,
- * this function could probably be implemented a lot faster if it is a
+ * NB: this function will NOT remove any duplicates that are present
+ * in list1 (so it only performs a "union" if list1 is known unique to
+ * start with). Also, if you are about to write "x = list_union(x, y)"
+ * you probably want to use list_concat_unique() instead to avoid wasting
+ * the list cells of the old x list.
+ *
+ * This function could probably be implemented a lot faster if it is a
* performance bottleneck.
*/
List *
return result;
}
-/* Free all storage in a list, and optionally the pointed-to elements */
+/*
+ * Append datum to list, but only if it isn't already in the list.
+ *
+ * Whether an element is already a member of the list is determined
+ * via equal().
+ */
+List *
+list_append_unique(List *list, void *datum)
+{
+ if (list_member(list, datum))
+ return list;
+ else
+ return lappend(list, datum);
+}
+
+/*
+ * This variant of list_append_unique() determines list membership via
+ * simple pointer equality.
+ */
+List *
+list_append_unique_ptr(List *list, void *datum)
+{
+ if (list_member_ptr(list, datum))
+ return list;
+ else
+ return lappend(list, datum);
+}
+
+/*
+ * This variant of list_append_unique() operates upon lists of integers.
+ */
+List *
+list_append_unique_int(List *list, int datum)
+{
+ if (list_member_int(list, datum))
+ return list;
+ else
+ return lappend_int(list, datum);
+}
+
+/*
+ * This variant of list_append_unique() operates upon lists of OIDs.
+ */
+List *
+list_append_unique_oid(List *list, Oid datum)
+{
+ if (list_member_oid(list, datum))
+ return list;
+ else
+ return lappend_oid(list, datum);
+}
+
+/*
+ * Append to list1 each member of list2 that isn't already in list1.
+ *
+ * Whether an element is already a member of the list is determined
+ * via equal().
+ *
+ * This is almost the same functionality as list_union(), but list1 is
+ * modified in-place rather than being copied. Note also that list2's cells
+ * are not inserted in list1, so the analogy to list_concat() isn't perfect.
+ */
+List *
+list_concat_unique(List *list1, List *list2)
+{
+ ListCell *cell;
+
+ Assert(IsPointerList(list1));
+ Assert(IsPointerList(list2));
+
+ foreach(cell, list2)
+ {
+ if (!list_member(list1, lfirst(cell)))
+ list1 = lappend(list1, lfirst(cell));
+ }
+
+ check_list_invariants(list1);
+ return list1;
+}
+
+/*
+ * This variant of list_concat_unique() determines list membership via
+ * simple pointer equality.
+ */
+List *
+list_concat_unique_ptr(List *list1, List *list2)
+{
+ ListCell *cell;
+
+ Assert(IsPointerList(list1));
+ Assert(IsPointerList(list2));
+
+ foreach(cell, list2)
+ {
+ if (!list_member_ptr(list1, lfirst(cell)))
+ list1 = lappend(list1, lfirst(cell));
+ }
+
+ check_list_invariants(list1);
+ return list1;
+}
+
+/*
+ * This variant of list_concat_unique() operates upon lists of integers.
+ */
+List *
+list_concat_unique_int(List *list1, List *list2)
+{
+ ListCell *cell;
+
+ Assert(IsIntegerList(list1));
+ Assert(IsIntegerList(list2));
+
+ foreach(cell, list2)
+ {
+ if (!list_member_int(list1, lfirst_int(cell)))
+ list1 = lappend_int(list1, lfirst_int(cell));
+ }
+
+ check_list_invariants(list1);
+ return list1;
+}
+
+/*
+ * This variant of list_concat_unique() operates upon lists of OIDs.
+ */
+List *
+list_concat_unique_oid(List *list1, List *list2)
+{
+ ListCell *cell;
+
+ Assert(IsOidList(list1));
+ Assert(IsOidList(list2));
+
+ foreach(cell, list2)
+ {
+ if (!list_member_oid(list1, lfirst_oid(cell)))
+ list1 = lappend_oid(list1, lfirst_oid(cell));
+ }
+
+ check_list_invariants(list1);
+ return list1;
+}
+
+/*
+ * Free all storage in a list, and optionally the pointed-to elements
+ */
static void
list_free_private(List *list, bool deep)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.186 2005/07/02 23:00:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.187 2005/07/28 20:26:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* subclause to any index on x alone, because such a Path would already have
* been generated at the upper level. So we could use an index on x,y,z
* or an index on x,y for the OR subclause, but not an index on just x.
+ * When dealing with a partial index, a match of the index predicate to
+ * one of the "current" clauses also makes the index usable.
*
* If istoplevel is true (indicating we are considering the top level of a
* rel's restriction clauses), we will include indexes in the result that
List *restrictclauses;
List *index_pathkeys;
List *useful_pathkeys;
+ bool useful_predicate;
+ bool found_clause;
bool index_is_ordered;
/*
* Otherwise, we have to test whether the added clauses are
* sufficient to imply the predicate. If so, we could use
* the index in the current context.
+ *
+ * We set useful_predicate to true iff the predicate was proven
+ * using the current set of clauses. This is needed to prevent
+ * matching a predOK index to an arm of an OR, which would be
+ * a legal but pointlessly inefficient plan. (A better plan will
+ * be generated by just scanning the predOK index alone, no OR.)
*/
- if (index->indpred != NIL && !index->predOK)
+ useful_predicate = false;
+ if (index->indpred != NIL)
{
- if (istoplevel)
- continue; /* no point in trying to prove it */
+ if (index->predOK)
+ {
+ if (istoplevel)
+ {
+ /* we know predicate was proven from these clauses */
+ useful_predicate = true;
+ }
+ }
+ else
+ {
+ if (istoplevel)
+ continue; /* no point in trying to prove it */
- /* Form all_clauses if not done already */
- if (all_clauses == NIL)
- all_clauses = list_concat(list_copy(clauses),
- outer_clauses);
+ /* Form all_clauses if not done already */
+ if (all_clauses == NIL)
+ all_clauses = list_concat(list_copy(clauses),
+ outer_clauses);
- if (!predicate_implied_by(index->indpred, all_clauses) ||
- predicate_implied_by(index->indpred, outer_clauses))
- continue;
+ if (!predicate_implied_by(index->indpred, all_clauses))
+ continue; /* can't use it at all */
+
+ if (!predicate_implied_by(index->indpred, outer_clauses))
+ useful_predicate = true;
+ }
}
/*
* 1. Match the index against the available restriction clauses.
+ * found_clause is set true only if at least one of the current
+ * clauses was used.
*/
restrictclauses = group_clauses_by_indexkey(index,
clauses,
outer_clauses,
- outer_relids);
+ outer_relids,
+ &found_clause);
+
+ /*
+ * Not all index AMs support scans with no restriction clauses.
+ * We can't generate a scan over an index with amoptionalkey = false
+ * unless there's at least one restriction clause.
+ */
+ if (restrictclauses == NIL && !index->amoptionalkey)
+ continue;
/*
* 2. Compute pathkeys describing index's ordering, if any, then
/*
* 3. Generate an indexscan path if there are relevant restriction
- * clauses OR the index ordering is potentially useful for later
- * merging or final output ordering.
- *
- * If there is a predicate, consider it anyway since the index
- * predicate has already been found to match the query. The
- * selectivity of the predicate might alone make the index useful.
- *
- * Note: not all index AMs support scans with no restriction clauses.
- * We can't generate a scan over an index with amoptionalkey = false
- * unless there's at least one restriction clause.
+ * clauses in the current clauses, OR the index ordering is
+ * potentially useful for later merging or final output ordering,
+ * OR the index has a predicate that was proven by the current
+ * clauses.
*/
- if (restrictclauses != NIL ||
- (index->amoptionalkey &&
- (useful_pathkeys != NIL || index->indpred != NIL)))
+ if (found_clause || useful_pathkeys != NIL || useful_predicate)
{
ipath = create_index_path(root, index,
restrictclauses,
* with one index key (in no particular order); the top list is ordered by
* index key. (This is depended on by expand_indexqual_conditions().)
*
- * As explained in the comments for find_usable_indexes(), we can use
- * clauses from either of the given lists, but the result is required to
- * use at least one clause from the "current clauses" list. We return
- * NIL if we don't find any such clause.
+ * We can use clauses from either the current clauses or outer_clauses lists,
+ * but *found_clause is set TRUE only if we used at least one clause from
+ * the "current clauses" list. See find_usable_indexes() for motivation.
*
* outer_relids determines what Vars will be allowed on the other side
* of a possible index qual; see match_clause_to_indexcol().
* Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4))
* if we find that clauses C1 and C2 use column A, clauses C3 and C4 use
* column C, and no clauses use column B.
+ *
+ * Note: in some circumstances we may find the same RestrictInfos coming
+ * from multiple places. Defend against redundant outputs by using
+ * list_append_unique_ptr (pointer equality should be good enough).
*/
List *
group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses,
- Relids outer_relids)
+ Relids outer_relids,
+ bool *found_clause)
{
List *clausegroup_list = NIL;
- bool found_clause = false;
+ bool found_outer_clause = false;
int indexcol = 0;
Oid *classes = index->classlist;
- if (clauses == NIL)
+ *found_clause = false; /* default result */
+
+ if (clauses == NIL && outer_clauses == NIL)
return NIL; /* cannot succeed */
do
rinfo,
outer_relids))
{
- clausegroup = lappend(clausegroup, rinfo);
- found_clause = true;
+ clausegroup = list_append_unique_ptr(clausegroup, rinfo);
+ *found_clause = true;
}
}
curClass,
rinfo,
outer_relids))
- clausegroup = lappend(clausegroup, rinfo);
+ {
+ clausegroup = list_append_unique_ptr(clausegroup, rinfo);
+ found_outer_clause = true;
+ }
}
/*
} while (!DoneMatchingIndexKeys(classes));
- if (!found_clause)
- return NIL;
+ if (!*found_clause && !found_outer_clause)
+ return NIL; /* no indexable clauses anywhere */
return clausegroup_list;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.73 2005/07/02 23:00:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.74 2005/07/28 20:26:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return false;
/*
- * Convert the path's 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.
+ * We include any partial-index predicates so as to get a reasonable
+ * representation of what the path is actually scanning.
*/
- newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, true);
- Assert(list_length(newrinfos) == 1);
+ newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath,
+ true, true);
+
+ /* It's possible we get back something other than a single OR clause */
+ if (list_length(newrinfos) != 1)
+ return false;
or_rinfo = (RestrictInfo *) linitial(newrinfos);
Assert(IsA(or_rinfo, RestrictInfo));
+ if (!restriction_is_or_clause(or_rinfo))
+ return false;
+ /*
+ * OK, add it to the rel's restriction list.
+ */
rel->baserestrictinfo = list_concat(rel->baserestrictinfo, newrinfos);
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.195 2005/07/23 21:05:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.196 2005/07/28 20:26:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (best_path->isjoininner)
{
- scan_clauses = list_union(scan_clauses, bitmapqualorig);
+ scan_clauses = list_concat_unique(scan_clauses, bitmapqualorig);
}
/*
* (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.
+ *
+ * Note: if you find yourself changing this, you probably need to change
+ * make_restrictinfo_from_bitmapqual too.
*/
static Plan *
create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List *subindexquals = NIL;
ListCell *l;
+ /*
+ * There may well be redundant quals among the subplans, since a
+ * top-level WHERE qual might have gotten used to form several
+ * different index quals. We don't try exceedingly hard to
+ * eliminate redundancies, but we do eliminate obvious duplicates
+ * by using list_concat_unique.
+ */
foreach(l, apath->bitmapquals)
{
Plan *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);
+ subquals = list_concat_unique(subquals, subqual);
+ subindexquals = list_concat_unique(subindexquals, subindexqual);
}
plan = (Plan *) make_bitmap_and(subplans);
plan->startup_cost = apath->path.startup_cost;
List *subplans = NIL;
List *subquals = NIL;
List *subindexquals = NIL;
+ bool const_true_subqual = false;
+ bool const_true_subindexqual = false;
ListCell *l;
+ /*
+ * Here, we detect both obvious redundancies and qual-free subplans.
+ * A qual-free subplan would cause us to generate "... OR true ..."
+ * which we may as well reduce to just "true".
+ */
foreach(l, opath->bitmapquals)
{
Plan *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));
+ if (subqual == NIL)
+ const_true_subqual = true;
+ else if (!const_true_subqual)
+ subquals = list_append_unique(subquals,
+ make_ands_explicit(subqual));
+ if (subindexqual == NIL)
+ const_true_subindexqual = true;
+ else if (!const_true_subindexqual)
+ subindexquals = list_append_unique(subindexquals,
+ make_ands_explicit(subindexqual));
}
plan = (Plan *) make_bitmap_or(subplans);
plan->startup_cost = opath->path.startup_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));
+ /*
+ * If there were constant-TRUE subquals, the OR reduces to constant
+ * TRUE. Also, avoid generating one-element ORs, which could happen
+ * due to redundancy elimination.
+ */
+ if (const_true_subqual)
+ *qual = NIL;
+ else if (list_length(subquals) <= 1)
+ *qual = subquals;
+ else
+ *qual = list_make1(make_orclause(subquals));
+ if (const_true_subindexqual)
+ *indexqual = NIL;
+ else if (list_length(subindexquals) <= 1)
+ *indexqual = subindexquals;
+ else
+ *indexqual = list_make1(make_orclause(subindexquals));
}
else if (IsA(bitmapqual, IndexPath))
{
{
/*
* Same deal for bitmapped index scans.
+ *
+ * Note: both here and above, we ignore any implicit index restrictions
+ * associated with the use of partial indexes. This is OK because
+ * we're only trying to prove we can dispense with some join quals;
+ * failing to prove that doesn't result in an incorrect plan. It is
+ * the right way to proceed because adding more quals to the stuff
+ * we got from the original query would just make it harder to detect
+ * duplication.
*/
BitmapHeapPath *innerpath = (BitmapHeapPath *) best_path->innerjoinpath;
List *bitmapclauses;
bitmapclauses =
- make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true);
+ make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
+ true,
+ false);
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.6 2005/07/23 21:05:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.7 2005/07/28 20:26:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
List *restrictclauses;
IndexPath *new_path;
Cost new_cost;
+ bool found_clause;
/* Ignore non-btree indexes */
if (index->relam != BTREE_AM_OID)
restrictclauses = group_clauses_by_indexkey(index,
index->rel->baserestrictinfo,
NIL,
- NULL);
+ NULL,
+ &found_clause);
if (list_length(restrictclauses) < indexcol)
continue; /* definitely haven't got enough */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.38 2005/07/02 23:00:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.39 2005/07/28 20:26:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
+#include "optimizer/predtest.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/var.h"
* RestrictInfo node(s) equivalent to the condition represented by the
* indexclauses of the Path structure.
*
- * The result is a List since we might need to return multiple RestrictInfos.
+ * The result is a List (effectively, implicit-AND representation) of
+ * RestrictInfos.
+ *
+ * If include_predicates is true, we add any partial index predicates to
+ * the explicit index quals. When this is not true, we return a condition
+ * that might be weaker than the actual scan represents.
*
* To do this through the normal make_restrictinfo() API, callers would have
* to strip off the RestrictInfo nodes present in the indexclauses lists, and
* then make_restrictinfo() would have to build new ones. It's better to have
* a specialized routine to allow sharing of RestrictInfos.
+ *
+ * The qual manipulations here are much the same as in create_bitmap_subplan;
+ * keep the two routines in sync!
*/
List *
-make_restrictinfo_from_bitmapqual(Path *bitmapqual, bool is_pushed_down)
+make_restrictinfo_from_bitmapqual(Path *bitmapqual,
+ bool is_pushed_down,
+ bool include_predicates)
{
List *result;
+ ListCell *l;
if (IsA(bitmapqual, BitmapAndPath))
{
BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;
- ListCell *l;
+ /*
+ * There may well be redundant quals among the subplans, since a
+ * top-level WHERE qual might have gotten used to form several
+ * different index quals. We don't try exceedingly hard to
+ * eliminate redundancies, but we do eliminate obvious duplicates
+ * by using list_concat_unique.
+ */
result = NIL;
foreach(l, apath->bitmapquals)
{
List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
- is_pushed_down);
- result = list_concat(result, sublist);
+ is_pushed_down,
+ include_predicates);
+ result = list_concat_unique(result, sublist);
}
}
else if (IsA(bitmapqual, BitmapOrPath))
BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;
List *withris = NIL;
List *withoutris = NIL;
- ListCell *l;
+ /*
+ * Here, we detect both obvious redundancies and qual-free subplans.
+ * A qual-free subplan would cause us to generate "... OR true ..."
+ * which we may as well reduce to just "true".
+ */
foreach(l, opath->bitmapquals)
{
List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
- is_pushed_down);
+ is_pushed_down,
+ include_predicates);
if (sublist == NIL)
{
- /* constant TRUE input yields constant TRUE OR result */
- /* (though this probably cannot happen) */
+ /*
+ * If we find a qual-less subscan, it represents a constant
+ * TRUE, and hence the OR result is also constant TRUE, so
+ * we can stop here.
+ */
return NIL;
}
/* Create AND subclause with RestrictInfos */
- withris = lappend(withris, make_ands_explicit(sublist));
+ withris = list_append_unique(withris,
+ make_ands_explicit(sublist));
/* And one without */
sublist = get_actual_clauses(sublist);
- withoutris = lappend(withoutris, make_ands_explicit(sublist));
+ withoutris = list_append_unique(withoutris,
+ make_ands_explicit(sublist));
+ }
+
+ /*
+ * Avoid generating one-element ORs, which could happen
+ * due to redundancy elimination.
+ */
+ if (list_length(withris) <= 1)
+ result = withris;
+ else
+ {
+ /* Here's the magic part not available to outside callers */
+ result =
+ list_make1(make_restrictinfo_internal(make_orclause(withoutris),
+ make_orclause(withris),
+ is_pushed_down,
+ NULL));
}
- /* Here's the magic part not available to outside callers */
- result =
- list_make1(make_restrictinfo_internal(make_orclause(withoutris),
- make_orclause(withris),
- is_pushed_down,
- NULL));
}
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
result = list_copy(ipath->indexclauses);
+ if (include_predicates && ipath->indexinfo->indpred != NIL)
+ {
+ foreach(l, ipath->indexinfo->indpred)
+ {
+ Expr *pred = (Expr *) lfirst(l);
+
+ /*
+ * We know that the index predicate must have been implied
+ * by the query condition as a whole, but it may or may not
+ * be implied by the conditions that got pushed into the
+ * bitmapqual. Avoid generating redundant conditions.
+ */
+ if (!predicate_implied_by(list_make1(pred), result))
+ result = lappend(result,
+ make_restrictinfo(pred,
+ is_pushed_down,
+ NULL));
+ }
+ }
}
else
{
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/pg_list.h,v 1.51 2004/12/31 22:03:34 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/pg_list.h,v 1.52 2005/07/28 20:26:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *list_difference_int(List *list1, List *list2);
extern List *list_difference_oid(List *list1, List *list2);
+extern List *list_append_unique(List *list, void *datum);
+extern List *list_append_unique_ptr(List *list, void *datum);
+extern List *list_append_unique_int(List *list, int datum);
+extern List *list_append_unique_oid(List *list, Oid datum);
+
+extern List *list_concat_unique(List *list1, List *list2);
+extern List *list_concat_unique_ptr(List *list1, List *list2);
+extern List *list_concat_unique_int(List *list1, List *list2);
+extern List *list_concat_unique_oid(List *list1, List *list2);
+
extern void list_free(List *list);
extern void list_free_deep(List *list);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.85 2005/06/10 22:25:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.86 2005/07/28 20:26:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Relids outer_relids, JoinType jointype);
extern List *group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses,
- Relids outer_relids);
+ Relids outer_relids,
+ bool *found_clause);
extern bool match_index_to_operand(Node *operand, int indexcol,
IndexOptInfo *index);
extern List *expand_indexqual_conditions(IndexOptInfo *index,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.32 2005/07/02 23:00:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.33 2005/07/28 20:26:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool is_pushed_down,
Relids required_relids);
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
- bool is_pushed_down);
+ bool is_pushed_down,
+ bool include_predicates);
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern List *get_actual_clauses(List *restrictinfo_list);
extern void get_actual_join_clauses(List *restrictinfo_list,