Teach planner about some cases where a restriction clause can be
propagated inside an outer join. In particular, given LEFT JOIN ON (A = B) WHERE A = constant, we cannot conclude that B = constant at the top level (B might be null instead), but we can nonetheless put a restriction B = constant into the quals for B's relation, since no inner-side rows not meeting that condition can contribute to the final result. Similarly, given FULL JOIN USING (J) WHERE J = constant, we can't directly conclude that either input J variable = constant, but it's OK to push such quals into each input rel. Per recent gripe from Kim Bisgaard. Along the way, remove 'valid_everywhere' flag from RestrictInfo, as on closer analysis it was not being used for anything, and was defined backwards anyway.
This commit is contained in:
parent
ea1e2b948d
commit
cc5e80b8d1
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.310 2005/06/28 05:08:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.311 2005/07/02 23:00:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1249,7 +1249,6 @@ _copyRestrictInfo(RestrictInfo *from)
|
||||
|
||||
COPY_NODE_FIELD(clause);
|
||||
COPY_SCALAR_FIELD(is_pushed_down);
|
||||
COPY_SCALAR_FIELD(valid_everywhere);
|
||||
COPY_SCALAR_FIELD(can_join);
|
||||
COPY_BITMAPSET_FIELD(clause_relids);
|
||||
COPY_BITMAPSET_FIELD(required_relids);
|
||||
|
@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.247 2005/06/28 05:08:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.248 2005/07/02 23:00:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -603,7 +603,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(clause);
|
||||
COMPARE_SCALAR_FIELD(is_pushed_down);
|
||||
COMPARE_SCALAR_FIELD(valid_everywhere);
|
||||
COMPARE_BITMAPSET_FIELD(required_relids);
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.257 2005/06/28 05:08:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.258 2005/07/02 23:00:39 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@ -1164,9 +1164,13 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
|
||||
WRITE_NODE_FIELD(parse);
|
||||
WRITE_NODE_FIELD(join_rel_list);
|
||||
WRITE_NODE_FIELD(equi_key_list);
|
||||
WRITE_NODE_FIELD(left_join_clauses);
|
||||
WRITE_NODE_FIELD(right_join_clauses);
|
||||
WRITE_NODE_FIELD(full_join_clauses);
|
||||
WRITE_NODE_FIELD(in_info_list);
|
||||
WRITE_NODE_FIELD(query_pathkeys);
|
||||
WRITE_BOOL_FIELD(hasJoinRTEs);
|
||||
WRITE_BOOL_FIELD(hasOuterJoins);
|
||||
WRITE_BOOL_FIELD(hasHavingQual);
|
||||
}
|
||||
|
||||
@ -1234,7 +1238,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
|
||||
/* NB: this isn't a complete set of fields */
|
||||
WRITE_NODE_FIELD(clause);
|
||||
WRITE_BOOL_FIELD(is_pushed_down);
|
||||
WRITE_BOOL_FIELD(valid_everywhere);
|
||||
WRITE_BOOL_FIELD(can_join);
|
||||
WRITE_BITMAPSET_FIELD(clause_relids);
|
||||
WRITE_BITMAPSET_FIELD(required_relids);
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.185 2005/06/14 04:04:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.186 2005/07/02 23:00:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1882,7 +1882,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
{
|
||||
resultquals = lappend(resultquals,
|
||||
make_restrictinfo(boolqual,
|
||||
true, true,
|
||||
true,
|
||||
NULL));
|
||||
continue;
|
||||
}
|
||||
@ -2132,7 +2132,7 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
elog(ERROR, "no = operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) prefix_const);
|
||||
result = list_make1(make_restrictinfo(expr, true, true, NULL));
|
||||
result = list_make1(make_restrictinfo(expr, true, NULL));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2147,7 +2147,7 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
elog(ERROR, "no >= operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) prefix_const);
|
||||
result = list_make1(make_restrictinfo(expr, true, true, NULL));
|
||||
result = list_make1(make_restrictinfo(expr, true, NULL));
|
||||
|
||||
/*-------
|
||||
* If we can create a string larger than the prefix, we can say
|
||||
@ -2163,7 +2163,7 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
elog(ERROR, "no < operator for opclass %u", opclass);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) greaterstr);
|
||||
result = lappend(result, make_restrictinfo(expr, true, true, NULL));
|
||||
result = lappend(result, make_restrictinfo(expr, true, NULL));
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -2234,7 +2234,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
(Expr *) leftop,
|
||||
(Expr *) makeConst(datatype, -1, opr1right,
|
||||
false, false));
|
||||
result = list_make1(make_restrictinfo(expr, true, true, NULL));
|
||||
result = list_make1(make_restrictinfo(expr, true, NULL));
|
||||
|
||||
/* create clause "key <= network_scan_last( rightop )" */
|
||||
|
||||
@ -2249,7 +2249,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
(Expr *) leftop,
|
||||
(Expr *) makeConst(datatype, -1, opr2right,
|
||||
false, false));
|
||||
result = lappend(result, make_restrictinfo(expr, true, true, NULL));
|
||||
result = lappend(result, make_restrictinfo(expr, true, NULL));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.72 2005/06/09 04:18:59 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.73 2005/07/02 23:00:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -90,16 +90,13 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
|
||||
ListCell *i;
|
||||
|
||||
/*
|
||||
* Find potentially interesting OR joinclauses. We must ignore any
|
||||
* joinclauses that are not marked valid_everywhere, because they
|
||||
* cannot be pushed down due to outer-join rules.
|
||||
* Find potentially interesting OR joinclauses.
|
||||
*/
|
||||
foreach(i, rel->joininfo)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
|
||||
|
||||
if (restriction_is_or_clause(rinfo) &&
|
||||
rinfo->valid_everywhere)
|
||||
if (restriction_is_or_clause(rinfo))
|
||||
{
|
||||
/*
|
||||
* Use the generate_bitmap_or_paths() machinery to estimate
|
||||
@ -140,8 +137,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
|
||||
* Convert the path's indexclauses structure to a RestrictInfo tree,
|
||||
* and add it to the rel's restriction list.
|
||||
*/
|
||||
newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath,
|
||||
true, true);
|
||||
newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, true);
|
||||
Assert(list_length(newrinfos) == 1);
|
||||
or_rinfo = (RestrictInfo *) linitial(newrinfos);
|
||||
Assert(IsA(or_rinfo, RestrictInfo));
|
||||
|
@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.68 2005/06/09 04:18:59 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.69 2005/07/02 23:00:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -32,6 +32,14 @@
|
||||
|
||||
|
||||
static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool checkType);
|
||||
static void generate_outer_join_implications(PlannerInfo *root,
|
||||
List *equi_key_set,
|
||||
Relids *relids);
|
||||
static void process_implied_const_eq(PlannerInfo *root,
|
||||
List *equi_key_set, Relids *relids,
|
||||
Node *item1, Oid sortop1,
|
||||
Relids item1_relids,
|
||||
bool delete_it);
|
||||
static List *make_canonical_pathkey(PlannerInfo *root, PathKeyItem *item);
|
||||
static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
|
||||
AttrNumber varattno);
|
||||
@ -193,6 +201,10 @@ add_equijoined_keys(PlannerInfo *root, RestrictInfo *restrictinfo)
|
||||
* functions; but we will never consider such an expression to be a pathkey
|
||||
* at all, because check_mergejoinable() will reject it.)
|
||||
*
|
||||
* Also, when we have constants in an equi_key_list we can try to propagate
|
||||
* the constants into outer joins; see generate_outer_join_implications
|
||||
* for discussion.
|
||||
*
|
||||
* This routine just walks the equi_key_list to find all pairwise equalities.
|
||||
* We call process_implied_equality (in plan/initsplan.c) to adjust the
|
||||
* restrictinfo datastructures for each pair.
|
||||
@ -213,9 +225,10 @@ generate_implied_equalities(PlannerInfo *root)
|
||||
|
||||
/*
|
||||
* A set containing only two items cannot imply any equalities
|
||||
* beyond the one that created the set, so we can skip it.
|
||||
* beyond the one that created the set, so we can skip it ---
|
||||
* unless outer joins appear in the query.
|
||||
*/
|
||||
if (nitems < 3)
|
||||
if (nitems < 3 && !root->hasOuterJoins)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -237,6 +250,20 @@ generate_implied_equalities(PlannerInfo *root)
|
||||
i1++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have constant(s) and outer joins, try to propagate the
|
||||
* constants through outer-join quals.
|
||||
*/
|
||||
if (have_consts && root->hasOuterJoins)
|
||||
generate_outer_join_implications(root, curset, relids);
|
||||
|
||||
/*
|
||||
* A set containing only two items cannot imply any equalities
|
||||
* beyond the one that created the set, so we can skip it.
|
||||
*/
|
||||
if (nitems < 3)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Match each item in the set with all that appear after it (it's
|
||||
* sufficient to generate A=B, need not process B=A too).
|
||||
@ -285,6 +312,264 @@ generate_implied_equalities(PlannerInfo *root)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_outer_join_implications
|
||||
* Generate clauses that can be deduced in outer-join situations.
|
||||
*
|
||||
* When we have mergejoinable clauses A = B that are outer-join clauses,
|
||||
* we can't blindly combine them with other clauses A = C to deduce B = C,
|
||||
* since in fact the "equality" A = B won't necessarily hold above the
|
||||
* outer join (one of the variables might be NULL instead). Nonetheless
|
||||
* there are cases where we can add qual clauses using transitivity.
|
||||
*
|
||||
* One case that we look for here is an outer-join clause OUTERVAR = INNERVAR
|
||||
* combined with a pushed-down (valid everywhere) clause OUTERVAR = CONSTANT.
|
||||
* It is safe and useful to push a clause INNERVAR = CONSTANT into the
|
||||
* evaluation of the inner (nullable) relation, because any inner rows not
|
||||
* meeting this condition will not contribute to the outer-join result anyway.
|
||||
* (Any outer rows they could join to will be eliminated by the pushed-down
|
||||
* clause.)
|
||||
*
|
||||
* Note that the above rule does not work for full outer joins, nor for
|
||||
* pushed-down restrictions on an inner-side variable; nor is it very
|
||||
* interesting to consider cases where the pushed-down clause involves
|
||||
* relations entirely outside the outer join, since such clauses couldn't
|
||||
* be pushed into the inner side's scan anyway. So the restriction to
|
||||
* outervar = pseudoconstant is not really giving up anything.
|
||||
*
|
||||
* For full-join cases, we can only do something useful if it's a FULL JOIN
|
||||
* USING and a merged column has a restriction MERGEDVAR = CONSTANT. By
|
||||
* the time it gets here, the restriction will look like
|
||||
* COALESCE(LEFTVAR, RIGHTVAR) = CONSTANT
|
||||
* and we will have a join clause LEFTVAR = RIGHTVAR that we can match the
|
||||
* COALESCE expression to. In this situation we can push LEFTVAR = CONSTANT
|
||||
* and RIGHTVAR = CONSTANT into the input relations, since any rows not
|
||||
* meeting these conditions cannot contribute to the join result.
|
||||
*
|
||||
* Again, there isn't any traction to be gained by trying to deal with
|
||||
* clauses comparing a mergedvar to a non-pseudoconstant. So we can make
|
||||
* use of the equi_key_lists to quickly find the interesting pushed-down
|
||||
* clauses. The interesting outer-join clauses were accumulated for us by
|
||||
* distribute_qual_to_rels.
|
||||
*
|
||||
* equi_key_set: a list of PathKeyItems that are known globally equivalent,
|
||||
* at least one of which is a pseudoconstant.
|
||||
* relids: an array of Relids sets showing the relation membership of each
|
||||
* PathKeyItem in equi_key_set.
|
||||
*/
|
||||
static void
|
||||
generate_outer_join_implications(PlannerInfo *root,
|
||||
List *equi_key_set,
|
||||
Relids *relids)
|
||||
{
|
||||
ListCell *l1;
|
||||
|
||||
/* Examine each mergejoinable outer-join clause with OUTERVAR on left */
|
||||
foreach(l1, root->left_join_clauses)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
|
||||
Node *leftop = get_leftop(rinfo->clause);
|
||||
Node *rightop = get_rightop(rinfo->clause);
|
||||
ListCell *l2;
|
||||
|
||||
/* Scan to see if it matches any element of equi_key_set */
|
||||
foreach(l2, equi_key_set)
|
||||
{
|
||||
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
|
||||
|
||||
if (equal(leftop, item1->key) &&
|
||||
rinfo->left_sortop == item1->sortop)
|
||||
{
|
||||
/*
|
||||
* Yes, so find constant member(s) of set and generate
|
||||
* implied INNERVAR = CONSTANT
|
||||
*/
|
||||
process_implied_const_eq(root, equi_key_set, relids,
|
||||
rightop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->right_relids,
|
||||
false);
|
||||
/*
|
||||
* We can remove the explicit outer join qual, too,
|
||||
* since we now have tests forcing each of its sides
|
||||
* to the same value.
|
||||
*/
|
||||
process_implied_equality(root,
|
||||
leftop,
|
||||
rightop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->left_relids,
|
||||
rinfo->right_relids,
|
||||
true);
|
||||
|
||||
/* No need to match against remaining set members */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Examine each mergejoinable outer-join clause with OUTERVAR on right */
|
||||
foreach(l1, root->right_join_clauses)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
|
||||
Node *leftop = get_leftop(rinfo->clause);
|
||||
Node *rightop = get_rightop(rinfo->clause);
|
||||
ListCell *l2;
|
||||
|
||||
/* Scan to see if it matches any element of equi_key_set */
|
||||
foreach(l2, equi_key_set)
|
||||
{
|
||||
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
|
||||
|
||||
if (equal(rightop, item1->key) &&
|
||||
rinfo->right_sortop == item1->sortop)
|
||||
{
|
||||
/*
|
||||
* Yes, so find constant member(s) of set and generate
|
||||
* implied INNERVAR = CONSTANT
|
||||
*/
|
||||
process_implied_const_eq(root, equi_key_set, relids,
|
||||
leftop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->left_relids,
|
||||
false);
|
||||
/*
|
||||
* We can remove the explicit outer join qual, too,
|
||||
* since we now have tests forcing each of its sides
|
||||
* to the same value.
|
||||
*/
|
||||
process_implied_equality(root,
|
||||
leftop,
|
||||
rightop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->left_relids,
|
||||
rinfo->right_relids,
|
||||
true);
|
||||
|
||||
/* No need to match against remaining set members */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Examine each mergejoinable full-join clause */
|
||||
foreach(l1, root->full_join_clauses)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
|
||||
Node *leftop = get_leftop(rinfo->clause);
|
||||
Node *rightop = get_rightop(rinfo->clause);
|
||||
int i1 = 0;
|
||||
ListCell *l2;
|
||||
|
||||
/* Scan to see if it matches any element of equi_key_set */
|
||||
foreach(l2, equi_key_set)
|
||||
{
|
||||
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
|
||||
CoalesceExpr *cexpr = (CoalesceExpr *) item1->key;
|
||||
|
||||
/*
|
||||
* Try to match a pathkey containing a COALESCE() expression
|
||||
* to the join clause. We can assume the COALESCE() inputs
|
||||
* are in the same order as the join clause, since both were
|
||||
* automatically generated in the cases we care about.
|
||||
*
|
||||
* XXX currently this may fail to match in cross-type cases
|
||||
* because the COALESCE will contain typecast operations while
|
||||
* the join clause may not (if there is a cross-type mergejoin
|
||||
* operator available for the two column types).
|
||||
* Is it OK to strip implicit coercions from the COALESCE
|
||||
* arguments? What of the sortops in such cases?
|
||||
*/
|
||||
if (IsA(cexpr, CoalesceExpr) &&
|
||||
list_length(cexpr->args) == 2 &&
|
||||
equal(leftop, (Node *) linitial(cexpr->args)) &&
|
||||
equal(rightop, (Node *) lsecond(cexpr->args)) &&
|
||||
rinfo->left_sortop == item1->sortop &&
|
||||
rinfo->right_sortop == item1->sortop)
|
||||
{
|
||||
/*
|
||||
* Yes, so find constant member(s) of set and generate
|
||||
* implied LEFTVAR = CONSTANT
|
||||
*/
|
||||
process_implied_const_eq(root, equi_key_set, relids,
|
||||
leftop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->left_relids,
|
||||
false);
|
||||
/* ... and RIGHTVAR = CONSTANT */
|
||||
process_implied_const_eq(root, equi_key_set, relids,
|
||||
rightop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->right_relids,
|
||||
false);
|
||||
/* ... and remove COALESCE() = CONSTANT */
|
||||
process_implied_const_eq(root, equi_key_set, relids,
|
||||
item1->key,
|
||||
item1->sortop,
|
||||
relids[i1],
|
||||
true);
|
||||
/*
|
||||
* We can remove the explicit outer join qual, too,
|
||||
* since we now have tests forcing each of its sides
|
||||
* to the same value.
|
||||
*/
|
||||
process_implied_equality(root,
|
||||
leftop,
|
||||
rightop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->left_relids,
|
||||
rinfo->right_relids,
|
||||
true);
|
||||
|
||||
/* No need to match against remaining set members */
|
||||
break;
|
||||
}
|
||||
i1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* process_implied_const_eq
|
||||
* Apply process_implied_equality with the given item and each
|
||||
* pseudoconstant member of equi_key_set.
|
||||
*
|
||||
* This is just a subroutine to save some cruft in
|
||||
* generate_outer_join_implications. equi_key_set and relids are as in
|
||||
* generate_outer_join_implications, the other parameters as for
|
||||
* process_implied_equality.
|
||||
*/
|
||||
static void
|
||||
process_implied_const_eq(PlannerInfo *root, List *equi_key_set, Relids *relids,
|
||||
Node *item1, Oid sortop1, Relids item1_relids,
|
||||
bool delete_it)
|
||||
{
|
||||
ListCell *l;
|
||||
bool found = false;
|
||||
int i = 0;
|
||||
|
||||
foreach(l, equi_key_set)
|
||||
{
|
||||
PathKeyItem *item2 = (PathKeyItem *) lfirst(l);
|
||||
|
||||
if (bms_is_empty(relids[i]))
|
||||
{
|
||||
process_implied_equality(root,
|
||||
item1, item2->key,
|
||||
sortop1, item2->sortop,
|
||||
item1_relids, NULL,
|
||||
delete_it);
|
||||
found = true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
/* Caller screwed up if no constants in list */
|
||||
Assert(found);
|
||||
}
|
||||
|
||||
/*
|
||||
* exprs_known_equal
|
||||
* Detect whether two expressions are known equal due to equijoin clauses.
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.192 2005/06/10 22:25:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.193 2005/07/02 23:00:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1176,8 +1176,7 @@ create_nestloop_plan(PlannerInfo *root,
|
||||
List *bitmapclauses;
|
||||
|
||||
bitmapclauses =
|
||||
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
|
||||
true, true);
|
||||
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true);
|
||||
joinrestrictclauses =
|
||||
select_nonredundant_join_clauses(root,
|
||||
joinrestrictclauses,
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.107 2005/06/09 04:18:59 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.108 2005/07/02 23:00:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -374,8 +374,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
Relids qualscope)
|
||||
{
|
||||
Relids relids;
|
||||
bool valid_everywhere;
|
||||
bool can_be_equijoin;
|
||||
bool maybe_equijoin;
|
||||
bool maybe_outer_join;
|
||||
RestrictInfo *restrictinfo;
|
||||
RelOptInfo *rel;
|
||||
List *vars;
|
||||
@ -409,14 +409,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
if (isdeduced)
|
||||
{
|
||||
/*
|
||||
* If the qual came from implied-equality deduction, we can
|
||||
* evaluate the qual at its natural semantic level. It is not
|
||||
* affected by any outer-join rules (else we'd not have decided
|
||||
* the vars were equal).
|
||||
* If the qual came from implied-equality deduction, we always
|
||||
* evaluate the qual at its natural semantic level. It is the
|
||||
* responsibility of the deducer not to create any quals that
|
||||
* should be delayed by outer-join rules.
|
||||
*/
|
||||
Assert(bms_equal(relids, qualscope));
|
||||
valid_everywhere = true;
|
||||
can_be_equijoin = true;
|
||||
/* Needn't feed it back for more deductions */
|
||||
maybe_equijoin = false;
|
||||
maybe_outer_join = false;
|
||||
}
|
||||
else if (bms_overlap(relids, outerjoin_nonnullable))
|
||||
{
|
||||
@ -434,8 +435,14 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
* result, so we treat it the same as an ordinary inner-join qual.
|
||||
*/
|
||||
relids = qualscope;
|
||||
valid_everywhere = false;
|
||||
can_be_equijoin = false;
|
||||
/*
|
||||
* We can't use such a clause to deduce equijoin (the left and
|
||||
* right sides might be unequal above the join because one of
|
||||
* them has gone to NULL) ... but we might be able to use it
|
||||
* for more limited purposes.
|
||||
*/
|
||||
maybe_equijoin = false;
|
||||
maybe_outer_join = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -449,34 +456,25 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
* time we are called, the outerjoinset of each baserel will show
|
||||
* exactly those outer joins that are below the qual in the join
|
||||
* tree.
|
||||
*
|
||||
* We also need to determine whether the qual is "valid everywhere",
|
||||
* which is true if the qual mentions no variables that are
|
||||
* involved in lower-level outer joins (this may be an overly
|
||||
* strong test).
|
||||
*/
|
||||
Relids addrelids = NULL;
|
||||
Relids tmprelids;
|
||||
int relno;
|
||||
|
||||
valid_everywhere = true;
|
||||
tmprelids = bms_copy(relids);
|
||||
while ((relno = bms_first_member(tmprelids)) >= 0)
|
||||
{
|
||||
RelOptInfo *rel = find_base_rel(root, relno);
|
||||
|
||||
if (rel->outerjoinset != NULL)
|
||||
{
|
||||
addrelids = bms_add_members(addrelids, rel->outerjoinset);
|
||||
valid_everywhere = false;
|
||||
}
|
||||
}
|
||||
bms_free(tmprelids);
|
||||
|
||||
if (bms_is_subset(addrelids, relids))
|
||||
{
|
||||
/* Qual is not affected by any outer-join restriction */
|
||||
can_be_equijoin = true;
|
||||
maybe_equijoin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -488,9 +486,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
* Because application of the qual will be delayed by outer
|
||||
* join, we mustn't assume its vars are equal everywhere.
|
||||
*/
|
||||
can_be_equijoin = false;
|
||||
maybe_equijoin = false;
|
||||
}
|
||||
bms_free(addrelids);
|
||||
maybe_outer_join = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -508,7 +507,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
*/
|
||||
restrictinfo = make_restrictinfo((Expr *) clause,
|
||||
is_pushed_down,
|
||||
valid_everywhere,
|
||||
relids);
|
||||
|
||||
/*
|
||||
@ -533,8 +531,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
* allows us to consider z and q equal after their rels are
|
||||
* joined.
|
||||
*/
|
||||
if (can_be_equijoin)
|
||||
check_mergejoinable(restrictinfo);
|
||||
check_mergejoinable(restrictinfo);
|
||||
|
||||
/*
|
||||
* If the clause was deduced from implied equality, check to
|
||||
@ -601,18 +598,60 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
}
|
||||
|
||||
/*
|
||||
* If the clause has a mergejoinable operator, and is not an
|
||||
* outer-join qualification nor bubbled up due to an outer join, then
|
||||
* the two sides represent equivalent PathKeyItems for path keys: any
|
||||
* path that is sorted by one side will also be sorted by the other
|
||||
* (as soon as the two rels are joined, that is). Record the key
|
||||
* equivalence for future use. (We can skip this for a deduced
|
||||
* clause, since the keys are already known equivalent in that case.)
|
||||
* If the clause has a mergejoinable operator, we may be able to
|
||||
* deduce more things from it under the principle of transitivity.
|
||||
*
|
||||
* If it is not an outer-join qualification nor bubbled up due to an outer
|
||||
* join, then the two sides represent equivalent PathKeyItems for path
|
||||
* keys: any path that is sorted by one side will also be sorted by the
|
||||
* other (as soon as the two rels are joined, that is). Pass such clauses
|
||||
* to add_equijoined_keys.
|
||||
*
|
||||
* If it is a left or right outer-join qualification that relates the two
|
||||
* sides of the outer join (no funny business like leftvar1 = leftvar2 +
|
||||
* rightvar), we add it to root->left_join_clauses or
|
||||
* root->right_join_clauses according to which side the nonnullable
|
||||
* variable appears on.
|
||||
*
|
||||
* If it is a full outer-join qualification, we add it to
|
||||
* root->full_join_clauses. (Ideally we'd discard cases that aren't
|
||||
* leftvar = rightvar, as we do for left/right joins, but this routine
|
||||
* doesn't have the info needed to do that; and the current usage of the
|
||||
* full_join_clauses list doesn't require that, so it's not currently
|
||||
* worth complicating this routine's API to make it possible.)
|
||||
*/
|
||||
if (can_be_equijoin &&
|
||||
restrictinfo->mergejoinoperator != InvalidOid &&
|
||||
!isdeduced)
|
||||
add_equijoined_keys(root, restrictinfo);
|
||||
if (restrictinfo->mergejoinoperator != InvalidOid)
|
||||
{
|
||||
if (maybe_equijoin)
|
||||
add_equijoined_keys(root, restrictinfo);
|
||||
else if (maybe_outer_join && restrictinfo->can_join)
|
||||
{
|
||||
if (bms_is_subset(restrictinfo->left_relids,
|
||||
outerjoin_nonnullable) &&
|
||||
!bms_overlap(restrictinfo->right_relids,
|
||||
outerjoin_nonnullable))
|
||||
{
|
||||
/* we have outervar = innervar */
|
||||
root->left_join_clauses = lappend(root->left_join_clauses,
|
||||
restrictinfo);
|
||||
}
|
||||
else if (bms_is_subset(restrictinfo->right_relids,
|
||||
outerjoin_nonnullable) &&
|
||||
!bms_overlap(restrictinfo->left_relids,
|
||||
outerjoin_nonnullable))
|
||||
{
|
||||
/* we have innervar = outervar */
|
||||
root->right_join_clauses = lappend(root->right_join_clauses,
|
||||
restrictinfo);
|
||||
}
|
||||
else if (bms_equal(outerjoin_nonnullable, qualscope))
|
||||
{
|
||||
/* FULL JOIN (above tests cannot match in this case) */
|
||||
root->full_join_clauses = lappend(root->full_join_clauses,
|
||||
restrictinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.85 2005/06/10 03:32:23 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.86 2005/07/02 23:00:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -121,6 +121,9 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
|
||||
root->join_rel_list = NIL;
|
||||
root->join_rel_hash = NULL;
|
||||
root->equi_key_list = NIL;
|
||||
root->left_join_clauses = NIL;
|
||||
root->right_join_clauses = NIL;
|
||||
root->full_join_clauses = NIL;
|
||||
|
||||
/*
|
||||
* Construct RelOptInfo nodes for all base relations in query.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.189 2005/06/10 02:21:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.190 2005/07/02 23:00:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -194,7 +194,6 @@ subquery_planner(Query *parse, double tuple_fraction,
|
||||
int saved_planid = PlannerPlanId;
|
||||
PlannerInfo *root;
|
||||
Plan *plan;
|
||||
bool hasOuterJoins;
|
||||
List *newHaving;
|
||||
List *lst;
|
||||
ListCell *l;
|
||||
@ -228,12 +227,16 @@ subquery_planner(Query *parse, double tuple_fraction,
|
||||
/*
|
||||
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we
|
||||
* can avoid the expense of doing flatten_join_alias_vars(). Also
|
||||
* check for outer joins --- if none, we can skip
|
||||
* reduce_outer_joins(). This must be done after we have done
|
||||
* check for outer joins --- if none, we can skip reduce_outer_joins()
|
||||
* and some other processing. This must be done after we have done
|
||||
* pull_up_subqueries, of course.
|
||||
*
|
||||
* Note: if reduce_outer_joins manages to eliminate all outer joins,
|
||||
* root->hasOuterJoins is not reset currently. This is OK since its
|
||||
* purpose is merely to suppress unnecessary processing in simple cases.
|
||||
*/
|
||||
root->hasJoinRTEs = false;
|
||||
hasOuterJoins = false;
|
||||
root->hasOuterJoins = false;
|
||||
foreach(l, parse->rtable)
|
||||
{
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
||||
@ -243,7 +246,7 @@ subquery_planner(Query *parse, double tuple_fraction,
|
||||
root->hasJoinRTEs = true;
|
||||
if (IS_OUTER_JOIN(rte->jointype))
|
||||
{
|
||||
hasOuterJoins = true;
|
||||
root->hasOuterJoins = true;
|
||||
/* Can quit scanning once we find an outer join */
|
||||
break;
|
||||
}
|
||||
@ -347,7 +350,7 @@ subquery_planner(Query *parse, double tuple_fraction,
|
||||
* joins. This step is most easily done after we've done expression
|
||||
* preprocessing.
|
||||
*/
|
||||
if (hasOuterJoins)
|
||||
if (root->hasOuterJoins)
|
||||
reduce_outer_joins(root);
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.37 2005/06/09 04:19:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.38 2005/07/02 23:00:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,11 +24,9 @@
|
||||
static RestrictInfo *make_restrictinfo_internal(Expr *clause,
|
||||
Expr *orclause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere,
|
||||
Relids required_relids);
|
||||
static Expr *make_sub_restrictinfos(Expr *clause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
bool is_pushed_down);
|
||||
static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
|
||||
RestrictInfo *rinfo,
|
||||
List *reference_list,
|
||||
@ -40,8 +38,8 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
|
||||
*
|
||||
* Build a RestrictInfo node containing the given subexpression.
|
||||
*
|
||||
* The is_pushed_down and valid_everywhere flags must be supplied by the
|
||||
* caller. required_relids can be NULL, in which case it defaults to the
|
||||
* The is_pushed_down flag must be supplied by the 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
|
||||
@ -49,23 +47,19 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
|
||||
* later.
|
||||
*/
|
||||
RestrictInfo *
|
||||
make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere,
|
||||
Relids required_relids)
|
||||
make_restrictinfo(Expr *clause, bool is_pushed_down, Relids required_relids)
|
||||
{
|
||||
/*
|
||||
* If it's an OR clause, build a modified copy with RestrictInfos
|
||||
* inserted above each subclause of the top-level AND/OR structure.
|
||||
*/
|
||||
if (or_clause((Node *) clause))
|
||||
return (RestrictInfo *) make_sub_restrictinfos(clause,
|
||||
is_pushed_down,
|
||||
valid_everywhere);
|
||||
return (RestrictInfo *) make_sub_restrictinfos(clause, is_pushed_down);
|
||||
|
||||
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
|
||||
Assert(!and_clause((Node *) clause));
|
||||
|
||||
return make_restrictinfo_internal(clause, NULL,
|
||||
is_pushed_down, valid_everywhere,
|
||||
return make_restrictinfo_internal(clause, NULL, is_pushed_down,
|
||||
required_relids);
|
||||
}
|
||||
|
||||
@ -84,9 +78,7 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere,
|
||||
* a specialized routine to allow sharing of RestrictInfos.
|
||||
*/
|
||||
List *
|
||||
make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere)
|
||||
make_restrictinfo_from_bitmapqual(Path *bitmapqual, bool is_pushed_down)
|
||||
{
|
||||
List *result;
|
||||
|
||||
@ -101,8 +93,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
List *sublist;
|
||||
|
||||
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
|
||||
is_pushed_down,
|
||||
valid_everywhere);
|
||||
is_pushed_down);
|
||||
result = list_concat(result, sublist);
|
||||
}
|
||||
}
|
||||
@ -118,8 +109,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
List *sublist;
|
||||
|
||||
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
|
||||
is_pushed_down,
|
||||
valid_everywhere);
|
||||
is_pushed_down);
|
||||
if (sublist == NIL)
|
||||
{
|
||||
/* constant TRUE input yields constant TRUE OR result */
|
||||
@ -137,7 +127,6 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
list_make1(make_restrictinfo_internal(make_orclause(withoutris),
|
||||
make_orclause(withris),
|
||||
is_pushed_down,
|
||||
valid_everywhere,
|
||||
NULL));
|
||||
}
|
||||
else if (IsA(bitmapqual, IndexPath))
|
||||
@ -162,15 +151,13 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
*/
|
||||
static RestrictInfo *
|
||||
make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
bool is_pushed_down, bool valid_everywhere,
|
||||
Relids required_relids)
|
||||
bool is_pushed_down, Relids required_relids)
|
||||
{
|
||||
RestrictInfo *restrictinfo = makeNode(RestrictInfo);
|
||||
|
||||
restrictinfo->clause = clause;
|
||||
restrictinfo->orclause = orclause;
|
||||
restrictinfo->is_pushed_down = is_pushed_down;
|
||||
restrictinfo->valid_everywhere = valid_everywhere;
|
||||
restrictinfo->can_join = false; /* may get set below */
|
||||
|
||||
/*
|
||||
@ -250,8 +237,7 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
* simple clauses are valid RestrictInfos.
|
||||
*/
|
||||
static Expr *
|
||||
make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
|
||||
bool valid_everywhere)
|
||||
make_sub_restrictinfos(Expr *clause, bool is_pushed_down)
|
||||
{
|
||||
if (or_clause((Node *) clause))
|
||||
{
|
||||
@ -261,12 +247,10 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
|
||||
foreach(temp, ((BoolExpr *) clause)->args)
|
||||
orlist = lappend(orlist,
|
||||
make_sub_restrictinfos(lfirst(temp),
|
||||
is_pushed_down,
|
||||
valid_everywhere));
|
||||
is_pushed_down));
|
||||
return (Expr *) make_restrictinfo_internal(clause,
|
||||
make_orclause(orlist),
|
||||
is_pushed_down,
|
||||
valid_everywhere,
|
||||
NULL);
|
||||
}
|
||||
else if (and_clause((Node *) clause))
|
||||
@ -277,15 +261,13 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
|
||||
foreach(temp, ((BoolExpr *) clause)->args)
|
||||
andlist = lappend(andlist,
|
||||
make_sub_restrictinfos(lfirst(temp),
|
||||
is_pushed_down,
|
||||
valid_everywhere));
|
||||
is_pushed_down));
|
||||
return make_andclause(andlist);
|
||||
}
|
||||
else
|
||||
return (Expr *) make_restrictinfo_internal(clause,
|
||||
NULL,
|
||||
is_pushed_down,
|
||||
valid_everywhere,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.115 2005/06/13 23:14:49 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.116 2005/07/02 23:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -87,6 +87,15 @@ typedef struct PlannerInfo
|
||||
List *equi_key_list; /* list of lists of equijoined
|
||||
* PathKeyItems */
|
||||
|
||||
List *left_join_clauses; /* list of RestrictInfos for outer join
|
||||
* clauses w/nonnullable var on left */
|
||||
|
||||
List *right_join_clauses; /* list of RestrictInfos for outer join
|
||||
* clauses w/nonnullable var on right */
|
||||
|
||||
List *full_join_clauses; /* list of RestrictInfos for full outer
|
||||
* join clauses */
|
||||
|
||||
List *in_info_list; /* list of InClauseInfos */
|
||||
|
||||
List *query_pathkeys; /* desired pathkeys for query_planner(),
|
||||
@ -95,6 +104,7 @@ typedef struct PlannerInfo
|
||||
double tuple_fraction; /* tuple_fraction passed to query_planner */
|
||||
|
||||
bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */
|
||||
bool hasOuterJoins; /* true if any RTEs are outer joins */
|
||||
bool hasHavingQual; /* true if havingQual was non-null */
|
||||
} PlannerInfo;
|
||||
|
||||
@ -695,10 +705,6 @@ typedef struct HashPath
|
||||
* joined, will also have is_pushed_down set because it will get attached to
|
||||
* some lower joinrel.
|
||||
*
|
||||
* 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
|
||||
* asserts can be presumed true throughout the plan tree.
|
||||
*
|
||||
* In general, the referenced clause might be arbitrarily complex. The
|
||||
* kinds of clauses we can handle as indexscan quals, mergejoin clauses,
|
||||
* or hashjoin clauses are fairly limited --- the code for each kind of
|
||||
@ -725,8 +731,6 @@ typedef struct RestrictInfo
|
||||
|
||||
bool is_pushed_down; /* TRUE if clause was pushed down in level */
|
||||
|
||||
bool valid_everywhere; /* TRUE if valid on every level */
|
||||
|
||||
/*
|
||||
* This flag is set true if the clause looks potentially useful as a
|
||||
* merge or hash join clause, that is if it is a binary opclause with
|
||||
|
@ -7,7 +7,7 @@
|
||||
* 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.31 2005/06/09 04:19:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.32 2005/07/02 23:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,11 +19,9 @@
|
||||
|
||||
extern RestrictInfo *make_restrictinfo(Expr *clause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere,
|
||||
Relids required_relids);
|
||||
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
bool is_pushed_down);
|
||||
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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user