Commit a31ad27f authored by Tom Lane's avatar Tom Lane

Simplify the planner's join clause management by storing join clauses

of a relation in a flat 'joininfo' list.  The former arrangement grouped
the join clauses according to the set of unjoined relids used in each;
however, profiling on test cases involving lots of joins proves that
that data structure is a net loss.  It takes more time to group the
join clauses together than is saved by avoiding duplicate tests later.
It doesn't help any that there are usually not more than one or two
clauses per group ...
parent c51815af
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.305 2005/06/05 22:32:54 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.306 2005/06/09 04:18:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1237,6 +1237,7 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1237,6 +1237,7 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_SCALAR_FIELD(valid_everywhere); COPY_SCALAR_FIELD(valid_everywhere);
COPY_SCALAR_FIELD(can_join); COPY_SCALAR_FIELD(can_join);
COPY_BITMAPSET_FIELD(clause_relids); COPY_BITMAPSET_FIELD(clause_relids);
COPY_BITMAPSET_FIELD(required_relids);
COPY_BITMAPSET_FIELD(left_relids); COPY_BITMAPSET_FIELD(left_relids);
COPY_BITMAPSET_FIELD(right_relids); COPY_BITMAPSET_FIELD(right_relids);
COPY_NODE_FIELD(orclause); COPY_NODE_FIELD(orclause);
...@@ -1262,20 +1263,6 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1262,20 +1263,6 @@ _copyRestrictInfo(RestrictInfo *from)
return newnode; return newnode;
} }
/*
* _copyJoinInfo
*/
static JoinInfo *
_copyJoinInfo(JoinInfo *from)
{
JoinInfo *newnode = makeNode(JoinInfo);
COPY_BITMAPSET_FIELD(unjoined_relids);
COPY_NODE_FIELD(jinfo_restrictinfo);
return newnode;
}
/* /*
* _copyInClauseInfo * _copyInClauseInfo
*/ */
...@@ -2857,9 +2844,6 @@ copyObject(void *from) ...@@ -2857,9 +2844,6 @@ copyObject(void *from)
case T_RestrictInfo: case T_RestrictInfo:
retval = _copyRestrictInfo(from); retval = _copyRestrictInfo(from);
break; break;
case T_JoinInfo:
retval = _copyJoinInfo(from);
break;
case T_InClauseInfo: case T_InClauseInfo:
retval = _copyInClauseInfo(from); retval = _copyInClauseInfo(from);
break; break;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.242 2005/06/05 22:32:54 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.243 2005/06/09 04:18:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -594,6 +594,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) ...@@ -594,6 +594,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
COMPARE_NODE_FIELD(clause); COMPARE_NODE_FIELD(clause);
COMPARE_SCALAR_FIELD(is_pushed_down); COMPARE_SCALAR_FIELD(is_pushed_down);
COMPARE_SCALAR_FIELD(valid_everywhere); COMPARE_SCALAR_FIELD(valid_everywhere);
COMPARE_BITMAPSET_FIELD(required_relids);
/* /*
* We ignore all the remaining fields, since they may not be set yet, * We ignore all the remaining fields, since they may not be set yet,
...@@ -603,15 +604,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) ...@@ -603,15 +604,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
return true; return true;
} }
static bool
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
{
COMPARE_BITMAPSET_FIELD(unjoined_relids);
COMPARE_NODE_FIELD(jinfo_restrictinfo);
return true;
}
static bool static bool
_equalInClauseInfo(InClauseInfo *a, InClauseInfo *b) _equalInClauseInfo(InClauseInfo *a, InClauseInfo *b)
{ {
...@@ -1915,9 +1907,6 @@ equal(void *a, void *b) ...@@ -1915,9 +1907,6 @@ equal(void *a, void *b)
case T_RestrictInfo: case T_RestrictInfo:
retval = _equalRestrictInfo(a, b); retval = _equalRestrictInfo(a, b);
break; break;
case T_JoinInfo:
retval = _equalJoinInfo(a, b);
break;
case T_InClauseInfo: case T_InClauseInfo:
retval = _equalInClauseInfo(a, b); retval = _equalInClauseInfo(a, b);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.254 2005/06/06 04:13:35 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.255 2005/06/09 04:18:58 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1227,6 +1227,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1227,6 +1227,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_BOOL_FIELD(valid_everywhere); WRITE_BOOL_FIELD(valid_everywhere);
WRITE_BOOL_FIELD(can_join); WRITE_BOOL_FIELD(can_join);
WRITE_BITMAPSET_FIELD(clause_relids); WRITE_BITMAPSET_FIELD(clause_relids);
WRITE_BITMAPSET_FIELD(required_relids);
WRITE_BITMAPSET_FIELD(left_relids); WRITE_BITMAPSET_FIELD(left_relids);
WRITE_BITMAPSET_FIELD(right_relids); WRITE_BITMAPSET_FIELD(right_relids);
WRITE_NODE_FIELD(orclause); WRITE_NODE_FIELD(orclause);
...@@ -1238,15 +1239,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1238,15 +1239,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_OID_FIELD(hashjoinoperator); WRITE_OID_FIELD(hashjoinoperator);
} }
static void
_outJoinInfo(StringInfo str, JoinInfo *node)
{
WRITE_NODE_TYPE("JOININFO");
WRITE_BITMAPSET_FIELD(unjoined_relids);
WRITE_NODE_FIELD(jinfo_restrictinfo);
}
static void static void
_outInnerIndexscanInfo(StringInfo str, InnerIndexscanInfo *node) _outInnerIndexscanInfo(StringInfo str, InnerIndexscanInfo *node)
{ {
...@@ -1989,9 +1981,6 @@ _outNode(StringInfo str, void *obj) ...@@ -1989,9 +1981,6 @@ _outNode(StringInfo str, void *obj)
case T_RestrictInfo: case T_RestrictInfo:
_outRestrictInfo(str, obj); _outRestrictInfo(str, obj);
break; break;
case T_JoinInfo:
_outJoinInfo(str, obj);
break;
case T_InnerIndexscanInfo: case T_InnerIndexscanInfo:
_outInnerIndexscanInfo(str, obj); _outInnerIndexscanInfo(str, obj);
break; break;
......
...@@ -75,11 +75,10 @@ way. All the Paths made for a given relation are placed in its ...@@ -75,11 +75,10 @@ way. All the Paths made for a given relation are placed in its
RelOptInfo.pathlist. (Actually, we discard Paths that are obviously RelOptInfo.pathlist. (Actually, we discard Paths that are obviously
inferior alternatives before they ever get into the pathlist --- what inferior alternatives before they ever get into the pathlist --- what
ends up in the pathlist is the cheapest way of generating each potentially ends up in the pathlist is the cheapest way of generating each potentially
useful sort ordering of the relation.) Also create RelOptInfo.joininfo useful sort ordering of the relation.) Also create a RelOptInfo.joininfo
nodes that list all the join clauses that involve this relation. For list including all the join clauses that involve this relation. For
example, the WHERE clause "tab1.col1 = tab2.col1" generates a JoinInfo example, the WHERE clause "tab1.col1 = tab2.col1" generates entries in
for tab1 listing tab2 as an unjoined relation, and also one for tab2 both tab1 and tab2's joininfo lists.
showing tab1 as an unjoined relation.
If we have only a single base relation in the query, we are done. If we have only a single base relation in the query, we are done.
Otherwise we have to figure out how to join the base relations into a Otherwise we have to figure out how to join the base relations into a
...@@ -252,7 +251,6 @@ RelOptInfo - a relation or joined relations ...@@ -252,7 +251,6 @@ RelOptInfo - a relation or joined relations
RestrictInfo - WHERE clauses, like "x = 3" or "y = z" RestrictInfo - WHERE clauses, like "x = 3" or "y = z"
(note the same structure is used for restriction and (note the same structure is used for restriction and
join clauses) join clauses)
JoinInfo - join clauses associated with a particular pair of relations
Path - every way to generate a RelOptInfo(sequential,index,joins) Path - every way to generate a RelOptInfo(sequential,index,joins)
SeqScan - a plain Path node with pathtype = T_SeqScan SeqScan - a plain Path node with pathtype = T_SeqScan
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.75 2005/06/08 23:02:04 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.76 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <math.h> #include <math.h>
#include "optimizer/geqo.h" #include "optimizer/geqo.h"
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -261,13 +262,8 @@ desirable_join(PlannerInfo *root, ...@@ -261,13 +262,8 @@ desirable_join(PlannerInfo *root,
/* /*
* Join if there is an applicable join clause. * Join if there is an applicable join clause.
*/ */
foreach(l, outer_rel->joininfo) if (have_relevant_joinclause(outer_rel, inner_rel))
{
JoinInfo *joininfo = (JoinInfo *) lfirst(l);
if (bms_is_subset(joininfo->unjoined_relids, inner_rel->relids))
return true; return true;
}
/* /*
* Join if the rels are members of the same IN sub-select. This is * Join if the rels are members of the same IN sub-select. This is
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.132 2005/06/06 04:13:35 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.133 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1048,14 +1048,10 @@ debug_print_rel(PlannerInfo *root, RelOptInfo *rel) ...@@ -1048,14 +1048,10 @@ debug_print_rel(PlannerInfo *root, RelOptInfo *rel)
printf("\n"); printf("\n");
} }
foreach(l, rel->joininfo) if (rel->joininfo)
{ {
JoinInfo *j = (JoinInfo *) lfirst(l); printf("\tjoininfo: ");
print_restrictclauses(root, rel->joininfo);
printf("\tjoininfo (");
print_relids(j->unjoined_relids);
printf("): ");
print_restrictclauses(root, j->jinfo_restrictinfo);
printf("\n"); printf("\n");
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.181 2005/06/05 22:32:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.182 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -71,8 +71,6 @@ static Oid indexable_operator(Expr *clause, Oid opclass, ...@@ -71,8 +71,6 @@ static Oid indexable_operator(Expr *clause, Oid opclass,
static bool pred_test_recurse(Node *clause, Node *predicate); static bool pred_test_recurse(Node *clause, Node *predicate);
static bool pred_test_simple_clause(Expr *predicate, Node *clause); static bool pred_test_simple_clause(Expr *predicate, Node *clause);
static Relids indexable_outerrelids(RelOptInfo *rel); static Relids indexable_outerrelids(RelOptInfo *rel);
static bool list_matches_any_index(List *clauses, RelOptInfo *rel,
Relids outer_relids);
static bool matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, static bool matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel,
Relids outer_relids); Relids outer_relids);
static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
...@@ -908,7 +906,7 @@ pred_test(List *predicate_list, List *restrictinfo_list) ...@@ -908,7 +906,7 @@ pred_test(List *predicate_list, List *restrictinfo_list)
* classes over equi-joined attributes (i.e., if it recognized that a * classes over equi-joined attributes (i.e., if it recognized that a
* qualification such as "where a.b=c.d and a.b=5" could make use of * qualification such as "where a.b=c.d and a.b=5" could make use of
* an index on c.d), then we could use that equivalence class info * an index on c.d), then we could use that equivalence class info
* here with joininfo_list to do more complete tests for the usability * here with joininfo lists to do more complete tests for the usability
* of a partial index. For now, the test only uses restriction * of a partial index. For now, the test only uses restriction
* clauses (those in restrictinfo_list). --Nels, Dec '92 * clauses (those in restrictinfo_list). --Nels, Dec '92
* *
...@@ -1550,69 +1548,62 @@ indexable_outerrelids(RelOptInfo *rel) ...@@ -1550,69 +1548,62 @@ indexable_outerrelids(RelOptInfo *rel)
Relids outer_relids = NULL; Relids outer_relids = NULL;
ListCell *l; ListCell *l;
/*
* Examine each joinclause in the joininfo list to see if it matches any
* key of any index. If so, add the clause's other rels to the result.
* (Note: we consider only actual participants, not extraneous rels
* possibly mentioned in required_relids.)
*/
foreach(l, rel->joininfo) foreach(l, rel->joininfo)
{ {
JoinInfo *joininfo = (JoinInfo *) lfirst(l); RestrictInfo *joininfo = (RestrictInfo *) lfirst(l);
Relids other_rels;
/* other_rels = bms_difference(joininfo->clause_relids, rel->relids);
* Examine each joinclause in the JoinInfo node's list to see if if (matches_any_index(joininfo, rel, other_rels))
* it matches any key of any index. If so, add the JoinInfo's outer_relids = bms_join(outer_relids, other_rels);
* otherrels to the result. We can skip examining other else
* joinclauses in the same list as soon as we find a match, since bms_free(other_rels);
* by definition they all have the same otherrels.
*/
if (list_matches_any_index(joininfo->jinfo_restrictinfo,
rel,
joininfo->unjoined_relids))
outer_relids = bms_add_members(outer_relids,
joininfo->unjoined_relids);
} }
return outer_relids; return outer_relids;
} }
/* /*
* list_matches_any_index * matches_any_index
* Workhorse for indexable_outerrelids: given a list of RestrictInfos, * Workhorse for indexable_outerrelids: see if a joinclause can be
* see if any of them match any index of the given rel. * matched to any index of the given rel.
*
* We define it like this so that we can recurse into OR subclauses.
*/ */
static bool static bool
list_matches_any_index(List *clauses, RelOptInfo *rel, Relids outer_relids) matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
{ {
ListCell *l; ListCell *l;
foreach(l, clauses)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
ListCell *j;
Assert(IsA(rinfo, RestrictInfo)); Assert(IsA(rinfo, RestrictInfo));
/* RestrictInfos that aren't ORs are easy */ if (restriction_is_or_clause(rinfo))
if (!restriction_is_or_clause(rinfo))
{ {
if (matches_any_index(rinfo, rel, outer_relids)) foreach(l, ((BoolExpr *) rinfo->orclause)->args)
return true;
continue;
}
foreach(j, ((BoolExpr *) rinfo->orclause)->args)
{ {
Node *orarg = (Node *) lfirst(j); Node *orarg = (Node *) lfirst(l);
/* OR arguments should be ANDs or sub-RestrictInfos */ /* OR arguments should be ANDs or sub-RestrictInfos */
if (and_clause(orarg)) if (and_clause(orarg))
{ {
List *andargs = ((BoolExpr *) orarg)->args; ListCell *j;
/* Recurse to examine AND items and sub-ORs */ /* Recurse to examine AND items and sub-ORs */
if (list_matches_any_index(andargs, rel, outer_relids)) foreach(j, ((BoolExpr *) orarg)->args)
{
RestrictInfo *arinfo = (RestrictInfo *) lfirst(j);
if (matches_any_index(arinfo, rel, outer_relids))
return true; return true;
} }
}
else else
{ {
/* Recurse to examine simple clause */
Assert(IsA(orarg, RestrictInfo)); Assert(IsA(orarg, RestrictInfo));
Assert(!restriction_is_or_clause((RestrictInfo *) orarg)); Assert(!restriction_is_or_clause((RestrictInfo *) orarg));
if (matches_any_index((RestrictInfo *) orarg, rel, if (matches_any_index((RestrictInfo *) orarg, rel,
...@@ -1620,20 +1611,9 @@ list_matches_any_index(List *clauses, RelOptInfo *rel, Relids outer_relids) ...@@ -1620,20 +1611,9 @@ list_matches_any_index(List *clauses, RelOptInfo *rel, Relids outer_relids)
return true; return true;
} }
} }
}
return false; return false;
} }
/*
* matches_any_index
* Workhorse for indexable_outerrelids: see if a simple joinclause can be
* matched to any index of the given rel.
*/
static bool
matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
{
ListCell *l;
/* Normal case for a simple restriction clause */ /* Normal case for a simple restriction clause */
foreach(l, rel->indexlist) foreach(l, rel->indexlist)
...@@ -1833,7 +1813,7 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, ...@@ -1833,7 +1813,7 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
{ {
List *clause_list = NIL; List *clause_list = NIL;
bool jfound = false; bool jfound = false;
int numsources; Relids join_relids;
ListCell *l; ListCell *l;
/* /*
...@@ -1854,46 +1834,33 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, ...@@ -1854,46 +1834,33 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
clause_list = lappend(clause_list, rinfo); clause_list = lappend(clause_list, rinfo);
} }
/* found anything in base restrict list? */
numsources = (clause_list != NIL) ? 1 : 0;
/* Look for joinclauses that are usable with given outer_relids */ /* Look for joinclauses that are usable with given outer_relids */
foreach(l, rel->joininfo) join_relids = bms_union(rel->relids, outer_relids);
{
JoinInfo *joininfo = (JoinInfo *) lfirst(l);
bool jfoundhere = false;
ListCell *j;
if (!bms_is_subset(joininfo->unjoined_relids, outer_relids)) foreach(l, rel->joininfo)
continue;
foreach(j, joininfo->jinfo_restrictinfo)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(j); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
/* Can't use pushed-down clauses in outer join */ /* Can't use pushed-down clauses in outer join */
if (isouterjoin && rinfo->is_pushed_down) if (isouterjoin && rinfo->is_pushed_down)
continue; continue;
if (!bms_is_subset(rinfo->required_relids, join_relids))
continue;
clause_list = lappend(clause_list, rinfo); clause_list = lappend(clause_list, rinfo);
if (!jfoundhere)
{
jfoundhere = true;
jfound = true; jfound = true;
numsources++;
}
}
} }
bms_free(join_relids);
/* if no join clause was matched then forget it, per comments above */ /* if no join clause was matched then forget it, per comments above */
if (!jfound) if (!jfound)
return NIL; return NIL;
/* /*
* If we found clauses in more than one list, we may now have * We may now have clauses that are known redundant. Get rid of 'em.
* clauses that are known redundant. Get rid of 'em.
*/ */
if (numsources > 1) if (list_length(clause_list) > 1)
{ {
clause_list = remove_redundant_join_clauses(root, clause_list = remove_redundant_join_clauses(root,
clause_list, clause_list,
...@@ -2304,7 +2271,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) ...@@ -2304,7 +2271,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{ {
resultquals = lappend(resultquals, resultquals = lappend(resultquals,
make_restrictinfo(boolqual, make_restrictinfo(boolqual,
true, true)); true, true,
NULL));
continue; continue;
} }
} }
...@@ -2553,7 +2521,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2553,7 +2521,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no = operator for opclass %u", opclass); elog(ERROR, "no = operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const); (Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, true)); result = list_make1(make_restrictinfo(expr, true, true, NULL));
return result; return result;
} }
...@@ -2568,7 +2536,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2568,7 +2536,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no >= operator for opclass %u", opclass); elog(ERROR, "no >= operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const); (Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, true)); result = list_make1(make_restrictinfo(expr, true, true, NULL));
/*------- /*-------
* If we can create a string larger than the prefix, we can say * If we can create a string larger than the prefix, we can say
...@@ -2584,7 +2552,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2584,7 +2552,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no < operator for opclass %u", opclass); elog(ERROR, "no < operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) greaterstr); (Expr *) leftop, (Expr *) greaterstr);
result = lappend(result, make_restrictinfo(expr, true, true)); result = lappend(result, make_restrictinfo(expr, true, true, NULL));
} }
return result; return result;
...@@ -2655,7 +2623,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) ...@@ -2655,7 +2623,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop, (Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr1right, (Expr *) makeConst(datatype, -1, opr1right,
false, false)); false, false));
result = list_make1(make_restrictinfo(expr, true, true)); result = list_make1(make_restrictinfo(expr, true, true, NULL));
/* create clause "key <= network_scan_last( rightop )" */ /* create clause "key <= network_scan_last( rightop )" */
...@@ -2670,7 +2638,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) ...@@ -2670,7 +2638,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop, (Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr2right, (Expr *) makeConst(datatype, -1, opr2right,
false, false)); false, false));
result = lappend(result, make_restrictinfo(expr, true, true)); result = lappend(result, make_restrictinfo(expr, true, true, NULL));
return result; return result;
} }
......
...@@ -8,12 +8,13 @@ ...@@ -8,12 +8,13 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.73 2005/06/05 22:32:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.74 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
...@@ -169,19 +170,12 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -169,19 +170,12 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
if (!bms_overlap(old_rel->relids, new_rel->relids)) if (!bms_overlap(old_rel->relids, new_rel->relids))
{ {
ListCell *i;
/* /*
* OK, we can build a rel of the right level from this * OK, we can build a rel of the right level from this
* pair of rels. Do so if there is at least one * pair of rels. Do so if there is at least one
* usable join clause. * usable join clause.
*/ */
foreach(i, old_rel->joininfo) if (have_relevant_joinclause(old_rel, new_rel))
{
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
if (bms_is_subset(joininfo->unjoined_relids,
new_rel->relids))
{ {
RelOptInfo *jrel; RelOptInfo *jrel;
...@@ -190,9 +184,6 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -190,9 +184,6 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
/* Avoid making duplicate entries ... */ /* Avoid making duplicate entries ... */
if (jrel && !list_member_ptr(result_rels, jrel)) if (jrel && !list_member_ptr(result_rels, jrel))
result_rels = lcons(jrel, result_rels); result_rels = lcons(jrel, result_rels);
break; /* need not consider more
* joininfos */
}
} }
} }
} }
...@@ -269,7 +260,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -269,7 +260,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
/* /*
* make_rels_by_clause_joins * make_rels_by_clause_joins
* Build joins between the given relation 'old_rel' and other relations * Build joins between the given relation 'old_rel' and other relations
* that are mentioned within old_rel's joininfo nodes (i.e., relations * that are mentioned within old_rel's joininfo list (i.e., relations
* that participate in join clauses that 'old_rel' also participates in). * that participate in join clauses that 'old_rel' also participates in).
* The join rel nodes are returned in a list. * The join rel nodes are returned in a list.
* *
...@@ -278,10 +269,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -278,10 +269,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
* rels to be considered for joining * rels to be considered for joining
* *
* Currently, this is only used with initial rels in other_rels, but it * Currently, this is only used with initial rels in other_rels, but it
* will work for joining to joinrels too, if the caller ensures there is no * will work for joining to joinrels too.
* membership overlap between old_rel and the rels in other_rels. (We need
* no extra test for overlap for initial rels, since the is_subset test can
* only succeed when other_rel is not already part of old_rel.)
*/ */
static List * static List *
make_rels_by_clause_joins(PlannerInfo *root, make_rels_by_clause_joins(PlannerInfo *root,
...@@ -289,33 +277,22 @@ make_rels_by_clause_joins(PlannerInfo *root, ...@@ -289,33 +277,22 @@ make_rels_by_clause_joins(PlannerInfo *root,
ListCell *other_rels) ListCell *other_rels)
{ {
List *result = NIL; List *result = NIL;
ListCell *i, ListCell *l;
*j;
foreach(i, old_rel->joininfo)
{
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
Relids unjoined_relids = joininfo->unjoined_relids;
for_each_cell(j, other_rels) for_each_cell(l, other_rels)
{ {
RelOptInfo *other_rel = (RelOptInfo *) lfirst(j); RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
if (bms_is_subset(unjoined_relids, other_rel->relids)) if (!bms_overlap(old_rel->relids, other_rel->relids) &&
have_relevant_joinclause(old_rel, other_rel))
{ {
RelOptInfo *jrel; RelOptInfo *jrel;
jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER); jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER);
if (jrel)
/*
* Avoid entering same joinrel into our output list more
* than once.
*/
if (jrel && !list_member_ptr(result, jrel))
result = lcons(jrel, result); result = lcons(jrel, result);
} }
} }
}
return result; return result;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.71 2005/06/05 22:32:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.72 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -96,12 +96,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -96,12 +96,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
*/ */
foreach(i, rel->joininfo) foreach(i, rel->joininfo)
{ {
JoinInfo *joininfo = (JoinInfo *) lfirst(i); RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
ListCell *j;
foreach(j, joininfo->jinfo_restrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(j);
if (restriction_is_or_clause(rinfo) && if (restriction_is_or_clause(rinfo) &&
rinfo->valid_everywhere) rinfo->valid_everywhere)
...@@ -136,7 +131,6 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -136,7 +131,6 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
} }
} }
} }
}
/* Fail if no suitable clauses found */ /* Fail if no suitable clauses found */
if (bestpath == NULL) if (bestpath == NULL)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.67 2005/06/05 22:32:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.68 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1157,11 +1157,11 @@ make_pathkeys_for_mergeclauses(PlannerInfo *root, ...@@ -1157,11 +1157,11 @@ make_pathkeys_for_mergeclauses(PlannerInfo *root,
/* /*
* pathkeys_useful_for_merging * pathkeys_useful_for_merging
* Count the number of pathkeys that may be useful for mergejoins * Count the number of pathkeys that may be useful for mergejoins
* above the given relation (by looking at its joininfo lists). * above the given relation (by looking at its joininfo list).
* *
* We consider a pathkey potentially useful if it corresponds to the merge * We consider a pathkey potentially useful if it corresponds to the merge
* ordering of either side of any joinclause for the rel. This might be * ordering of either side of any joinclause for the rel. This might be
* overoptimistic, since joinclauses that appear in different join lists * overoptimistic, since joinclauses that require different other relations
* might never be usable at the same time, but trying to be exact is likely * might never be usable at the same time, but trying to be exact is likely
* to be more trouble than it's worth. * to be more trouble than it's worth.
*/ */
...@@ -1179,12 +1179,7 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) ...@@ -1179,12 +1179,7 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys)
foreach(j, rel->joininfo) foreach(j, rel->joininfo)
{ {
JoinInfo *joininfo = (JoinInfo *) lfirst(j); RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j);
ListCell *k;
foreach(k, joininfo->jinfo_restrictinfo)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(k);
if (restrictinfo->mergejoinoperator == InvalidOid) if (restrictinfo->mergejoinoperator == InvalidOid)
continue; continue;
...@@ -1202,10 +1197,6 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) ...@@ -1202,10 +1197,6 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys)
} }
} }
if (matched)
break;
}
/* /*
* If we didn't find a mergeclause, we're done --- any additional * If we didn't find a mergeclause, we're done --- any additional
* sort-key positions in the pathkeys are useless. (But we can * sort-key positions in the pathkeys are useless. (But we can
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.106 2005/06/05 22:32:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.107 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -169,7 +169,7 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed) ...@@ -169,7 +169,7 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
/* /*
* distribute_quals_to_rels * distribute_quals_to_rels
* Recursively scan the query's join tree for WHERE and JOIN/ON qual * Recursively scan the query's join tree for WHERE and JOIN/ON qual
* clauses, and add these to the appropriate RestrictInfo and JoinInfo * clauses, and add these to the appropriate restrictinfo and joininfo
* lists belonging to base RelOptInfos. Also, base RelOptInfos are marked * lists belonging to base RelOptInfos. Also, base RelOptInfos are marked
* with outerjoinset information, to aid in proper positioning of qual * with outerjoinset information, to aid in proper positioning of qual
* clauses that appear above outer joins. * clauses that appear above outer joins.
...@@ -346,7 +346,7 @@ mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels) ...@@ -346,7 +346,7 @@ mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels)
/* /*
* distribute_qual_to_rels * distribute_qual_to_rels
* Add clause information to either the 'RestrictInfo' or 'JoinInfo' field * Add clause information to either the baserestrictinfo or joininfo list
* (depending on whether the clause is a join) of each base relation * (depending on whether the clause is a join) of each base relation
* mentioned in the clause. A RestrictInfo node is created and added to * mentioned in the clause. A RestrictInfo node is created and added to
* the appropriate list for each rel. Also, if the clause uses a * the appropriate list for each rel. Also, if the clause uses a
...@@ -508,7 +508,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -508,7 +508,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/ */
restrictinfo = make_restrictinfo((Expr *) clause, restrictinfo = make_restrictinfo((Expr *) clause,
is_pushed_down, is_pushed_down,
valid_everywhere); valid_everywhere,
relids);
/* /*
* Figure out where to attach it. * Figure out where to attach it.
...@@ -654,8 +655,8 @@ process_implied_equality(PlannerInfo *root, ...@@ -654,8 +655,8 @@ process_implied_equality(PlannerInfo *root,
/* /*
* If the exprs involve a single rel, we need to look at that rel's * If the exprs involve a single rel, we need to look at that rel's
* baserestrictinfo list. If multiple rels, any one will have a * baserestrictinfo list. If multiple rels, we can scan the joininfo
* joininfo node for the rest, and we can scan any of 'em. * list of any of 'em.
*/ */
if (membership == BMS_SINGLETON) if (membership == BMS_SINGLETON)
{ {
...@@ -666,20 +667,14 @@ process_implied_equality(PlannerInfo *root, ...@@ -666,20 +667,14 @@ process_implied_equality(PlannerInfo *root,
{ {
Relids other_rels; Relids other_rels;
int first_rel; int first_rel;
JoinInfo *joininfo;
/* Copy relids, find and remove one member */ /* Copy relids, find and remove one member */
other_rels = bms_copy(relids); other_rels = bms_copy(relids);
first_rel = bms_first_member(other_rels); first_rel = bms_first_member(other_rels);
bms_free(other_rels);
rel1 = find_base_rel(root, first_rel); rel1 = find_base_rel(root, first_rel);
restrictlist = rel1->joininfo;
/* use remaining members to find join node */
joininfo = find_joininfo_node(rel1, other_rels);
restrictlist = joininfo ? joininfo->jinfo_restrictinfo : NIL;
bms_free(other_rels);
} }
/* /*
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.122 2005/06/05 22:32:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.123 2005/06/09 04:18:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1023,6 +1023,9 @@ adjust_inherited_attrs_mutator(Node *node, ...@@ -1023,6 +1023,9 @@ adjust_inherited_attrs_mutator(Node *node,
newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids, newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
context->old_rt_index, context->old_rt_index,
context->new_rt_index); context->new_rt_index);
newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
context->old_rt_index,
context->new_rt_index);
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids, newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
context->old_rt_index, context->old_rt_index,
context->new_rt_index); context->new_rt_index);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* joininfo.c * joininfo.c
* JoinInfo node manipulation routines * joininfo list manipulation routines
* *
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.42 2005/06/05 22:32:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.43 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,58 +19,49 @@ ...@@ -19,58 +19,49 @@
/* /*
* find_joininfo_node * have_relevant_joinclause
* Find the joininfo node within a relation entry corresponding * Detect whether there is a joinclause that can be used to join
* to a join between 'this_rel' and the relations in 'join_relids'. * the two given relations.
* If there is no such node, return NULL.
*
* Returns a joininfo node, or NULL.
*/ */
JoinInfo * bool
find_joininfo_node(RelOptInfo *this_rel, Relids join_relids) have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2)
{ {
bool result = false;
Relids join_relids;
List *joininfo;
ListCell *l; ListCell *l;
foreach(l, this_rel->joininfo) join_relids = bms_union(rel1->relids, rel2->relids);
{
JoinInfo *joininfo = (JoinInfo *) lfirst(l);
if (bms_equal(join_relids, joininfo->unjoined_relids))
return joininfo;
}
return NULL;
}
/* /*
* make_joininfo_node * We could scan either relation's joininfo list; may as well use the
* Find the joininfo node within a relation entry corresponding * shorter one.
* to a join between 'this_rel' and the relations in 'join_relids'.
* A new node is created and added to the relation entry's joininfo
* field if the desired one can't be found.
*
* Returns a joininfo node.
*/ */
JoinInfo * if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
make_joininfo_node(RelOptInfo *this_rel, Relids join_relids) joininfo = rel1->joininfo;
{ else
JoinInfo *joininfo = find_joininfo_node(this_rel, join_relids); joininfo = rel2->joininfo;
if (joininfo == NULL) foreach(l, joininfo)
{ {
joininfo = makeNode(JoinInfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
joininfo->unjoined_relids = join_relids;
joininfo->jinfo_restrictinfo = NIL; if (bms_is_subset(rinfo->required_relids, join_relids))
this_rel->joininfo = lcons(joininfo, this_rel->joininfo); {
result = true;
break;
}
} }
return joininfo;
bms_free(join_relids);
return result;
} }
/* /*
* add_join_clause_to_rels * add_join_clause_to_rels
* For every relation participating in a join clause, add 'restrictinfo' to * Add 'restrictinfo' to the joininfo list of each relation it requires.
* the appropriate joininfo list (creating a new list and adding it to the
* appropriate rel node if necessary).
* *
* Note that the same copy of the restrictinfo node is linked to by all the * Note that the same copy of the restrictinfo node is linked to by all the
* lists it is in. This allows us to exploit caching of information about * lists it is in. This allows us to exploit caching of information about
...@@ -89,32 +80,12 @@ add_join_clause_to_rels(PlannerInfo *root, ...@@ -89,32 +80,12 @@ add_join_clause_to_rels(PlannerInfo *root,
Relids tmprelids; Relids tmprelids;
int cur_relid; int cur_relid;
/* For every relid, find the joininfo, and add the proper join entries */
tmprelids = bms_copy(join_relids); tmprelids = bms_copy(join_relids);
while ((cur_relid = bms_first_member(tmprelids)) >= 0) while ((cur_relid = bms_first_member(tmprelids)) >= 0)
{ {
Relids unjoined_relids; RelOptInfo *rel = find_base_rel(root, cur_relid);
JoinInfo *joininfo;
/* Get the relids not equal to the current relid */
unjoined_relids = bms_copy(join_relids);
unjoined_relids = bms_del_member(unjoined_relids, cur_relid);
Assert(!bms_is_empty(unjoined_relids));
/*
* Find or make the joininfo node for this combination of rels,
* and add the restrictinfo node to it.
*/
joininfo = make_joininfo_node(find_base_rel(root, cur_relid),
unjoined_relids);
joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
restrictinfo);
/* rel->joininfo = lappend(rel->joininfo, restrictinfo);
* Can't bms_free(unjoined_relids) because new joininfo node may
* link to it. We could avoid leaking memory by doing bms_copy()
* in make_joininfo_node, but for now speed seems better.
*/
} }
bms_free(tmprelids); bms_free(tmprelids);
} }
...@@ -138,34 +109,17 @@ remove_join_clause_from_rels(PlannerInfo *root, ...@@ -138,34 +109,17 @@ remove_join_clause_from_rels(PlannerInfo *root,
Relids tmprelids; Relids tmprelids;
int cur_relid; int cur_relid;
/* For every relid, find the joininfo */
tmprelids = bms_copy(join_relids); tmprelids = bms_copy(join_relids);
while ((cur_relid = bms_first_member(tmprelids)) >= 0) while ((cur_relid = bms_first_member(tmprelids)) >= 0)
{ {
Relids unjoined_relids; RelOptInfo *rel = find_base_rel(root, cur_relid);
JoinInfo *joininfo;
/* Get the relids not equal to the current relid */
unjoined_relids = bms_copy(join_relids);
unjoined_relids = bms_del_member(unjoined_relids, cur_relid);
Assert(!bms_is_empty(unjoined_relids));
/*
* Find the joininfo node for this combination of rels; it should
* exist already, if add_join_clause_to_rels was called.
*/
joininfo = find_joininfo_node(find_base_rel(root, cur_relid),
unjoined_relids);
Assert(joininfo);
/* /*
* Remove the restrictinfo from the list. Pointer comparison is * Remove the restrictinfo from the list. Pointer comparison is
* sufficient. * sufficient.
*/ */
Assert(list_member_ptr(joininfo->jinfo_restrictinfo, restrictinfo)); Assert(list_member_ptr(rel->joininfo, restrictinfo));
joininfo->jinfo_restrictinfo = list_delete_ptr(joininfo->jinfo_restrictinfo, rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
restrictinfo);
bms_free(unjoined_relids);
} }
bms_free(tmprelids); bms_free(tmprelids);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.69 2005/06/08 23:02:05 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.70 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -479,8 +479,8 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, ...@@ -479,8 +479,8 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
* *
* These routines are separate because the restriction list must be * These routines are separate because the restriction list must be
* built afresh for each pair of input sub-relations we consider, whereas * built afresh for each pair of input sub-relations we consider, whereas
* the join lists need only be computed once for any join RelOptInfo. * the join list need only be computed once for any join RelOptInfo.
* The join lists are fully determined by the set of rels making up the * The join list is fully determined by the set of rels making up the
* joinrel, so we should get the same results (up to ordering) from any * joinrel, so we should get the same results (up to ordering) from any
* candidate pair of sub-relations. But the restriction list is whatever * candidate pair of sub-relations. But the restriction list is whatever
* is not handled in the sub-relations, so it depends on which * is not handled in the sub-relations, so it depends on which
...@@ -488,7 +488,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, ...@@ -488,7 +488,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
* *
* If a join clause from an input relation refers to base rels still not * If a join clause from an input relation refers to base rels still not
* present in the joinrel, then it is still a join clause for the joinrel; * present in the joinrel, then it is still a join clause for the joinrel;
* we put it into an appropriate JoinInfo list for the joinrel. Otherwise, * we put it into the joininfo list for the joinrel. Otherwise,
* the clause is now a restrict clause for the joined relation, and we * the clause is now a restrict clause for the joined relation, and we
* return it to the caller of build_joinrel_restrictlist() to be stored in * return it to the caller of build_joinrel_restrictlist() to be stored in
* join paths made from this pair of sub-relations. (It will not need to * join paths made from this pair of sub-relations. (It will not need to
...@@ -506,7 +506,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, ...@@ -506,7 +506,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
* *
* build_joinrel_restrictlist() returns a list of relevant restrictinfos, * build_joinrel_restrictlist() returns a list of relevant restrictinfos,
* whereas build_joinrel_joinlist() stores its results in the joinrel's * whereas build_joinrel_joinlist() stores its results in the joinrel's
* joininfo lists. One or the other must accept each given clause! * joininfo list. One or the other must accept each given clause!
* *
* NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
* up to the join relation. I believe this is no longer necessary, because * up to the join relation. I believe this is no longer necessary, because
...@@ -562,29 +562,27 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel, ...@@ -562,29 +562,27 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
List *joininfo_list) List *joininfo_list)
{ {
List *restrictlist = NIL; List *restrictlist = NIL;
ListCell *xjoininfo; ListCell *l;
foreach(xjoininfo, joininfo_list) foreach(l, joininfo_list)
{ {
JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
if (bms_is_subset(joininfo->unjoined_relids, joinrel->relids)) if (bms_is_subset(rinfo->required_relids, joinrel->relids))
{ {
/* /*
* Clauses in this JoinInfo list become restriction clauses * This clause becomes a restriction clause for the joinrel,
* for the joinrel, since they refer to no outside rels. * since it refers to no outside rels. We don't bother to
* * check for duplicates here --- build_joinrel_restrictlist
* We must copy the list to avoid disturbing the input relation, * will do that.
* but we can use a shallow copy.
*/ */
restrictlist = list_concat(restrictlist, restrictlist = lappend(restrictlist, rinfo);
list_copy(joininfo->jinfo_restrictinfo));
} }
else else
{ {
/* /*
* These clauses are still join clauses at this level, so we * This clause is still a join clause at this level, so we
* ignore them in this routine. * ignore it in this routine.
*/ */
} }
} }
...@@ -596,42 +594,33 @@ static void ...@@ -596,42 +594,33 @@ static void
subbuild_joinrel_joinlist(RelOptInfo *joinrel, subbuild_joinrel_joinlist(RelOptInfo *joinrel,
List *joininfo_list) List *joininfo_list)
{ {
ListCell *xjoininfo; ListCell *l;
foreach(xjoininfo, joininfo_list) foreach(l, joininfo_list)
{ {
JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
Relids new_unjoined_relids;
new_unjoined_relids = bms_difference(joininfo->unjoined_relids, if (bms_is_subset(rinfo->required_relids, joinrel->relids))
joinrel->relids);
if (bms_is_empty(new_unjoined_relids))
{ {
/* /*
* Clauses in this JoinInfo list become restriction clauses * This clause becomes a restriction clause for the joinrel,
* for the joinrel, since they refer to no outside rels. So we * since it refers to no outside rels. So we can ignore it
* can ignore them in this routine. * in this routine.
*/ */
bms_free(new_unjoined_relids);
} }
else else
{ {
/* /*
* These clauses are still join clauses at this level, so find * This clause is still a join clause at this level, so add
* or make the appropriate JoinInfo item for the joinrel, and * it to the joininfo list for the joinrel, being careful to
* add the clauses to it, eliminating duplicates. (Since * eliminate duplicates. (Since RestrictInfo nodes are normally
* RestrictInfo nodes are normally multiply-linked rather than * multiply-linked rather than copied, pointer equality should be
* copied, pointer equality should be a sufficient test. If * a sufficient test. If two equal() nodes should happen to sneak
* two equal() nodes should happen to sneak in, no great harm * in, no great harm is done --- they'll be detected by
* is done --- they'll be detected by redundant-clause testing * redundant-clause testing when they reach a restriction list.)
* when they reach a restriction list.)
*/ */
JoinInfo *new_joininfo; if (!list_member_ptr(joinrel->joininfo, rinfo))
joinrel->joininfo = lappend(joinrel->joininfo, rinfo);
new_joininfo = make_joininfo_node(joinrel, new_unjoined_relids);
new_joininfo->jinfo_restrictinfo =
list_union_ptr(new_joininfo->jinfo_restrictinfo,
joininfo->jinfo_restrictinfo);
} }
} }
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.36 2005/06/05 22:32:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.37 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
static RestrictInfo *make_restrictinfo_internal(Expr *clause, static RestrictInfo *make_restrictinfo_internal(Expr *clause,
Expr *orclause, Expr *orclause,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere); bool valid_everywhere,
Relids required_relids);
static Expr *make_sub_restrictinfos(Expr *clause, static Expr *make_sub_restrictinfos(Expr *clause,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere); bool valid_everywhere);
...@@ -40,14 +41,16 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, ...@@ -40,14 +41,16 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
* Build a RestrictInfo node containing the given subexpression. * Build a RestrictInfo node containing the given subexpression.
* *
* The is_pushed_down and valid_everywhere flags must be supplied by the * The is_pushed_down and valid_everywhere flags must be supplied by the
* caller. * caller. required_relids can be NULL, in which case it defaults to the
* actual clause contents (i.e., clause_relids).
* *
* We initialize fields that depend only on the given subexpression, leaving * We initialize fields that depend only on the given subexpression, leaving
* others that depend on context (or may never be needed at all) to be filled * others that depend on context (or may never be needed at all) to be filled
* later. * later.
*/ */
RestrictInfo * RestrictInfo *
make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere) make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere,
Relids required_relids)
{ {
/* /*
* If it's an OR clause, build a modified copy with RestrictInfos * If it's an OR clause, build a modified copy with RestrictInfos
...@@ -62,7 +65,8 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere) ...@@ -62,7 +65,8 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere)
Assert(!and_clause((Node *) clause)); Assert(!and_clause((Node *) clause));
return make_restrictinfo_internal(clause, NULL, return make_restrictinfo_internal(clause, NULL,
is_pushed_down, valid_everywhere); is_pushed_down, valid_everywhere,
required_relids);
} }
/* /*
...@@ -133,7 +137,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -133,7 +137,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
list_make1(make_restrictinfo_internal(make_orclause(withoutris), list_make1(make_restrictinfo_internal(make_orclause(withoutris),
make_orclause(withris), make_orclause(withris),
is_pushed_down, is_pushed_down,
valid_everywhere)); valid_everywhere,
NULL));
} }
else if (IsA(bitmapqual, IndexPath)) else if (IsA(bitmapqual, IndexPath))
{ {
...@@ -157,7 +162,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -157,7 +162,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
*/ */
static RestrictInfo * static RestrictInfo *
make_restrictinfo_internal(Expr *clause, Expr *orclause, make_restrictinfo_internal(Expr *clause, Expr *orclause,
bool is_pushed_down, bool valid_everywhere) bool is_pushed_down, bool valid_everywhere,
Relids required_relids)
{ {
RestrictInfo *restrictinfo = makeNode(RestrictInfo); RestrictInfo *restrictinfo = makeNode(RestrictInfo);
...@@ -200,6 +206,12 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause, ...@@ -200,6 +206,12 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
restrictinfo->clause_relids = pull_varnos((Node *) clause); restrictinfo->clause_relids = pull_varnos((Node *) clause);
} }
/* required_relids defaults to clause_relids */
if (required_relids != NULL)
restrictinfo->required_relids = required_relids;
else
restrictinfo->required_relids = restrictinfo->clause_relids;
/* /*
* Fill in all the cacheable fields with "not yet set" markers. None * Fill in all the cacheable fields with "not yet set" markers. None
* of these will be computed until/unless needed. Note in particular * of these will be computed until/unless needed. Note in particular
...@@ -254,7 +266,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, ...@@ -254,7 +266,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
return (Expr *) make_restrictinfo_internal(clause, return (Expr *) make_restrictinfo_internal(clause,
make_orclause(orlist), make_orclause(orlist),
is_pushed_down, is_pushed_down,
valid_everywhere); valid_everywhere,
NULL);
} }
else if (and_clause((Node *) clause)) else if (and_clause((Node *) clause))
{ {
...@@ -272,7 +285,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, ...@@ -272,7 +285,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
return (Expr *) make_restrictinfo_internal(clause, return (Expr *) make_restrictinfo_internal(clause,
NULL, NULL,
is_pushed_down, is_pushed_down,
valid_everywhere); valid_everywhere,
NULL);
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.169 2005/06/05 22:32:57 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.170 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -183,7 +183,6 @@ typedef enum NodeTag ...@@ -183,7 +183,6 @@ typedef enum NodeTag
T_UniquePath, T_UniquePath,
T_PathKeyItem, T_PathKeyItem,
T_RestrictInfo, T_RestrictInfo,
T_JoinInfo,
T_InnerIndexscanInfo, T_InnerIndexscanInfo,
T_InClauseInfo, T_InClauseInfo,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.112 2005/06/08 23:02:05 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.113 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -181,7 +181,7 @@ typedef struct PlannerInfo ...@@ -181,7 +181,7 @@ typedef struct PlannerInfo
* and joins that the relation participates in: * and joins that the relation participates in:
* *
* baserestrictinfo - List of RestrictInfo nodes, containing info about * baserestrictinfo - List of RestrictInfo nodes, containing info about
* each qualification clause in which this relation * each non-join qualification clause in which this relation
* participates (only used for base rels) * participates (only used for base rels)
* baserestrictcost - Estimated cost of evaluating the baserestrictinfo * baserestrictcost - Estimated cost of evaluating the baserestrictinfo
* clauses at a single tuple (only used for base rels) * clauses at a single tuple (only used for base rels)
...@@ -189,8 +189,8 @@ typedef struct PlannerInfo ...@@ -189,8 +189,8 @@ typedef struct PlannerInfo
* side of an outer join, the set of all relids * side of an outer join, the set of all relids
* participating in the highest such outer join; else NULL. * participating in the highest such outer join; else NULL.
* Otherwise, unused. * Otherwise, unused.
* joininfo - List of JoinInfo nodes, containing info about each join * joininfo - List of RestrictInfo nodes, containing info about each
* clause in which this relation participates * join clause in which this relation participates
* index_outer_relids - only used for base rels; set of outer relids * index_outer_relids - only used for base rels; set of outer relids
* that participate in indexable joinclauses for this rel * that participate in indexable joinclauses for this rel
* index_inner_paths - only used for base rels; list of InnerIndexscanInfo * index_inner_paths - only used for base rels; list of InnerIndexscanInfo
...@@ -206,7 +206,7 @@ typedef struct PlannerInfo ...@@ -206,7 +206,7 @@ typedef struct PlannerInfo
* and should not be processed again at the level of {1 2 3}.) Therefore, * and should not be processed again at the level of {1 2 3}.) Therefore,
* the restrictinfo list in the join case appears in individual JoinPaths * the restrictinfo list in the join case appears in individual JoinPaths
* (field joinrestrictinfo), not in the parent relation. But it's OK for * (field joinrestrictinfo), not in the parent relation. But it's OK for
* the RelOptInfo to store the joininfo lists, because those are the same * the RelOptInfo to store the joininfo list, because that is the same
* for a given rel no matter how we form it. * for a given rel no matter how we form it.
* *
* We store baserestrictcost in the RelOptInfo (for base relations) because * We store baserestrictcost in the RelOptInfo (for base relations) because
...@@ -262,7 +262,8 @@ typedef struct RelOptInfo ...@@ -262,7 +262,8 @@ typedef struct RelOptInfo
* base rel) */ * base rel) */
QualCost baserestrictcost; /* cost of evaluating the above */ QualCost baserestrictcost; /* cost of evaluating the above */
Relids outerjoinset; /* set of base relids */ Relids outerjoinset; /* set of base relids */
List *joininfo; /* JoinInfo structures */ List *joininfo; /* RestrictInfo structures for join clauses
* involving this rel */
/* cached info about inner indexscan paths for relation: */ /* cached info about inner indexscan paths for relation: */
Relids index_outer_relids; /* other relids in indexable join Relids index_outer_relids; /* other relids in indexable join
...@@ -645,8 +646,8 @@ typedef struct HashPath ...@@ -645,8 +646,8 @@ typedef struct HashPath
* in the baserestrictinfo list of the RelOptInfo for that base rel. * in the baserestrictinfo list of the RelOptInfo for that base rel.
* *
* If a restriction clause references more than one base rel, it will * If a restriction clause references more than one base rel, it will
* appear in the JoinInfo lists of every RelOptInfo that describes a strict * appear in the joininfo list of every RelOptInfo that describes a strict
* subset of the base rels mentioned in the clause. The JoinInfo lists are * subset of the base rels mentioned in the clause. The joininfo lists are
* used to drive join tree building by selecting plausible join candidates. * used to drive join tree building by selecting plausible join candidates.
* The clause cannot actually be applied until we have built a join rel * The clause cannot actually be applied until we have built a join rel
* containing all the base rels it references, however. * containing all the base rels it references, however.
...@@ -676,8 +677,8 @@ typedef struct HashPath ...@@ -676,8 +677,8 @@ typedef struct HashPath
* pushed down to a lower level than its original syntactic placement in the * pushed down to a lower level than its original syntactic placement in the
* join tree would suggest. If an outer join prevents us from pushing a qual * join tree would suggest. If an outer join prevents us from pushing a qual
* down to its "natural" semantic level (the level associated with just the * down to its "natural" semantic level (the level associated with just the
* base rels used in the qual) then the qual will appear in JoinInfo lists * base rels used in the qual) then we mark the qual with a "required_relids"
* that reference more than just the base rels it actually uses. By * value including more than just the base rels it actually uses. By
* pretending that the qual references all the rels appearing in the outer * pretending that the qual references all the rels appearing in the outer
* join, we prevent it from being evaluated below the outer join's joinrel. * join, we prevent it from being evaluated below the outer join's joinrel.
* When we do form the outer join's joinrel, we still need to distinguish * When we do form the outer join's joinrel, we still need to distinguish
...@@ -685,11 +686,11 @@ typedef struct HashPath ...@@ -685,11 +686,11 @@ typedef struct HashPath
* that appeared higher in the tree and were pushed down to the join rel * that appeared higher in the tree and were pushed down to the join rel
* because they used no other rels. That's what the is_pushed_down flag is * because they used no other rels. That's what the is_pushed_down flag is
* for; it tells us that a qual came from a point above the join of the * for; it tells us that a qual came from a point above the join of the
* specific set of base rels that it uses (or that the JoinInfo structures * set of base rels listed in required_relids. A clause that originally came
* claim it uses). A clause that originally came from WHERE will *always* * from WHERE will *always* have its is_pushed_down flag set; a clause that
* have its is_pushed_down flag set; a clause that came from an INNER JOIN * came from an INNER JOIN condition, but doesn't use all the rels being
* condition, but doesn't use all the rels being joined, will also have * joined, will also have is_pushed_down set because it will get attached to
* is_pushed_down set because it will get attached to some lower joinrel. * some lower joinrel.
* *
* We also store a valid_everywhere flag, which says that the clause is not * We also store a valid_everywhere flag, which says that the clause is not
* affected by any lower-level outer join, and therefore any conditions it * affected by any lower-level outer join, and therefore any conditions it
...@@ -732,9 +733,12 @@ typedef struct RestrictInfo ...@@ -732,9 +733,12 @@ typedef struct RestrictInfo
*/ */
bool can_join; bool can_join;
/* The set of relids (varnos) referenced in the clause: */ /* The set of relids (varnos) actually referenced in the clause: */
Relids clause_relids; Relids clause_relids;
/* The set of relids required to evaluate the clause: */
Relids required_relids;
/* These fields are set for any binary opclause: */ /* These fields are set for any binary opclause: */
Relids left_relids; /* relids in left side of clause */ Relids left_relids; /* relids in left side of clause */
Relids right_relids; /* relids in right side of clause */ Relids right_relids; /* relids in right side of clause */
...@@ -767,27 +771,6 @@ typedef struct RestrictInfo ...@@ -767,27 +771,6 @@ typedef struct RestrictInfo
Selectivity right_bucketsize; /* avg bucketsize of right side */ Selectivity right_bucketsize; /* avg bucketsize of right side */
} RestrictInfo; } RestrictInfo;
/*
* Join clause info.
*
* We make a list of these for each RelOptInfo, containing info about
* all the join clauses this RelOptInfo participates in. (For this
* purpose, a "join clause" is a WHERE clause that mentions both vars
* belonging to this relation and vars belonging to relations not yet
* joined to it.) We group these clauses according to the set of
* other base relations (unjoined relations) mentioned in them.
* There is one JoinInfo for each distinct set of unjoined_relids,
* and its jinfo_restrictinfo lists the clause(s) that use that set
* of other relations.
*/
typedef struct JoinInfo
{
NodeTag type;
Relids unjoined_relids; /* some rels not yet part of my RelOptInfo */
List *jinfo_restrictinfo; /* relevant RestrictInfos */
} JoinInfo;
/* /*
* Inner indexscan info. * Inner indexscan info.
* *
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.29 2005/06/05 22:32:58 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.30 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
#include "nodes/relation.h" #include "nodes/relation.h"
extern JoinInfo *find_joininfo_node(RelOptInfo *this_rel, Relids join_relids); extern bool have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2);
extern JoinInfo *make_joininfo_node(RelOptInfo *this_rel, Relids join_relids);
extern void add_join_clause_to_rels(PlannerInfo *root, extern void add_join_clause_to_rels(PlannerInfo *root,
RestrictInfo *restrictinfo, RestrictInfo *restrictinfo,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.30 2005/06/05 22:32:58 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.31 2005/06/09 04:19:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
#include "nodes/relation.h" #include "nodes/relation.h"
extern RestrictInfo *make_restrictinfo(Expr *clause, bool is_pushed_down, extern RestrictInfo *make_restrictinfo(Expr *clause,
bool valid_everywhere); bool is_pushed_down,
bool valid_everywhere,
Relids required_relids);
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual, extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere); bool valid_everywhere);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment