1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* initsplan.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Target list, qualification, joininfo initialization routines
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2013-01-01 23:15:01 +01:00
|
|
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/optimizer/plan/initsplan.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2001-05-07 02:43:27 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1998-08-10 04:26:40 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2010-10-31 02:55:20 +01:00
|
|
|
#include "nodes/nodeFuncs.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "optimizer/clauses.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "optimizer/joininfo.h"
|
|
|
|
#include "optimizer/pathnode.h"
|
2000-02-15 21:49:31 +01:00
|
|
|
#include "optimizer/paths.h"
|
2008-10-21 22:42:53 +02:00
|
|
|
#include "optimizer/placeholder.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "optimizer/planmain.h"
|
2012-08-27 04:48:55 +02:00
|
|
|
#include "optimizer/planner.h"
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
#include "optimizer/prep.h"
|
2004-01-04 01:07:32 +01:00
|
|
|
#include "optimizer/restrictinfo.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "optimizer/var.h"
|
2012-08-27 04:48:55 +02:00
|
|
|
#include "rewrite/rewriteManip.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/lsyscache.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
/* These parameters are set by GUC */
|
|
|
|
int from_collapse_limit;
|
|
|
|
int join_collapse_limit;
|
|
|
|
|
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel,
|
|
|
|
Index rtindex);
|
|
|
|
static void add_lateral_info(PlannerInfo *root, Index rhs, Relids lhs);
|
2005-12-20 03:30:36 +01:00
|
|
|
static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
|
2007-08-31 03:44:06 +02:00
|
|
|
bool below_outer_join,
|
|
|
|
Relids *qualscope, Relids *inner_join_rels);
|
2008-08-14 20:48:00 +02:00
|
|
|
static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root,
|
2006-10-04 02:30:14 +02:00
|
|
|
Relids left_rels, Relids right_rels,
|
2007-08-31 03:44:06 +02:00
|
|
|
Relids inner_join_rels,
|
2008-08-14 20:48:00 +02:00
|
|
|
JoinType jointype, List *clause);
|
2005-06-06 00:32:58 +02:00
|
|
|
static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
2005-09-28 23:17:02 +02:00
|
|
|
bool is_deduced,
|
|
|
|
bool below_outer_join,
|
2008-10-25 21:51:32 +02:00
|
|
|
JoinType jointype,
|
2005-12-20 03:30:36 +01:00
|
|
|
Relids qualscope,
|
|
|
|
Relids ojscope,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
Relids outerjoin_nonnullable,
|
|
|
|
Relids deduced_nullable_relids);
|
2007-05-23 01:23:58 +02:00
|
|
|
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
|
2009-04-16 22:42:16 +02:00
|
|
|
Relids *nullable_relids_p, bool is_pushed_down);
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
static bool check_equivalence_delay(PlannerInfo *root,
|
|
|
|
RestrictInfo *restrictinfo);
|
2008-08-14 20:48:00 +02:00
|
|
|
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
|
1999-08-16 04:17:58 +02:00
|
|
|
static void check_mergejoinable(RestrictInfo *restrictinfo);
|
|
|
|
static void check_hashjoinable(RestrictInfo *restrictinfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2002-03-12 01:52:10 +01:00
|
|
|
* JOIN TREES
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2002-03-12 01:52:10 +01:00
|
|
|
* add_base_rels_to_query
|
|
|
|
*
|
|
|
|
* Scan the query's jointree and create baserel RelOptInfos for all
|
2003-01-15 20:35:48 +01:00
|
|
|
* the base relations (ie, table, subquery, and function RTEs)
|
|
|
|
* appearing in the jointree.
|
1999-10-07 06:23:24 +02:00
|
|
|
*
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
* The initial invocation must pass root->parse->jointree as the value of
|
2006-10-04 02:30:14 +02:00
|
|
|
* jtnode. Internally, the function recurses through the jointree.
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
*
|
2002-03-12 01:52:10 +01:00
|
|
|
* At the end of this process, there should be one baserel RelOptInfo for
|
|
|
|
* every non-join RTE that is used in the query. Therefore, this routine
|
2006-01-31 22:39:25 +01:00
|
|
|
* is the only place that should call build_simple_rel with reloptkind
|
2006-10-04 02:30:14 +02:00
|
|
|
* RELOPT_BASEREL. (Note: build_simple_rel recurses internally to build
|
2006-09-20 00:49:53 +02:00
|
|
|
* "other rel" RelOptInfos for the members of any appendrels we find here.)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2003-01-15 20:35:48 +01:00
|
|
|
void
|
2005-06-06 00:32:58 +02:00
|
|
|
add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-09-12 23:07:18 +02:00
|
|
|
if (jtnode == NULL)
|
2003-01-15 20:35:48 +01:00
|
|
|
return;
|
2000-09-29 20:21:41 +02:00
|
|
|
if (IsA(jtnode, RangeTblRef))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-09-29 20:21:41 +02:00
|
|
|
int varno = ((RangeTblRef *) jtnode)->rtindex;
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2006-01-31 22:39:25 +01:00
|
|
|
(void) build_simple_rel(root, varno, RELOPT_BASEREL);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2000-09-29 20:21:41 +02:00
|
|
|
else if (IsA(jtnode, FromExpr))
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2000-09-29 20:21:41 +02:00
|
|
|
FromExpr *f = (FromExpr *) jtnode;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
1999-08-10 05:00:15 +02:00
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
foreach(l, f->fromlist)
|
2003-01-15 20:35:48 +01:00
|
|
|
add_base_rels_to_query(root, lfirst(l));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
else if (IsA(jtnode, JoinExpr))
|
|
|
|
{
|
|
|
|
JoinExpr *j = (JoinExpr *) jtnode;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2003-01-15 20:35:48 +01:00
|
|
|
add_base_rels_to_query(root, j->larg);
|
|
|
|
add_base_rels_to_query(root, j->rarg);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(jtnode));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-07-24 05:11:01 +02:00
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* TARGET LISTS
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* build_base_rel_tlists
|
2003-06-30 01:05:05 +02:00
|
|
|
* Add targetlist entries for each var needed in the query's final tlist
|
|
|
|
* to the appropriate base relations.
|
|
|
|
*
|
|
|
|
* We mark such vars as needed by "relation 0" to ensure that they will
|
|
|
|
* propagate up through all join plan steps.
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
|
|
|
void
|
2005-06-06 00:32:58 +02:00
|
|
|
build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
|
2002-03-12 01:52:10 +01:00
|
|
|
{
|
2009-04-19 21:46:33 +02:00
|
|
|
List *tlist_vars = pull_var_clause((Node *) final_tlist,
|
Avoid listing ungrouped Vars in the targetlist of Agg-underneath-Window.
Regular aggregate functions in combination with, or within the arguments
of, window functions are OK per spec; they have the semantics that the
aggregate output rows are computed and then we run the window functions
over that row set. (Thus, this combination is not really useful unless
there's a GROUP BY so that more than one aggregate output row is possible.)
The case without GROUP BY could fail, as recently reported by Jeff Davis,
because sloppy construction of the Agg node's targetlist resulted in extra
references to possibly-ungrouped Vars appearing outside the aggregate
function calls themselves. See the added regression test case for an
example.
Fixing this requires modifying the API of flatten_tlist and its underlying
function pull_var_clause. I chose to make pull_var_clause's API for
aggregates identical to what it was already doing for placeholders, since
the useful behaviors turn out to be the same (error, report node as-is, or
recurse into it). I also tightened the error checking in this area a bit:
if it was ever valid to see an uplevel Var, Aggref, or PlaceHolderVar here,
that was a long time ago, so complain instead of ignoring them.
Backpatch into 9.1. The failure exists in 8.4 and 9.0 as well, but seeing
that it only occurs in a basically-useless corner case, it doesn't seem
worth the risks of changing a function API in a minor release. There might
be third-party code using pull_var_clause.
2011-07-13 00:23:55 +02:00
|
|
|
PVC_RECURSE_AGGREGATES,
|
2009-04-19 21:46:33 +02:00
|
|
|
PVC_INCLUDE_PLACEHOLDERS);
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2003-06-30 01:05:05 +02:00
|
|
|
if (tlist_vars != NIL)
|
|
|
|
{
|
2011-08-09 06:48:51 +02:00
|
|
|
add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
|
2004-05-31 01:40:41 +02:00
|
|
|
list_free(tlist_vars);
|
2003-06-30 01:05:05 +02:00
|
|
|
}
|
2002-03-12 01:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add_vars_to_targetlist
|
|
|
|
* For each variable appearing in the list, add it to the owning
|
2003-06-30 01:05:05 +02:00
|
|
|
* relation's targetlist if not already present, and mark the variable
|
|
|
|
* as being needed for the indicated join (or for final output if
|
|
|
|
* where_needed includes "relation 0").
|
2008-10-21 22:42:53 +02:00
|
|
|
*
|
|
|
|
* The list may also contain PlaceHolderVars. These don't necessarily
|
|
|
|
* have a single owning relation; we keep their attr_needed info in
|
2011-08-09 06:48:51 +02:00
|
|
|
* root->placeholder_list instead. If create_new_ph is true, it's OK
|
|
|
|
* to create new PlaceHolderInfos, and we also have to update ph_may_need;
|
|
|
|
* otherwise, the PlaceHolderInfos must already exist, and we should only
|
|
|
|
* update their ph_needed. (It should be true before deconstruct_jointree
|
|
|
|
* begins, and false after that.)
|
2002-03-12 01:52:10 +01:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
void
|
2011-08-09 06:48:51 +02:00
|
|
|
add_vars_to_targetlist(PlannerInfo *root, List *vars,
|
|
|
|
Relids where_needed, bool create_new_ph)
|
2002-03-12 01:52:10 +01:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *temp;
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2003-06-30 01:05:05 +02:00
|
|
|
Assert(!bms_is_empty(where_needed));
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
foreach(temp, vars)
|
|
|
|
{
|
2008-10-21 22:42:53 +02:00
|
|
|
Node *node = (Node *) lfirst(temp);
|
|
|
|
|
|
|
|
if (IsA(node, Var))
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
|
|
|
RelOptInfo *rel = find_base_rel(root, var->varno);
|
|
|
|
int attno = var->varattno;
|
2002-03-12 01:52:10 +01:00
|
|
|
|
2008-10-21 22:42:53 +02:00
|
|
|
Assert(attno >= rel->min_attr && attno <= rel->max_attr);
|
|
|
|
attno -= rel->min_attr;
|
|
|
|
if (rel->attr_needed[attno] == NULL)
|
|
|
|
{
|
|
|
|
/* Variable not yet requested, so add to reltargetlist */
|
|
|
|
/* XXX is copyObject necessary here? */
|
|
|
|
rel->reltargetlist = lappend(rel->reltargetlist,
|
|
|
|
copyObject(var));
|
|
|
|
}
|
|
|
|
rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
|
|
|
|
where_needed);
|
|
|
|
}
|
|
|
|
else if (IsA(node, PlaceHolderVar))
|
2003-06-30 01:05:05 +02:00
|
|
|
{
|
2008-10-21 22:42:53 +02:00
|
|
|
PlaceHolderVar *phv = (PlaceHolderVar *) node;
|
2011-08-09 06:48:51 +02:00
|
|
|
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
|
|
|
|
create_new_ph);
|
2008-10-21 22:42:53 +02:00
|
|
|
|
2011-08-09 06:48:51 +02:00
|
|
|
/* Always adjust ph_needed */
|
2008-10-21 22:42:53 +02:00
|
|
|
phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
|
|
|
|
where_needed);
|
2011-04-10 17:42:00 +02:00
|
|
|
|
2010-09-28 18:08:56 +02:00
|
|
|
/*
|
2012-06-10 21:20:04 +02:00
|
|
|
* If we are creating PlaceHolderInfos, mark them with the correct
|
|
|
|
* maybe-needed locations. Otherwise, it's too late to change
|
2012-09-01 19:56:14 +02:00
|
|
|
* that, so we'd better not have set ph_needed to more than
|
|
|
|
* ph_may_need.
|
2010-09-28 18:08:56 +02:00
|
|
|
*/
|
2011-08-09 06:48:51 +02:00
|
|
|
if (create_new_ph)
|
|
|
|
mark_placeholder_maybe_needed(root, phinfo, where_needed);
|
2012-09-01 19:56:14 +02:00
|
|
|
else
|
|
|
|
Assert(bms_is_subset(phinfo->ph_needed, phinfo->ph_may_need));
|
2003-06-30 01:05:05 +02:00
|
|
|
}
|
2008-10-21 22:42:53 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
|
2002-03-12 01:52:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* LATERAL REFERENCES
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
2012-08-27 04:48:55 +02:00
|
|
|
* find_lateral_references
|
|
|
|
* For each LATERAL subquery, extract all its references to Vars and
|
|
|
|
* PlaceHolderVars of the current query level, and make sure those values
|
|
|
|
* will be available for evaluation of the subquery.
|
2012-08-08 01:02:54 +02:00
|
|
|
*
|
2012-08-27 04:48:55 +02:00
|
|
|
* While later planning steps ensure that the Var/PHV source rels are on the
|
|
|
|
* outside of nestloops relative to the LATERAL subquery, we also need to
|
|
|
|
* ensure that the Vars/PHVs propagate up to the nestloop join level; this
|
|
|
|
* means setting suitable where_needed values for them.
|
|
|
|
*
|
|
|
|
* This has to run before deconstruct_jointree, since it might result in
|
|
|
|
* creation of PlaceHolderInfos or extension of their ph_may_need sets.
|
2012-08-08 01:02:54 +02:00
|
|
|
*/
|
2012-08-27 04:48:55 +02:00
|
|
|
void
|
|
|
|
find_lateral_references(PlannerInfo *root)
|
|
|
|
{
|
|
|
|
Index rti;
|
|
|
|
|
|
|
|
/* We need do nothing if the query contains no LATERAL RTEs */
|
|
|
|
if (!root->hasLateralRTEs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Examine all baserels (the rel array has been set up by now).
|
|
|
|
*/
|
|
|
|
for (rti = 1; rti < root->simple_rel_array_size; rti++)
|
|
|
|
{
|
|
|
|
RelOptInfo *brel = root->simple_rel_array[rti];
|
|
|
|
|
|
|
|
/* there may be empty slots corresponding to non-baserel RTEs */
|
|
|
|
if (brel == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Assert(brel->relid == rti); /* sanity check on array */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This bit is less obvious than it might look. We ignore appendrel
|
|
|
|
* otherrels and consider only their parent baserels. In a case where
|
|
|
|
* a LATERAL-containing UNION ALL subquery was pulled up, it is the
|
|
|
|
* otherrels that are actually going to be in the plan. However, we
|
|
|
|
* want to mark all their lateral references as needed by the parent,
|
|
|
|
* because it is the parent's relid that will be used for join
|
|
|
|
* planning purposes. And the parent's RTE will contain all the
|
|
|
|
* lateral references we need to know, since the pulled-up members are
|
|
|
|
* nothing but copies of parts of the original RTE's subquery. We
|
|
|
|
* could visit the children instead and transform their references
|
|
|
|
* back to the parent's relid, but it would be much more complicated
|
|
|
|
* for no real gain. (Important here is that the child members have
|
|
|
|
* not yet received any processing beyond being pulled up.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ignore RTEs that are "other rels" */
|
|
|
|
if (brel->reloptkind != RELOPT_BASEREL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
extract_lateral_references(root, brel, rti);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
static void
|
2012-08-27 04:48:55 +02:00
|
|
|
extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
|
2012-08-08 01:02:54 +02:00
|
|
|
{
|
|
|
|
RangeTblEntry *rte = root->simple_rte_array[rtindex];
|
|
|
|
List *vars;
|
|
|
|
List *newvars;
|
|
|
|
Relids where_needed;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
/* No cross-references are possible if it's not LATERAL */
|
|
|
|
if (!rte->lateral)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Fetch the appropriate variables */
|
|
|
|
if (rte->rtekind == RTE_SUBQUERY)
|
|
|
|
vars = pull_vars_of_level((Node *) rte->subquery, 1);
|
|
|
|
else if (rte->rtekind == RTE_FUNCTION)
|
|
|
|
vars = pull_vars_of_level(rte->funcexpr, 0);
|
2012-08-12 22:01:26 +02:00
|
|
|
else if (rte->rtekind == RTE_VALUES)
|
|
|
|
vars = pull_vars_of_level((Node *) rte->values_lists, 0);
|
2012-08-08 01:02:54 +02:00
|
|
|
else
|
2012-08-27 04:48:55 +02:00
|
|
|
{
|
|
|
|
Assert(false);
|
|
|
|
return; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vars == NIL)
|
|
|
|
return; /* nothing to do */
|
2012-08-08 01:02:54 +02:00
|
|
|
|
2012-08-18 20:10:17 +02:00
|
|
|
/* Copy each Var (or PlaceHolderVar) and adjust it to match our level */
|
2012-08-08 01:02:54 +02:00
|
|
|
newvars = NIL;
|
|
|
|
foreach(lc, vars)
|
|
|
|
{
|
2012-08-27 04:48:55 +02:00
|
|
|
Node *node = (Node *) lfirst(lc);
|
2012-08-08 01:02:54 +02:00
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
node = copyObject(node);
|
|
|
|
if (IsA(node, Var))
|
2012-08-18 20:10:17 +02:00
|
|
|
{
|
2012-08-27 04:48:55 +02:00
|
|
|
Var *var = (Var *) node;
|
|
|
|
|
|
|
|
/* Adjustment is easy since it's just one node */
|
|
|
|
var->varlevelsup = 0;
|
2012-08-18 20:10:17 +02:00
|
|
|
}
|
2012-08-27 04:48:55 +02:00
|
|
|
else if (IsA(node, PlaceHolderVar))
|
2012-08-18 20:10:17 +02:00
|
|
|
{
|
2012-08-27 04:48:55 +02:00
|
|
|
PlaceHolderVar *phv = (PlaceHolderVar *) node;
|
|
|
|
int levelsup = phv->phlevelsup;
|
|
|
|
|
|
|
|
/* Have to work harder to adjust the contained expression too */
|
|
|
|
if (levelsup != 0)
|
|
|
|
IncrementVarSublevelsUp(node, -levelsup, 0);
|
|
|
|
|
2012-08-18 20:10:17 +02:00
|
|
|
/*
|
2012-08-27 04:48:55 +02:00
|
|
|
* If we pulled the PHV out of a subquery RTE, its expression
|
|
|
|
* needs to be preprocessed. subquery_planner() already did this
|
|
|
|
* for level-zero PHVs in function and values RTEs, though.
|
2012-08-18 20:10:17 +02:00
|
|
|
*/
|
2012-08-27 04:48:55 +02:00
|
|
|
if (levelsup > 0)
|
|
|
|
phv->phexpr = preprocess_phv_expression(root, phv->phexpr);
|
2012-08-18 20:10:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
Assert(false);
|
2012-08-27 04:48:55 +02:00
|
|
|
newvars = lappend(newvars, node);
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
list_free(vars);
|
|
|
|
|
2012-08-08 01:02:54 +02:00
|
|
|
/*
|
|
|
|
* We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
|
|
|
|
* of a cheat: a more formal approach would be to mark each one as needed
|
|
|
|
* at the join of the LATERAL RTE with its source RTE. But it will work,
|
|
|
|
* and it's much less tedious than computing a separate where_needed for
|
|
|
|
* each Var.
|
|
|
|
*/
|
|
|
|
where_needed = bms_make_singleton(rtindex);
|
|
|
|
|
|
|
|
/* Push the Vars into their source relations' targetlists */
|
2012-08-27 04:48:55 +02:00
|
|
|
add_vars_to_targetlist(root, newvars, where_needed, true);
|
2012-08-08 01:02:54 +02:00
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
/* Remember the lateral references for create_lateral_join_info */
|
|
|
|
brel->lateral_vars = newvars;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create_lateral_join_info
|
|
|
|
* For each LATERAL subquery, create LateralJoinInfo(s) and add them to
|
|
|
|
* root->lateral_info_list, and fill in the per-rel lateral_relids sets.
|
|
|
|
*
|
|
|
|
* This has to run after deconstruct_jointree, because we need to know the
|
|
|
|
* final ph_eval_at values for referenced PlaceHolderVars.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
create_lateral_join_info(PlannerInfo *root)
|
|
|
|
{
|
|
|
|
Index rti;
|
|
|
|
|
|
|
|
/* We need do nothing if the query contains no LATERAL RTEs */
|
|
|
|
if (!root->hasLateralRTEs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Examine all baserels (the rel array has been set up by now).
|
|
|
|
*/
|
|
|
|
for (rti = 1; rti < root->simple_rel_array_size; rti++)
|
|
|
|
{
|
|
|
|
RelOptInfo *brel = root->simple_rel_array[rti];
|
|
|
|
Relids lateral_relids;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
/* there may be empty slots corresponding to non-baserel RTEs */
|
|
|
|
if (brel == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Assert(brel->relid == rti); /* sanity check on array */
|
|
|
|
|
|
|
|
/* ignore RTEs that are "other rels" */
|
|
|
|
if (brel->reloptkind != RELOPT_BASEREL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
lateral_relids = NULL;
|
|
|
|
|
|
|
|
/* consider each laterally-referenced Var or PHV */
|
|
|
|
foreach(lc, brel->lateral_vars)
|
|
|
|
{
|
|
|
|
Node *node = (Node *) lfirst(lc);
|
|
|
|
|
|
|
|
if (IsA(node, Var))
|
|
|
|
{
|
|
|
|
Var *var = (Var *) node;
|
|
|
|
|
|
|
|
add_lateral_info(root, rti, bms_make_singleton(var->varno));
|
|
|
|
lateral_relids = bms_add_member(lateral_relids,
|
|
|
|
var->varno);
|
|
|
|
}
|
|
|
|
else if (IsA(node, PlaceHolderVar))
|
|
|
|
{
|
|
|
|
PlaceHolderVar *phv = (PlaceHolderVar *) node;
|
|
|
|
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
|
|
|
|
false);
|
|
|
|
|
|
|
|
add_lateral_info(root, rti, bms_copy(phinfo->ph_eval_at));
|
|
|
|
lateral_relids = bms_add_members(lateral_relids,
|
|
|
|
phinfo->ph_eval_at);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We now know all the relids needed for lateral refs in this rel */
|
|
|
|
if (bms_is_empty(lateral_relids))
|
|
|
|
continue; /* ensure lateral_relids is NULL if empty */
|
|
|
|
brel->lateral_relids = lateral_relids;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's an appendrel parent, copy its lateral_relids to each child
|
|
|
|
* rel. We intentionally give each child rel the same minimum
|
|
|
|
* parameterization, even though it's quite possible that some don't
|
|
|
|
* reference all the lateral rels. This is because any append path
|
|
|
|
* for the parent will have to have the same parameterization for
|
|
|
|
* every child anyway, and there's no value in forcing extra
|
|
|
|
* reparameterize_path() calls.
|
|
|
|
*/
|
|
|
|
if (root->simple_rte_array[rti]->inh)
|
|
|
|
{
|
|
|
|
foreach(lc, root->append_rel_list)
|
|
|
|
{
|
|
|
|
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
|
|
|
|
RelOptInfo *childrel;
|
|
|
|
|
|
|
|
if (appinfo->parent_relid != rti)
|
|
|
|
continue;
|
|
|
|
childrel = root->simple_rel_array[appinfo->child_relid];
|
|
|
|
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
|
|
|
|
Assert(childrel->lateral_relids == NULL);
|
|
|
|
childrel->lateral_relids = lateral_relids;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add_lateral_info
|
|
|
|
* Add a LateralJoinInfo to root->lateral_info_list, if needed
|
|
|
|
*
|
|
|
|
* We suppress redundant list entries. The passed lhs set must be freshly
|
|
|
|
* made; we free it if not used in a new list entry.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
add_lateral_info(PlannerInfo *root, Index rhs, Relids lhs)
|
|
|
|
{
|
|
|
|
LateralJoinInfo *ljinfo;
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
Assert(!bms_is_member(rhs, lhs));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If an existing list member has the same RHS and an LHS that is a subset
|
|
|
|
* of the new one, it's redundant, but we don't trouble to get rid of it.
|
|
|
|
* The only case that is really worth worrying about is identical entries,
|
|
|
|
* and we handle that well enough with this simple logic.
|
|
|
|
*/
|
|
|
|
foreach(l, root->lateral_info_list)
|
|
|
|
{
|
|
|
|
ljinfo = (LateralJoinInfo *) lfirst(l);
|
|
|
|
if (rhs == ljinfo->lateral_rhs &&
|
|
|
|
bms_is_subset(lhs, ljinfo->lateral_lhs))
|
|
|
|
{
|
|
|
|
bms_free(lhs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not there, so make a new entry */
|
|
|
|
ljinfo = makeNode(LateralJoinInfo);
|
|
|
|
ljinfo->lateral_rhs = rhs;
|
|
|
|
ljinfo->lateral_lhs = lhs;
|
|
|
|
root->lateral_info_list = lappend(root->lateral_info_list, ljinfo);
|
2012-08-08 01:02:54 +02:00
|
|
|
}
|
|
|
|
|
2002-03-12 01:52:10 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2005-12-20 03:30:36 +01:00
|
|
|
* JOIN TREE PROCESSING
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2005-12-20 03:30:36 +01:00
|
|
|
* deconstruct_jointree
|
2000-09-29 20:21:41 +02:00
|
|
|
* Recursively scan the query's join tree for WHERE and JOIN/ON qual
|
2005-06-09 06:19:00 +02:00
|
|
|
* clauses, and add these to the appropriate restrictinfo and joininfo
|
2008-08-14 20:48:00 +02:00
|
|
|
* lists belonging to base RelOptInfos. Also, add SpecialJoinInfo nodes
|
|
|
|
* to root->join_info_list for any outer joins appearing in the query tree.
|
2005-12-20 03:30:36 +01:00
|
|
|
* Return a "joinlist" data structure showing the join order decisions
|
|
|
|
* that need to be made by make_one_rel().
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2005-12-20 03:30:36 +01:00
|
|
|
* The "joinlist" result is a list of items that are either RangeTblRef
|
|
|
|
* jointree nodes or sub-joinlists. All the items at the same level of
|
|
|
|
* joinlist must be joined in an order to be determined by make_one_rel()
|
2008-08-14 20:48:00 +02:00
|
|
|
* (note that legal orders may be constrained by SpecialJoinInfo nodes).
|
2005-12-20 03:30:36 +01:00
|
|
|
* A sub-joinlist represents a subproblem to be planned separately. Currently
|
|
|
|
* sub-joinlists arise only from FULL OUTER JOIN or when collapsing of
|
|
|
|
* subproblems is stopped by join_collapse_limit or from_collapse_limit.
|
2005-09-28 23:17:02 +02:00
|
|
|
*
|
2000-09-12 23:07:18 +02:00
|
|
|
* NOTE: when dealing with inner joins, it is appropriate to let a qual clause
|
|
|
|
* be evaluated at the lowest level where all the variables it mentions are
|
2000-09-29 20:21:41 +02:00
|
|
|
* available. However, we cannot push a qual down into the nullable side(s)
|
|
|
|
* of an outer join since the qual might eliminate matching rows and cause a
|
2006-10-04 02:30:14 +02:00
|
|
|
* NULL row to be incorrectly emitted by the join. Therefore, we artificially
|
2005-12-20 03:30:36 +01:00
|
|
|
* OR the minimum-relids of such an outer join into the required_relids of
|
2006-10-04 02:30:14 +02:00
|
|
|
* clauses appearing above it. This forces those clauses to be delayed until
|
2005-12-20 03:30:36 +01:00
|
|
|
* application of the outer join (or maybe even higher in the join tree).
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
deconstruct_jointree(PlannerInfo *root)
|
|
|
|
{
|
|
|
|
Relids qualscope;
|
2007-08-31 03:44:06 +02:00
|
|
|
Relids inner_join_rels;
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/* Start recursion at top of jointree */
|
|
|
|
Assert(root->parse->jointree != NULL &&
|
|
|
|
IsA(root->parse->jointree, FromExpr));
|
|
|
|
|
|
|
|
return deconstruct_recurse(root, (Node *) root->parse->jointree, false,
|
2007-08-31 03:44:06 +02:00
|
|
|
&qualscope, &inner_join_rels);
|
2005-12-20 03:30:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deconstruct_recurse
|
|
|
|
* One recursion level of deconstruct_jointree processing.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2005-12-20 03:30:36 +01:00
|
|
|
* Inputs:
|
|
|
|
* jtnode is the jointree node to examine
|
|
|
|
* below_outer_join is TRUE if this node is within the nullable side of a
|
|
|
|
* higher-level outer join
|
|
|
|
* Outputs:
|
|
|
|
* *qualscope gets the set of base Relids syntactically included in this
|
|
|
|
* jointree node (do not modify or free this, as it may also be pointed
|
2008-08-14 20:48:00 +02:00
|
|
|
* to by RestrictInfo and SpecialJoinInfo nodes)
|
2007-08-31 03:44:06 +02:00
|
|
|
* *inner_join_rels gets the set of base Relids syntactically included in
|
|
|
|
* inner joins appearing at or below this jointree node (do not modify
|
|
|
|
* or free this, either)
|
2005-12-20 03:30:36 +01:00
|
|
|
* Return value is the appropriate joinlist for this jointree node
|
|
|
|
*
|
2008-08-14 20:48:00 +02:00
|
|
|
* In addition, entries will be added to root->join_info_list for outer joins.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2005-12-20 03:30:36 +01:00
|
|
|
static List *
|
|
|
|
deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
|
2007-08-31 03:44:06 +02:00
|
|
|
Relids *qualscope, Relids *inner_join_rels)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2005-12-20 03:30:36 +01:00
|
|
|
List *joinlist;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
if (jtnode == NULL)
|
2005-12-20 03:30:36 +01:00
|
|
|
{
|
|
|
|
*qualscope = NULL;
|
2007-08-31 03:44:06 +02:00
|
|
|
*inner_join_rels = NULL;
|
2005-12-20 03:30:36 +01:00
|
|
|
return NIL;
|
|
|
|
}
|
2000-09-29 20:21:41 +02:00
|
|
|
if (IsA(jtnode, RangeTblRef))
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2000-09-29 20:21:41 +02:00
|
|
|
int varno = ((RangeTblRef *) jtnode)->rtindex;
|
|
|
|
|
2012-08-27 04:48:55 +02:00
|
|
|
/* No quals to deal with, just return correct result */
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = bms_make_singleton(varno);
|
2007-08-31 03:44:06 +02:00
|
|
|
/* A single baserel does not create an inner join */
|
|
|
|
*inner_join_rels = NULL;
|
2005-12-20 03:30:36 +01:00
|
|
|
joinlist = list_make1(jtnode);
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
|
|
|
else if (IsA(jtnode, FromExpr))
|
|
|
|
{
|
|
|
|
FromExpr *f = (FromExpr *) jtnode;
|
2005-12-20 03:30:36 +01:00
|
|
|
int remaining;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* First, recurse to handle child joins. We collapse subproblems into
|
|
|
|
* a single joinlist whenever the resulting joinlist wouldn't exceed
|
|
|
|
* from_collapse_limit members. Also, always collapse one-element
|
|
|
|
* subproblems, since that won't lengthen the joinlist anyway.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = NULL;
|
2007-08-31 03:44:06 +02:00
|
|
|
*inner_join_rels = NULL;
|
2005-12-20 03:30:36 +01:00
|
|
|
joinlist = NIL;
|
|
|
|
remaining = list_length(f->fromlist);
|
2000-09-29 20:21:41 +02:00
|
|
|
foreach(l, f->fromlist)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
Relids sub_qualscope;
|
|
|
|
List *sub_joinlist;
|
|
|
|
int sub_members;
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
sub_joinlist = deconstruct_recurse(root, lfirst(l),
|
|
|
|
below_outer_join,
|
2007-08-31 03:44:06 +02:00
|
|
|
&sub_qualscope,
|
|
|
|
inner_join_rels);
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = bms_add_members(*qualscope, sub_qualscope);
|
|
|
|
sub_members = list_length(sub_joinlist);
|
|
|
|
remaining--;
|
|
|
|
if (sub_members <= 1 ||
|
|
|
|
list_length(joinlist) + sub_members + remaining <= from_collapse_limit)
|
|
|
|
joinlist = list_concat(joinlist, sub_joinlist);
|
|
|
|
else
|
|
|
|
joinlist = lappend(joinlist, sub_joinlist);
|
2000-09-29 20:21:41 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2007-08-31 03:44:06 +02:00
|
|
|
/*
|
|
|
|
* A FROM with more than one list element is an inner join subsuming
|
2007-11-15 22:14:46 +01:00
|
|
|
* all below it, so we should report inner_join_rels = qualscope. If
|
|
|
|
* there was exactly one element, we should (and already did) report
|
|
|
|
* whatever its inner_join_rels were. If there were no elements (is
|
|
|
|
* that possible?) the initialization before the loop fixed it.
|
2007-08-31 03:44:06 +02:00
|
|
|
*/
|
|
|
|
if (list_length(f->fromlist) > 1)
|
|
|
|
*inner_join_rels = *qualscope;
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
/*
|
2007-02-16 21:57:19 +01:00
|
|
|
* Now process the top-level quals.
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, (List *) f->quals)
|
2008-08-14 20:48:00 +02:00
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Node *qual = (Node *) lfirst(l);
|
2008-08-14 20:48:00 +02:00
|
|
|
|
2009-02-25 04:30:38 +01:00
|
|
|
distribute_qual_to_rels(root, qual,
|
|
|
|
false, below_outer_join, JOIN_INNER,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
*qualscope, NULL, NULL, NULL);
|
2008-08-14 20:48:00 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
else if (IsA(jtnode, JoinExpr))
|
|
|
|
{
|
|
|
|
JoinExpr *j = (JoinExpr *) jtnode;
|
|
|
|
Relids leftids,
|
2003-03-03 00:46:34 +01:00
|
|
|
rightids,
|
2007-08-31 03:44:06 +02:00
|
|
|
left_inners,
|
|
|
|
right_inners,
|
2003-03-03 00:46:34 +01:00
|
|
|
nonnullable_rels,
|
2005-12-20 03:30:36 +01:00
|
|
|
ojscope;
|
|
|
|
List *leftjoinlist,
|
|
|
|
*rightjoinlist;
|
2008-08-14 20:48:00 +02:00
|
|
|
SpecialJoinInfo *sjinfo;
|
|
|
|
ListCell *l;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Order of operations here is subtle and critical. First we recurse
|
|
|
|
* to handle sub-JOINs. Their join quals will be placed without
|
|
|
|
* regard for whether this level is an outer join, which is correct.
|
|
|
|
* Then we place our own join quals, which are restricted by lower
|
|
|
|
* outer joins in any case, and are forced to this level if this is an
|
|
|
|
* outer join and they mention the outer side. Finally, if this is an
|
2008-08-14 20:48:00 +02:00
|
|
|
* outer join, we create a join_info_list entry for the join. This
|
2005-12-20 03:30:36 +01:00
|
|
|
* will prevent quals above us in the join tree that use those rels
|
|
|
|
* from being pushed down below this level. (It's okay for upper
|
|
|
|
* quals to be pushed down to the outer side, however.)
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
|
|
|
switch (j->jointype)
|
|
|
|
{
|
|
|
|
case JOIN_INNER:
|
2005-12-20 03:30:36 +01:00
|
|
|
leftjoinlist = deconstruct_recurse(root, j->larg,
|
|
|
|
below_outer_join,
|
2007-08-31 03:44:06 +02:00
|
|
|
&leftids, &left_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
rightjoinlist = deconstruct_recurse(root, j->rarg,
|
|
|
|
below_outer_join,
|
2007-08-31 03:44:06 +02:00
|
|
|
&rightids, &right_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = bms_union(leftids, rightids);
|
2007-08-31 03:44:06 +02:00
|
|
|
*inner_join_rels = *qualscope;
|
2000-09-12 23:07:18 +02:00
|
|
|
/* Inner join adds no restrictions for quals */
|
2005-09-28 23:17:02 +02:00
|
|
|
nonnullable_rels = NULL;
|
2000-09-12 23:07:18 +02:00
|
|
|
break;
|
|
|
|
case JOIN_LEFT:
|
2008-08-14 20:48:00 +02:00
|
|
|
case JOIN_ANTI:
|
2005-12-20 03:30:36 +01:00
|
|
|
leftjoinlist = deconstruct_recurse(root, j->larg,
|
|
|
|
below_outer_join,
|
2007-08-31 03:44:06 +02:00
|
|
|
&leftids, &left_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
rightjoinlist = deconstruct_recurse(root, j->rarg,
|
|
|
|
true,
|
2007-08-31 03:44:06 +02:00
|
|
|
&rightids, &right_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = bms_union(leftids, rightids);
|
2007-08-31 03:44:06 +02:00
|
|
|
*inner_join_rels = bms_union(left_inners, right_inners);
|
2003-03-03 00:46:34 +01:00
|
|
|
nonnullable_rels = leftids;
|
2000-09-12 23:07:18 +02:00
|
|
|
break;
|
2009-02-25 04:30:38 +01:00
|
|
|
case JOIN_SEMI:
|
|
|
|
leftjoinlist = deconstruct_recurse(root, j->larg,
|
|
|
|
below_outer_join,
|
|
|
|
&leftids, &left_inners);
|
|
|
|
rightjoinlist = deconstruct_recurse(root, j->rarg,
|
|
|
|
below_outer_join,
|
|
|
|
&rightids, &right_inners);
|
|
|
|
*qualscope = bms_union(leftids, rightids);
|
|
|
|
*inner_join_rels = bms_union(left_inners, right_inners);
|
|
|
|
/* Semi join adds no restrictions for quals */
|
|
|
|
nonnullable_rels = NULL;
|
|
|
|
break;
|
2000-09-12 23:07:18 +02:00
|
|
|
case JOIN_FULL:
|
2005-12-20 03:30:36 +01:00
|
|
|
leftjoinlist = deconstruct_recurse(root, j->larg,
|
|
|
|
true,
|
2007-08-31 03:44:06 +02:00
|
|
|
&leftids, &left_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
rightjoinlist = deconstruct_recurse(root, j->rarg,
|
|
|
|
true,
|
2007-08-31 03:44:06 +02:00
|
|
|
&rightids, &right_inners);
|
2005-12-20 03:30:36 +01:00
|
|
|
*qualscope = bms_union(leftids, rightids);
|
2007-08-31 03:44:06 +02:00
|
|
|
*inner_join_rels = bms_union(left_inners, right_inners);
|
2003-03-03 00:46:34 +01:00
|
|
|
/* each side is both outer and inner */
|
2005-12-20 03:30:36 +01:00
|
|
|
nonnullable_rels = *qualscope;
|
2000-09-12 23:07:18 +02:00
|
|
|
break;
|
|
|
|
default:
|
2008-08-14 20:48:00 +02:00
|
|
|
/* JOIN_RIGHT was eliminated during reduce_outer_joins() */
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "unrecognized join type: %d",
|
2000-09-12 23:07:18 +02:00
|
|
|
(int) j->jointype);
|
2005-10-15 04:49:52 +02:00
|
|
|
nonnullable_rels = NULL; /* keep compiler quiet */
|
2005-12-20 03:30:36 +01:00
|
|
|
leftjoinlist = rightjoinlist = NIL;
|
2000-09-12 23:07:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
/*
|
2008-08-14 20:48:00 +02:00
|
|
|
* For an OJ, form the SpecialJoinInfo now, because we need the OJ's
|
2007-02-13 03:31:03 +01:00
|
|
|
* semantic scope (ojscope) to pass to distribute_qual_to_rels. But
|
2008-08-14 20:48:00 +02:00
|
|
|
* we mustn't add it to join_info_list just yet, because we don't want
|
2007-02-13 03:31:03 +01:00
|
|
|
* distribute_qual_to_rels to think it is an outer join below us.
|
2009-02-25 04:30:38 +01:00
|
|
|
*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we
|
|
|
|
* want ojscope = NULL for distribute_qual_to_rels.
|
2005-12-20 03:30:36 +01:00
|
|
|
*/
|
|
|
|
if (j->jointype != JOIN_INNER)
|
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo = make_outerjoininfo(root,
|
2007-08-31 03:44:06 +02:00
|
|
|
leftids, rightids,
|
|
|
|
*inner_join_rels,
|
2008-08-14 20:48:00 +02:00
|
|
|
j->jointype,
|
|
|
|
(List *) j->quals);
|
2009-02-25 04:30:38 +01:00
|
|
|
if (j->jointype == JOIN_SEMI)
|
|
|
|
ojscope = NULL;
|
|
|
|
else
|
|
|
|
ojscope = bms_union(sjinfo->min_lefthand,
|
|
|
|
sjinfo->min_righthand);
|
2005-12-20 03:30:36 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo = NULL;
|
2005-12-20 03:30:36 +01:00
|
|
|
ojscope = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process the qual clauses */
|
2008-08-14 20:48:00 +02:00
|
|
|
foreach(l, (List *) j->quals)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
Node *qual = (Node *) lfirst(l);
|
2008-08-14 20:48:00 +02:00
|
|
|
|
2009-02-25 04:30:38 +01:00
|
|
|
distribute_qual_to_rels(root, qual,
|
|
|
|
false, below_outer_join, j->jointype,
|
|
|
|
*qualscope,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
ojscope, nonnullable_rels, NULL);
|
2008-08-14 20:48:00 +02:00
|
|
|
}
|
2005-12-20 03:30:36 +01:00
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
/* Now we can add the SpecialJoinInfo to join_info_list */
|
|
|
|
if (sjinfo)
|
2010-09-28 18:08:56 +02:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
root->join_info_list = lappend(root->join_info_list, sjinfo);
|
2010-09-28 18:08:56 +02:00
|
|
|
/* Each time we do that, recheck placeholder eval levels */
|
|
|
|
update_placeholder_eval_levels(root, sjinfo);
|
|
|
|
}
|
2003-03-03 00:46:34 +01:00
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
/*
|
|
|
|
* Finally, compute the output joinlist. We fold subproblems together
|
|
|
|
* except at a FULL JOIN or where join_collapse_limit would be
|
|
|
|
* exceeded.
|
|
|
|
*/
|
2007-01-08 17:47:30 +01:00
|
|
|
if (j->jointype == JOIN_FULL)
|
|
|
|
{
|
|
|
|
/* force the join order exactly at this node */
|
|
|
|
joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist));
|
|
|
|
}
|
|
|
|
else if (list_length(leftjoinlist) + list_length(rightjoinlist) <=
|
|
|
|
join_collapse_limit)
|
|
|
|
{
|
|
|
|
/* OK to combine subproblems */
|
2005-12-20 03:30:36 +01:00
|
|
|
joinlist = list_concat(leftjoinlist, rightjoinlist);
|
2007-01-08 17:47:30 +01:00
|
|
|
}
|
2006-10-04 02:30:14 +02:00
|
|
|
else
|
2007-01-08 17:47:30 +01:00
|
|
|
{
|
|
|
|
/* can't combine, but needn't force join order above here */
|
2007-11-15 22:14:46 +01:00
|
|
|
Node *leftpart,
|
|
|
|
*rightpart;
|
2007-01-08 17:47:30 +01:00
|
|
|
|
|
|
|
/* avoid creating useless 1-element sublists */
|
|
|
|
if (list_length(leftjoinlist) == 1)
|
|
|
|
leftpart = (Node *) linitial(leftjoinlist);
|
|
|
|
else
|
|
|
|
leftpart = (Node *) leftjoinlist;
|
|
|
|
if (list_length(rightjoinlist) == 1)
|
|
|
|
rightpart = (Node *) linitial(rightjoinlist);
|
|
|
|
else
|
|
|
|
rightpart = (Node *) rightjoinlist;
|
|
|
|
joinlist = list_make2(leftpart, rightpart);
|
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
else
|
2005-12-20 03:30:36 +01:00
|
|
|
{
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "unrecognized node type: %d",
|
|
|
|
(int) nodeTag(jtnode));
|
2005-12-20 03:30:36 +01:00
|
|
|
joinlist = NIL; /* keep compiler quiet */
|
|
|
|
}
|
|
|
|
return joinlist;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-12-20 03:30:36 +01:00
|
|
|
* make_outerjoininfo
|
2008-08-14 20:48:00 +02:00
|
|
|
* Build a SpecialJoinInfo for the current outer join
|
2005-12-20 03:30:36 +01:00
|
|
|
*
|
|
|
|
* Inputs:
|
|
|
|
* left_rels: the base Relids syntactically on outer side of join
|
|
|
|
* right_rels: the base Relids syntactically on inner side of join
|
2007-08-31 03:44:06 +02:00
|
|
|
* inner_join_rels: base Relids participating in inner joins below this one
|
2008-08-14 20:48:00 +02:00
|
|
|
* jointype: what it says (must always be LEFT, FULL, SEMI, or ANTI)
|
|
|
|
* clause: the outer join's join condition (in implicit-AND format)
|
2005-12-20 03:30:36 +01:00
|
|
|
*
|
2008-08-14 20:48:00 +02:00
|
|
|
* The node should eventually be appended to root->join_info_list, but we
|
2005-12-20 03:30:36 +01:00
|
|
|
* do not do that here.
|
2007-02-13 03:31:03 +01:00
|
|
|
*
|
|
|
|
* Note: we assume that this function is invoked bottom-up, so that
|
2008-08-14 20:48:00 +02:00
|
|
|
* root->join_info_list already contains entries for all outer joins that are
|
2007-08-31 03:44:06 +02:00
|
|
|
* syntactically below this one.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2008-08-14 20:48:00 +02:00
|
|
|
static SpecialJoinInfo *
|
2005-12-20 03:30:36 +01:00
|
|
|
make_outerjoininfo(PlannerInfo *root,
|
|
|
|
Relids left_rels, Relids right_rels,
|
2007-08-31 03:44:06 +02:00
|
|
|
Relids inner_join_rels,
|
2008-08-14 20:48:00 +02:00
|
|
|
JoinType jointype, List *clause)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
SpecialJoinInfo *sjinfo = makeNode(SpecialJoinInfo);
|
2005-12-20 03:30:36 +01:00
|
|
|
Relids clause_relids;
|
|
|
|
Relids strict_relids;
|
2007-08-31 03:44:06 +02:00
|
|
|
Relids min_lefthand;
|
|
|
|
Relids min_righthand;
|
2005-12-20 03:30:36 +01:00
|
|
|
ListCell *l;
|
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
/*
|
|
|
|
* We should not see RIGHT JOIN here because left/right were switched
|
|
|
|
* earlier
|
|
|
|
*/
|
|
|
|
Assert(jointype != JOIN_INNER);
|
|
|
|
Assert(jointype != JOIN_RIGHT);
|
|
|
|
|
2006-09-08 19:49:13 +02:00
|
|
|
/*
|
|
|
|
* Presently the executor cannot support FOR UPDATE/SHARE marking of rels
|
|
|
|
* appearing on the nullable side of an outer join. (It's somewhat unclear
|
|
|
|
* what that would mean, anyway: what should we mark when a result row is
|
|
|
|
* generated from no element of the nullable relation?) So, complain if
|
|
|
|
* any nullable rel is FOR UPDATE/SHARE.
|
|
|
|
*
|
|
|
|
* You might be wondering why this test isn't made far upstream in the
|
2006-10-04 02:30:14 +02:00
|
|
|
* parser. It's because the parser hasn't got enough info --- consider
|
|
|
|
* FOR UPDATE applied to a view. Only after rewriting and flattening do
|
|
|
|
* we know whether the view contains an outer join.
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
*
|
2010-02-26 03:01:40 +01:00
|
|
|
* We use the original RowMarkClause list here; the PlanRowMark list would
|
|
|
|
* list everything.
|
2006-09-08 19:49:13 +02:00
|
|
|
*/
|
|
|
|
foreach(l, root->parse->rowMarks)
|
|
|
|
{
|
|
|
|
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
|
|
|
|
|
|
|
|
if (bms_is_member(rc->rti, right_rels) ||
|
2008-08-14 20:48:00 +02:00
|
|
|
(jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels)))
|
2006-09-08 19:49:13 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join")));
|
|
|
|
}
|
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo->syn_lefthand = left_rels;
|
|
|
|
sjinfo->syn_righthand = right_rels;
|
|
|
|
sjinfo->jointype = jointype;
|
2007-05-23 01:23:58 +02:00
|
|
|
/* this always starts out false */
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo->delay_upper_joins = false;
|
|
|
|
sjinfo->join_quals = clause;
|
2007-05-23 01:23:58 +02:00
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
/* If it's a full join, no need to be very smart */
|
2008-08-14 20:48:00 +02:00
|
|
|
if (jointype == JOIN_FULL)
|
2005-12-20 03:30:36 +01:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo->min_lefthand = bms_copy(left_rels);
|
|
|
|
sjinfo->min_righthand = bms_copy(right_rels);
|
|
|
|
sjinfo->lhs_strict = false; /* don't care about this */
|
|
|
|
return sjinfo;
|
2005-12-20 03:30:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve all relids mentioned within the join clause.
|
|
|
|
*/
|
2008-08-14 20:48:00 +02:00
|
|
|
clause_relids = pull_varnos((Node *) clause);
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For which relids is the clause strict, ie, it cannot succeed if the
|
|
|
|
* rel's columns are all NULL?
|
|
|
|
*/
|
2008-08-14 20:48:00 +02:00
|
|
|
strict_relids = find_nonnullable_rels((Node *) clause);
|
2000-09-12 23:07:18 +02:00
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
/* Remember whether the clause is strict for any LHS relations */
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo->lhs_strict = bms_overlap(strict_relids, left_rels);
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Required LHS always includes the LHS rels mentioned in the clause. We
|
|
|
|
* may have to add more rels based on lower outer joins; see below.
|
2005-12-20 03:30:36 +01:00
|
|
|
*/
|
2007-08-31 03:44:06 +02:00
|
|
|
min_lefthand = bms_intersect(clause_relids, left_rels);
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Similarly for required RHS. But here, we must also include any lower
|
2007-08-31 03:44:06 +02:00
|
|
|
* inner joins, to ensure we don't try to commute with any of them.
|
2005-12-20 03:30:36 +01:00
|
|
|
*/
|
2007-08-31 03:44:06 +02:00
|
|
|
min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
|
|
|
|
right_rels);
|
2005-12-20 03:30:36 +01:00
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
foreach(l, root->join_info_list)
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/* ignore full joins --- other mechanisms preserve their ordering */
|
2008-08-14 20:48:00 +02:00
|
|
|
if (otherinfo->jointype == JOIN_FULL)
|
2005-12-20 03:30:36 +01:00
|
|
|
continue;
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
/*
|
2005-12-20 03:30:36 +01:00
|
|
|
* For a lower OJ in our LHS, if our join condition uses the lower
|
|
|
|
* join's RHS and is not strict for that rel, we must preserve the
|
2007-08-31 03:44:06 +02:00
|
|
|
* ordering of the two OJs, so add lower OJ's full syntactic relset to
|
2007-11-15 22:14:46 +01:00
|
|
|
* min_lefthand. (We must use its full syntactic relset, not just its
|
|
|
|
* min_lefthand + min_righthand. This is because there might be other
|
|
|
|
* OJs below this one that this one can commute with, but we cannot
|
2009-06-11 16:49:15 +02:00
|
|
|
* commute with them if we don't with this one.) Also, if the current
|
2009-07-21 04:02:44 +02:00
|
|
|
* join is a semijoin or antijoin, we must preserve ordering
|
|
|
|
* regardless of strictness.
|
2007-08-31 03:44:06 +02:00
|
|
|
*
|
|
|
|
* Note: I believe we have to insist on being strict for at least one
|
|
|
|
* rel in the lower OJ's min_righthand, not its whole syn_righthand.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2009-02-27 23:41:38 +01:00
|
|
|
if (bms_overlap(left_rels, otherinfo->syn_righthand))
|
2005-12-20 03:30:36 +01:00
|
|
|
{
|
2009-02-27 23:41:38 +01:00
|
|
|
if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
|
2009-07-21 04:02:44 +02:00
|
|
|
(jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
|
2009-02-27 23:41:38 +01:00
|
|
|
!bms_overlap(strict_relids, otherinfo->min_righthand)))
|
|
|
|
{
|
|
|
|
min_lefthand = bms_add_members(min_lefthand,
|
|
|
|
otherinfo->syn_lefthand);
|
|
|
|
min_lefthand = bms_add_members(min_lefthand,
|
|
|
|
otherinfo->syn_righthand);
|
|
|
|
}
|
2005-12-20 03:30:36 +01:00
|
|
|
}
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2001-05-14 22:25:00 +02:00
|
|
|
/*
|
2005-12-20 03:30:36 +01:00
|
|
|
* For a lower OJ in our RHS, if our join condition does not use the
|
|
|
|
* lower join's RHS and the lower OJ's join condition is strict, we
|
2007-11-15 22:14:46 +01:00
|
|
|
* can interchange the ordering of the two OJs; otherwise we must add
|
2009-02-27 23:41:38 +01:00
|
|
|
* lower OJ's full syntactic relset to min_righthand. Here, we must
|
2009-05-07 22:13:09 +02:00
|
|
|
* preserve ordering anyway if either the current join is a semijoin,
|
2009-07-21 04:02:44 +02:00
|
|
|
* or the lower OJ is either a semijoin or an antijoin.
|
2007-05-23 01:23:58 +02:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Here, we have to consider that "our join condition" includes any
|
|
|
|
* clauses that syntactically appeared above the lower OJ and below
|
|
|
|
* ours; those are equivalent to degenerate clauses in our OJ and must
|
|
|
|
* be treated as such. Such clauses obviously can't reference our
|
|
|
|
* LHS, and they must be non-strict for the lower OJ's RHS (else
|
|
|
|
* reduce_outer_joins would have reduced the lower OJ to a plain
|
|
|
|
* join). Hence the other ways in which we handle clauses within our
|
|
|
|
* join condition are not affected by them. The net effect is
|
|
|
|
* therefore sufficiently represented by the delay_upper_joins flag
|
|
|
|
* saved for us by check_outerjoin_delay.
|
2001-05-14 22:25:00 +02:00
|
|
|
*/
|
2007-08-31 03:44:06 +02:00
|
|
|
if (bms_overlap(right_rels, otherinfo->syn_righthand))
|
2001-05-14 22:25:00 +02:00
|
|
|
{
|
2007-08-31 03:44:06 +02:00
|
|
|
if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
|
2009-05-07 22:13:09 +02:00
|
|
|
jointype == JOIN_SEMI ||
|
2009-07-21 04:02:44 +02:00
|
|
|
otherinfo->jointype == JOIN_SEMI ||
|
2009-02-27 23:41:38 +01:00
|
|
|
otherinfo->jointype == JOIN_ANTI ||
|
2007-08-31 03:44:06 +02:00
|
|
|
!otherinfo->lhs_strict || otherinfo->delay_upper_joins)
|
|
|
|
{
|
|
|
|
min_righthand = bms_add_members(min_righthand,
|
|
|
|
otherinfo->syn_lefthand);
|
|
|
|
min_righthand = bms_add_members(min_righthand,
|
|
|
|
otherinfo->syn_righthand);
|
|
|
|
}
|
2001-05-14 22:25:00 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
2005-12-20 03:30:36 +01:00
|
|
|
|
2010-09-28 18:08:56 +02:00
|
|
|
/*
|
|
|
|
* Examine PlaceHolderVars. If a PHV is supposed to be evaluated within
|
|
|
|
* this join's nullable side, and it may get used above this join, then
|
|
|
|
* ensure that min_righthand contains the full eval_at set of the PHV.
|
|
|
|
* This ensures that the PHV actually can be evaluated within the RHS.
|
2011-04-10 17:42:00 +02:00
|
|
|
* Note that this works only because we should already have determined the
|
|
|
|
* final eval_at level for any PHV syntactically within this join.
|
2010-09-28 18:08:56 +02:00
|
|
|
*/
|
|
|
|
foreach(l, root->placeholder_list)
|
|
|
|
{
|
|
|
|
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
|
|
|
|
Relids ph_syn_level = phinfo->ph_var->phrels;
|
|
|
|
|
|
|
|
/* Ignore placeholder if it didn't syntactically come from RHS */
|
|
|
|
if (!bms_is_subset(ph_syn_level, right_rels))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We can also ignore it if it's certainly not used above this join */
|
|
|
|
/* XXX this test is probably overly conservative */
|
|
|
|
if (bms_is_subset(phinfo->ph_may_need, min_righthand))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Else, prevent join from being formed before we eval the PHV */
|
|
|
|
min_righthand = bms_add_members(min_righthand, phinfo->ph_eval_at);
|
|
|
|
}
|
|
|
|
|
2007-08-31 03:44:06 +02:00
|
|
|
/*
|
|
|
|
* If we found nothing to put in min_lefthand, punt and make it the full
|
|
|
|
* LHS, to avoid having an empty min_lefthand which will confuse later
|
|
|
|
* processing. (We don't try to be smart about such cases, just correct.)
|
|
|
|
* Likewise for min_righthand.
|
|
|
|
*/
|
|
|
|
if (bms_is_empty(min_lefthand))
|
|
|
|
min_lefthand = bms_copy(left_rels);
|
|
|
|
if (bms_is_empty(min_righthand))
|
|
|
|
min_righthand = bms_copy(right_rels);
|
|
|
|
|
|
|
|
/* Now they'd better be nonempty */
|
|
|
|
Assert(!bms_is_empty(min_lefthand));
|
|
|
|
Assert(!bms_is_empty(min_righthand));
|
2005-12-20 03:30:36 +01:00
|
|
|
/* Shouldn't overlap either */
|
2007-08-31 03:44:06 +02:00
|
|
|
Assert(!bms_overlap(min_lefthand, min_righthand));
|
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
sjinfo->min_lefthand = min_lefthand;
|
|
|
|
sjinfo->min_righthand = min_righthand;
|
2005-12-20 03:30:36 +01:00
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
return sjinfo;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
2005-12-20 03:30:36 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* QUALIFICATIONS
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2000-09-29 20:21:41 +02:00
|
|
|
* distribute_qual_to_rels
|
2005-06-09 06:19:00 +02:00
|
|
|
* Add clause information to either the baserestrictinfo or joininfo list
|
1999-08-16 04:17:58 +02:00
|
|
|
* (depending on whether the clause is a join) of each base relation
|
2000-04-12 19:17:23 +02:00
|
|
|
* mentioned in the clause. A RestrictInfo node is created and added to
|
2007-01-20 21:45:41 +01:00
|
|
|
* the appropriate list for each rel. Alternatively, if the clause uses a
|
2003-03-03 00:46:34 +01:00
|
|
|
* mergejoinable operator and is not delayed by outer-join rules, enter
|
2007-01-20 21:45:41 +01:00
|
|
|
* the left- and right-side expressions into the query's list of
|
|
|
|
* EquivalenceClasses.
|
2000-09-12 23:07:18 +02:00
|
|
|
*
|
2000-09-29 20:21:41 +02:00
|
|
|
* 'clause': the qual clause to be distributed
|
2005-09-28 23:17:02 +02:00
|
|
|
* 'is_deduced': TRUE if the qual came from implied-equality deduction
|
|
|
|
* 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the
|
2007-01-20 21:45:41 +01:00
|
|
|
* nullable side of a higher-level outer join
|
2008-10-25 21:51:32 +02:00
|
|
|
* 'jointype': type of join the qual is from (JOIN_INNER for a WHERE clause)
|
2005-12-20 03:30:36 +01:00
|
|
|
* 'qualscope': set of baserels the qual's syntactic scope covers
|
|
|
|
* 'ojscope': NULL if not an outer-join qual, else the minimum set of baserels
|
|
|
|
* needed to form this join
|
2003-03-03 00:46:34 +01:00
|
|
|
* 'outerjoin_nonnullable': NULL if not an outer-join qual, else the set of
|
|
|
|
* baserels appearing on the outer (nonnullable) side of the join
|
2005-12-20 03:30:36 +01:00
|
|
|
* (for FULL JOIN this includes both sides of the join, and must in fact
|
|
|
|
* equal qualscope)
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* 'deduced_nullable_relids': if is_deduced is TRUE, the nullable relids to
|
|
|
|
* impute to the clause; otherwise NULL
|
2000-09-29 20:21:41 +02:00
|
|
|
*
|
2005-12-20 03:30:36 +01:00
|
|
|
* 'qualscope' identifies what level of JOIN the qual came from syntactically.
|
|
|
|
* 'ojscope' is needed if we decide to force the qual up to the outer-join
|
|
|
|
* level, which will be ojscope not necessarily qualscope.
|
2009-02-20 01:01:03 +01:00
|
|
|
*
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* In normal use (when is_deduced is FALSE), at the time this is called,
|
|
|
|
* root->join_info_list must contain entries for all and only those special
|
|
|
|
* joins that are syntactically below this qual. But when is_deduced is TRUE,
|
|
|
|
* we are adding new deduced clauses after completion of deconstruct_jointree,
|
|
|
|
* so it cannot be assumed that root->join_info_list has anything to do with
|
|
|
|
* qual placement.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
2005-06-06 00:32:58 +02:00
|
|
|
distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
2005-09-28 23:17:02 +02:00
|
|
|
bool is_deduced,
|
|
|
|
bool below_outer_join,
|
2008-10-25 21:51:32 +02:00
|
|
|
JoinType jointype,
|
2005-12-20 03:30:36 +01:00
|
|
|
Relids qualscope,
|
|
|
|
Relids ojscope,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
Relids outerjoin_nonnullable,
|
|
|
|
Relids deduced_nullable_relids)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-02-18 01:49:48 +01:00
|
|
|
Relids relids;
|
2007-02-16 21:57:19 +01:00
|
|
|
bool is_pushed_down;
|
2005-11-15 00:54:23 +01:00
|
|
|
bool outerjoin_delayed;
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
bool pseudoconstant = false;
|
2007-01-20 21:45:41 +01:00
|
|
|
bool maybe_equivalence;
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
bool maybe_outer_join;
|
2009-04-16 22:42:16 +02:00
|
|
|
Relids nullable_relids;
|
2004-01-04 01:07:32 +01:00
|
|
|
RestrictInfo *restrictinfo;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-25 01:21:14 +02:00
|
|
|
/*
|
2004-01-04 04:51:52 +01:00
|
|
|
* Retrieve all relids mentioned within the clause.
|
1999-07-25 01:21:14 +02:00
|
|
|
*/
|
2004-01-04 04:51:52 +01:00
|
|
|
relids = pull_varnos(clause);
|
1999-07-25 01:21:14 +02:00
|
|
|
|
2000-09-12 23:07:18 +02:00
|
|
|
/*
|
2012-09-01 00:57:12 +02:00
|
|
|
* Normally relids is a subset of qualscope, and we like to check that
|
|
|
|
* here as a crosscheck on the parser and rewriter. That need not be the
|
|
|
|
* case when there are LATERAL RTEs, however: the clause could contain
|
|
|
|
* references to rels outside its syntactic scope as a consequence of
|
|
|
|
* pull-up of such references from a LATERAL subquery below it. So, only
|
|
|
|
* check if the query contains no LATERAL RTEs.
|
2012-08-12 22:01:26 +02:00
|
|
|
*
|
2012-09-01 00:57:12 +02:00
|
|
|
* However, if it's an outer-join clause, we always insist that relids be
|
|
|
|
* a subset of ojscope. This is safe because is_simple_subquery()
|
|
|
|
* disallows pullup of LATERAL subqueries that could cause the restriction
|
|
|
|
* to be violated.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
2012-09-01 00:57:12 +02:00
|
|
|
if (!root->hasLateralRTEs && !bms_is_subset(relids, qualscope))
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
elog(ERROR, "JOIN qualification cannot refer to other relations");
|
2005-12-20 03:30:36 +01:00
|
|
|
if (ojscope && !bms_is_subset(relids, ojscope))
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
2007-02-01 20:10:30 +01:00
|
|
|
elog(ERROR, "JOIN qualification cannot refer to other relations");
|
2000-09-29 20:21:41 +02:00
|
|
|
|
|
|
|
/*
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
* If the clause is variable-free, our normal heuristic for pushing it
|
|
|
|
* down to just the mentioned rels doesn't work, because there are none.
|
|
|
|
*
|
|
|
|
* If the clause is an outer-join clause, we must force it to the OJ's
|
|
|
|
* semantic level to preserve semantics.
|
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Otherwise, when the clause contains volatile functions, we force it to
|
|
|
|
* be evaluated at its original syntactic level. This preserves the
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
* expected semantics.
|
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* When the clause contains no volatile functions either, it is actually a
|
|
|
|
* pseudoconstant clause that will not change value during any one
|
|
|
|
* execution of the plan, and hence can be used as a one-time qual in a
|
|
|
|
* gating Result plan node. We put such a clause into the regular
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
* RestrictInfo lists for the moment, but eventually createplan.c will
|
|
|
|
* pull it out and make a gating Result node immediately above whatever
|
2006-10-04 02:30:14 +02:00
|
|
|
* plan node the pseudoconstant clause is assigned to. It's usually best
|
|
|
|
* to put a gating node as high in the plan tree as possible. If we are
|
|
|
|
* not below an outer join, we can actually push the pseudoconstant qual
|
|
|
|
* all the way to the top of the tree. If we are below an outer join, we
|
|
|
|
* leave the qual at its original syntactic level (we could push it up to
|
|
|
|
* just below the outer join, but that seems more complex than it's
|
|
|
|
* worth).
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2003-02-08 21:20:55 +01:00
|
|
|
if (bms_is_empty(relids))
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
{
|
|
|
|
if (ojscope)
|
|
|
|
{
|
|
|
|
/* clause is attached to outer join, eval it there */
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
relids = bms_copy(ojscope);
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
/* mustn't use as gating qual, so don't mark pseudoconstant */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* eval at original syntactic level */
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
relids = bms_copy(qualscope);
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
if (!contain_volatile_functions(clause))
|
|
|
|
{
|
|
|
|
/* mark as gating qual */
|
|
|
|
pseudoconstant = true;
|
|
|
|
/* tell createplan.c to check for gating quals */
|
|
|
|
root->hasPseudoConstantQuals = true;
|
|
|
|
/* if not below outer join, push it to top of tree */
|
|
|
|
if (!below_outer_join)
|
2009-05-06 22:31:18 +02:00
|
|
|
{
|
2008-08-17 03:20:00 +02:00
|
|
|
relids =
|
|
|
|
get_relids_in_jointree((Node *) root->parse->jointree,
|
|
|
|
false);
|
2009-05-06 22:31:18 +02:00
|
|
|
qualscope = bms_copy(relids);
|
|
|
|
}
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-09-29 20:21:41 +02:00
|
|
|
|
2007-02-16 21:57:19 +01:00
|
|
|
/*----------
|
2003-03-03 00:46:34 +01:00
|
|
|
* Check to see if clause application must be delayed by outer-join
|
|
|
|
* considerations.
|
2007-02-16 21:57:19 +01:00
|
|
|
*
|
|
|
|
* A word about is_pushed_down: we mark the qual as "pushed down" if
|
|
|
|
* it is (potentially) applicable at a level different from its original
|
|
|
|
* syntactic level. This flag is used to distinguish OUTER JOIN ON quals
|
|
|
|
* from other quals pushed down to the same joinrel. The rules are:
|
|
|
|
* WHERE quals and INNER JOIN quals: is_pushed_down = true.
|
|
|
|
* Non-degenerate OUTER JOIN quals: is_pushed_down = false.
|
|
|
|
* Degenerate OUTER JOIN quals: is_pushed_down = true.
|
|
|
|
* A "degenerate" OUTER JOIN qual is one that doesn't mention the
|
|
|
|
* non-nullable side, and hence can be pushed down into the nullable side
|
|
|
|
* without changing the join result. It is correct to treat it as a
|
|
|
|
* regular filter condition at the level where it is evaluated.
|
|
|
|
*
|
|
|
|
* Note: it is not immediately obvious that a simple boolean is enough
|
|
|
|
* for this: if for some reason we were to attach a degenerate qual to
|
|
|
|
* its original join level, it would need to be treated as an outer join
|
2007-11-15 22:14:46 +01:00
|
|
|
* qual there. However, this cannot happen, because all the rels the
|
2007-02-16 21:57:19 +01:00
|
|
|
* clause mentions must be in the outer join's min_righthand, therefore
|
|
|
|
* the join it needs must be formed before the outer join; and we always
|
|
|
|
* attach quals to the lowest level where they can be evaluated. But
|
|
|
|
* if we were ever to re-introduce a mechanism for delaying evaluation
|
|
|
|
* of "expensive" quals, this area would need work.
|
|
|
|
*----------
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
2005-09-28 23:17:02 +02:00
|
|
|
if (is_deduced)
|
2001-10-18 18:11:42 +02:00
|
|
|
{
|
2003-03-03 00:46:34 +01:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If the qual came from implied-equality deduction, it should not be
|
|
|
|
* outerjoin-delayed, else deducer blew it. But we can't check this
|
2008-08-14 20:48:00 +02:00
|
|
|
* because the join_info_list may now contain OJs above where the qual
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* belongs. For the same reason, we must rely on caller to supply the
|
|
|
|
* correct nullable_relids set.
|
2003-03-03 00:46:34 +01:00
|
|
|
*/
|
2005-12-20 03:30:36 +01:00
|
|
|
Assert(!ojscope);
|
2007-02-16 21:57:19 +01:00
|
|
|
is_pushed_down = true;
|
2005-11-15 00:54:23 +01:00
|
|
|
outerjoin_delayed = false;
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
nullable_relids = deduced_nullable_relids;
|
2007-01-20 21:45:41 +01:00
|
|
|
/* Don't feed it back for more deductions */
|
|
|
|
maybe_equivalence = false;
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
maybe_outer_join = false;
|
2001-10-18 18:11:42 +02:00
|
|
|
}
|
2008-11-22 23:47:06 +01:00
|
|
|
else if (bms_overlap(relids, outerjoin_nonnullable))
|
2000-09-12 23:07:18 +02:00
|
|
|
{
|
2003-03-03 00:46:34 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The qual is attached to an outer join and mentions (some of the)
|
2008-11-22 23:47:06 +01:00
|
|
|
* rels on the nonnullable side, so it's not degenerate.
|
2007-01-20 21:45:41 +01:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* We can't use such a clause to deduce equivalence (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
|
2009-06-11 16:49:15 +02:00
|
|
|
* deductions, if it is mergejoinable. So consider adding it to the
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
* lists of set-aside outer-join clauses.
|
2007-01-20 21:45:41 +01:00
|
|
|
*/
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
is_pushed_down = false;
|
2007-01-20 21:45:41 +01:00
|
|
|
maybe_equivalence = false;
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
maybe_outer_join = true;
|
|
|
|
|
|
|
|
/* Check to see if must be delayed by lower outer join */
|
2009-04-16 22:42:16 +02:00
|
|
|
outerjoin_delayed = check_outerjoin_delay(root,
|
|
|
|
&relids,
|
|
|
|
&nullable_relids,
|
|
|
|
false);
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now force the qual to be evaluated exactly at the level of joining
|
|
|
|
* corresponding to the outer join. We cannot let it get pushed down
|
|
|
|
* into the nonnullable side, since then we'd produce no output rows,
|
|
|
|
* rather than the intended single null-extended row, for any
|
|
|
|
* nonnullable-side rows failing the qual.
|
|
|
|
*
|
|
|
|
* (Do this step after calling check_outerjoin_delay, because that
|
|
|
|
* trashes relids.)
|
2003-03-03 00:46:34 +01:00
|
|
|
*/
|
2005-12-20 03:30:36 +01:00
|
|
|
Assert(ojscope);
|
|
|
|
relids = ojscope;
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
Assert(!pseudoconstant);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-02-16 21:57:19 +01:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Normal qual clause or degenerate outer-join clause. Either way, we
|
|
|
|
* can mark it as pushed-down.
|
2007-02-16 21:57:19 +01:00
|
|
|
*/
|
|
|
|
is_pushed_down = true;
|
|
|
|
|
Fix some planner issues found while investigating Kevin Grittner's report
of poorer planning in 8.3 than 8.2:
1. After pushing a constant across an outer join --- ie, given
"a LEFT JOIN b ON (a.x = b.y) WHERE a.x = 42", we can deduce that b.y is
sort of equal to 42, in the sense that we needn't fetch any b rows where
it isn't 42 --- loop to see if any additional deductions can be made.
Previous releases did that by recursing, but I had mistakenly thought that
this was no longer necessary given the EquivalenceClass machinery.
2. Allow pushing constants across outer join conditions even if the
condition is outerjoin_delayed due to a lower outer join. This is safe
as long as the condition is strict and we re-test it at the upper join.
3. Keep the outer-join clause even if we successfully push a constant
across it. This is *necessary* in the outerjoin_delayed case, but
even in the simple case, it seems better to do this to ensure that the
join search order heuristics will consider the join as reasonable to
make. Mark such a clause as having selectivity 1.0, though, since it's
not going to eliminate very many rows after application of the constant
condition.
4. Tweak have_relevant_eclass_joinclause to report that two relations
are joinable when they have vars that are equated to the same constant.
We won't actually generate any joinclause from such an EquivalenceClass,
but again it seems that in such a case it's a good idea to consider
the join as worth costing out.
5. Fix a bug in select_mergejoin_clauses that was exposed by these
changes: we have to reject candidate mergejoin clauses if either side was
equated to a constant, because we can't construct a canonical pathkey list
for such a clause. This is an implementation restriction that might be
worth fixing someday, but it doesn't seem critical to get it done for 8.3.
2008-01-09 21:42:29 +01:00
|
|
|
/* Check to see if must be delayed by lower outer join */
|
2009-04-16 22:42:16 +02:00
|
|
|
outerjoin_delayed = check_outerjoin_delay(root,
|
|
|
|
&relids,
|
|
|
|
&nullable_relids,
|
|
|
|
true);
|
2003-03-03 00:46:34 +01:00
|
|
|
|
2006-12-07 20:33:40 +01:00
|
|
|
if (outerjoin_delayed)
|
|
|
|
{
|
|
|
|
/* Should still be a subset of current scope ... */
|
2012-09-01 00:57:12 +02:00
|
|
|
Assert(root->hasLateralRTEs || bms_is_subset(relids, qualscope));
|
|
|
|
Assert(ojscope == NULL || bms_is_subset(relids, ojscope));
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2006-12-07 20:33:40 +01:00
|
|
|
/*
|
|
|
|
* Because application of the qual will be delayed by outer join,
|
|
|
|
* we mustn't assume its vars are equal everywhere.
|
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
maybe_equivalence = false;
|
2008-08-14 20:48:00 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It's possible that this is an IS NULL clause that's redundant
|
|
|
|
* with a lower antijoin; if so we can just discard it. We need
|
2009-06-11 16:49:15 +02:00
|
|
|
* not test in any of the other cases, because this will only be
|
|
|
|
* possible for pushed-down, delayed clauses.
|
2008-08-14 20:48:00 +02:00
|
|
|
*/
|
|
|
|
if (check_redundant_nullability_qual(root, clause))
|
|
|
|
return;
|
2006-12-07 20:33:40 +01:00
|
|
|
}
|
|
|
|
else
|
2003-03-03 00:46:34 +01:00
|
|
|
{
|
2005-09-28 23:17:02 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Qual is not delayed by any lower outer-join restriction, so we
|
|
|
|
* can consider feeding it to the equivalence machinery. However,
|
|
|
|
* if it's itself within an outer-join clause, treat it as though
|
|
|
|
* it appeared below that outer join (note that we can only get
|
|
|
|
* here when the clause references only nullable-side rels).
|
2005-09-28 23:17:02 +02:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
maybe_equivalence = true;
|
|
|
|
if (outerjoin_nonnullable != NULL)
|
|
|
|
below_outer_join = true;
|
2003-03-03 00:46:34 +01:00
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2007-01-20 21:45:41 +01:00
|
|
|
/*
|
|
|
|
* Since it doesn't mention the LHS, it's certainly not useful as a
|
|
|
|
* set-aside OJ clause, even if it's in an OJ.
|
|
|
|
*/
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
maybe_outer_join = false;
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
|
2003-12-31 00:53:15 +01:00
|
|
|
/*
|
2004-01-04 01:07:32 +01:00
|
|
|
* Build the RestrictInfo node itself.
|
2003-12-31 00:53:15 +01:00
|
|
|
*/
|
2004-01-05 06:07:36 +01:00
|
|
|
restrictinfo = make_restrictinfo((Expr *) clause,
|
|
|
|
is_pushed_down,
|
2005-11-15 00:54:23 +01:00
|
|
|
outerjoin_delayed,
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
pseudoconstant,
|
2009-04-16 22:42:16 +02:00
|
|
|
relids,
|
Revise parameterized-path mechanism to fix assorted issues.
This patch adjusts the treatment of parameterized paths so that all paths
with the same parameterization (same set of required outer rels) for the
same relation will have the same rowcount estimate. We cache the rowcount
estimates to ensure that property, and hopefully save a few cycles too.
Doing this makes it practical for add_path_precheck to operate without
a rowcount estimate: it need only assume that paths with different
parameterizations never dominate each other, which is close enough to
true anyway for coarse filtering, because normally a more-parameterized
path should yield fewer rows thanks to having more join clauses to apply.
In add_path, we do the full nine yards of comparing rowcount estimates
along with everything else, so that we can discard parameterized paths that
don't actually have an advantage. This fixes some issues I'd found with
add_path rejecting parameterized paths on the grounds that they were more
expensive than not-parameterized ones, even though they yielded many fewer
rows and hence would be cheaper once subsequent joining was considered.
To make the same-rowcounts assumption valid, we have to require that any
parameterized path enforce *all* join clauses that could be obtained from
the particular set of outer rels, even if not all of them are useful for
indexing. This is required at both base scans and joins. It's a good
thing anyway since the net impact is that join quals are checked at the
lowest practical level in the join tree. Hence, discard the original
rather ad-hoc mechanism for choosing parameterization joinquals, and build
a better one that has a more principled rule for when clauses can be moved.
The original rule was actually buggy anyway for lack of knowledge about
which relations are part of an outer join's outer side; getting this right
requires adding an outer_relids field to RestrictInfo.
2012-04-19 21:52:46 +02:00
|
|
|
outerjoin_nonnullable,
|
2009-04-16 22:42:16 +02:00
|
|
|
nullable_relids);
|
2003-12-31 00:53:15 +01:00
|
|
|
|
2004-01-04 01:07:32 +01:00
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* If it's a join clause (either naturally, or because delayed by
|
2007-11-15 22:14:46 +01:00
|
|
|
* outer-join rules), add vars used in the clause to targetlists of their
|
|
|
|
* relations, so that they will be emitted by the plan nodes that scan
|
|
|
|
* those relations (else they won't be available at the join node!).
|
2007-01-20 21:45:41 +01:00
|
|
|
*
|
|
|
|
* Note: if the clause gets absorbed into an EquivalenceClass then this
|
|
|
|
* may be unnecessary, but for now we have to do it to cover the case
|
|
|
|
* where the EC becomes ec_broken and we end up reinserting the original
|
|
|
|
* clauses into the plan.
|
2004-01-04 01:07:32 +01:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
if (bms_membership(relids) == BMS_MULTIPLE)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
Avoid listing ungrouped Vars in the targetlist of Agg-underneath-Window.
Regular aggregate functions in combination with, or within the arguments
of, window functions are OK per spec; they have the semantics that the
aggregate output rows are computed and then we run the window functions
over that row set. (Thus, this combination is not really useful unless
there's a GROUP BY so that more than one aggregate output row is possible.)
The case without GROUP BY could fail, as recently reported by Jeff Davis,
because sloppy construction of the Agg node's targetlist resulted in extra
references to possibly-ungrouped Vars appearing outside the aggregate
function calls themselves. See the added regression test case for an
example.
Fixing this requires modifying the API of flatten_tlist and its underlying
function pull_var_clause. I chose to make pull_var_clause's API for
aggregates identical to what it was already doing for placeholders, since
the useful behaviors turn out to be the same (error, report node as-is, or
recurse into it). I also tightened the error checking in this area a bit:
if it was ever valid to see an uplevel Var, Aggref, or PlaceHolderVar here,
that was a long time ago, so complain instead of ignoring them.
Backpatch into 9.1. The failure exists in 8.4 and 9.0 as well, but seeing
that it only occurs in a basically-useless corner case, it doesn't seem
worth the risks of changing a function API in a minor release. There might
be third-party code using pull_var_clause.
2011-07-13 00:23:55 +02:00
|
|
|
List *vars = pull_var_clause(clause,
|
|
|
|
PVC_RECURSE_AGGREGATES,
|
|
|
|
PVC_INCLUDE_PLACEHOLDERS);
|
2003-02-08 21:20:55 +01:00
|
|
|
|
2011-08-09 06:48:51 +02:00
|
|
|
add_vars_to_targetlist(root, vars, relids, false);
|
2007-01-20 21:45:41 +01:00
|
|
|
list_free(vars);
|
2000-08-13 04:50:35 +02:00
|
|
|
}
|
2000-02-15 21:49:31 +01:00
|
|
|
|
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* We check "mergejoinability" of every clause, not only join clauses,
|
|
|
|
* because we want to know about equivalences between vars of the same
|
|
|
|
* relation, or between vars and consts.
|
|
|
|
*/
|
|
|
|
check_mergejoinable(restrictinfo);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it is a true equivalence clause, send it to the EquivalenceClass
|
|
|
|
* machinery. We do *not* attach it directly to any restriction or join
|
|
|
|
* lists. The EC code will propagate it to the appropriate places later.
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If the clause has a mergejoinable operator and is not
|
|
|
|
* outerjoin-delayed, yet isn't an equivalence because it is an outer-join
|
|
|
|
* clause, the EC code may yet be able to do something with it. We add it
|
|
|
|
* to appropriate lists for further consideration later. Specifically:
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* 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
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
* 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
|
2007-11-15 22:14:46 +01:00
|
|
|
* 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.)
|
2007-01-20 21:45:41 +01:00
|
|
|
*
|
|
|
|
* If none of the above hold, pass it off to
|
|
|
|
* distribute_restrictinfo_to_rels().
|
2010-10-29 17:52:16 +02:00
|
|
|
*
|
|
|
|
* In all cases, it's important to initialize the left_ec and right_ec
|
|
|
|
* fields of a mergejoinable clause, so that all possibly mergejoinable
|
2011-04-10 17:42:00 +02:00
|
|
|
* expressions have representations in EquivalenceClasses. If
|
2010-10-29 17:52:16 +02:00
|
|
|
* process_equivalence is successful, it will take care of that;
|
|
|
|
* otherwise, we have to call initialize_mergeclause_eclasses to do it.
|
2000-02-15 21:49:31 +01:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
if (restrictinfo->mergeopfamilies)
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
{
|
2007-01-20 21:45:41 +01:00
|
|
|
if (maybe_equivalence)
|
|
|
|
{
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
if (check_equivalence_delay(root, restrictinfo) &&
|
|
|
|
process_equivalence(root, restrictinfo, below_outer_join))
|
2007-01-20 21:45:41 +01:00
|
|
|
return;
|
2010-10-29 17:52:16 +02:00
|
|
|
/* EC rejected it, so set left_ec/right_ec the hard way ... */
|
|
|
|
initialize_mergeclause_eclasses(root, restrictinfo);
|
|
|
|
/* ... and fall through to distribute_restrictinfo_to_rels */
|
2007-01-20 21:45:41 +01:00
|
|
|
}
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
else if (maybe_outer_join && restrictinfo->can_join)
|
|
|
|
{
|
2010-10-29 17:52:16 +02:00
|
|
|
/* we need to set up left_ec/right_ec the hard way */
|
|
|
|
initialize_mergeclause_eclasses(root, restrictinfo);
|
|
|
|
/* now see if it should go to any outer-join lists */
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
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);
|
2007-01-20 21:45:41 +01:00
|
|
|
return;
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
}
|
2007-01-20 21:45:41 +01:00
|
|
|
if (bms_is_subset(restrictinfo->right_relids,
|
2007-11-15 22:14:46 +01:00
|
|
|
outerjoin_nonnullable) &&
|
|
|
|
!bms_overlap(restrictinfo->left_relids,
|
|
|
|
outerjoin_nonnullable))
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
{
|
|
|
|
/* we have innervar = outervar */
|
|
|
|
root->right_join_clauses = lappend(root->right_join_clauses,
|
|
|
|
restrictinfo);
|
2007-01-20 21:45:41 +01:00
|
|
|
return;
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
}
|
2008-10-25 21:51:32 +02:00
|
|
|
if (jointype == JOIN_FULL)
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
{
|
|
|
|
/* FULL JOIN (above tests cannot match in this case) */
|
|
|
|
root->full_join_clauses = lappend(root->full_join_clauses,
|
|
|
|
restrictinfo);
|
2007-01-20 21:45:41 +01:00
|
|
|
return;
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
}
|
2010-10-29 17:52:16 +02:00
|
|
|
/* nope, so fall through to distribute_restrictinfo_to_rels */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* we still need to set up left_ec/right_ec */
|
|
|
|
initialize_mergeclause_eclasses(root, restrictinfo);
|
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.
2005-07-03 01:00:42 +02:00
|
|
|
}
|
|
|
|
}
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
/* No EC special case applies, so push it into the clause lists */
|
|
|
|
distribute_restrictinfo_to_rels(root, restrictinfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-07-24 05:11:01 +02:00
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* check_outerjoin_delay
|
|
|
|
* Detect whether a qual referencing the given relids must be delayed
|
2007-05-23 01:23:58 +02:00
|
|
|
* in application due to the presence of a lower outer join, and/or
|
|
|
|
* may force extra delay of higher-level outer joins.
|
2003-01-24 04:58:44 +01:00
|
|
|
*
|
2007-05-23 01:23:58 +02:00
|
|
|
* If the qual must be delayed, add relids to *relids_p to reflect the lowest
|
|
|
|
* safe level for evaluating the qual, and return TRUE. Any extra delay for
|
|
|
|
* higher-level joins is reflected by setting delay_upper_joins to TRUE in
|
2009-04-16 22:42:16 +02:00
|
|
|
* SpecialJoinInfo structs. We also compute nullable_relids, the set of
|
|
|
|
* referenced relids that are nullable by lower outer joins (note that this
|
|
|
|
* can be nonempty even for a non-delayed qual).
|
2007-01-20 21:45:41 +01:00
|
|
|
*
|
2007-02-16 21:57:19 +01:00
|
|
|
* For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have
|
2007-01-20 21:45:41 +01:00
|
|
|
* all the rels it mentions, and (2) we are at or above any outer joins that
|
|
|
|
* can null any of these rels and are below the syntactic location of the
|
2007-11-15 22:14:46 +01:00
|
|
|
* given qual. We must enforce (2) because pushing down such a clause below
|
2007-01-20 21:45:41 +01:00
|
|
|
* the OJ might cause the OJ to emit null-extended rows that should not have
|
|
|
|
* been formed, or that should have been rejected by the clause. (This is
|
|
|
|
* only an issue for non-strict quals, since if we can prove a qual mentioning
|
|
|
|
* only nullable rels is strict, we'd have reduced the outer join to an inner
|
|
|
|
* join in reduce_outer_joins().)
|
|
|
|
*
|
2008-08-14 20:48:00 +02:00
|
|
|
* To enforce (2), scan the join_info_list and merge the required-relid sets of
|
2007-01-20 21:45:41 +01:00
|
|
|
* any such OJs into the clause's own reference list. At the time we are
|
2008-08-14 20:48:00 +02:00
|
|
|
* called, the join_info_list contains only outer joins below this qual. We
|
2007-01-20 21:45:41 +01:00
|
|
|
* have to repeat the scan until no new relids get added; this ensures that
|
|
|
|
* the qual is suitably delayed regardless of the order in which OJs get
|
|
|
|
* executed. As an example, if we have one OJ with LHS=A, RHS=B, and one with
|
|
|
|
* LHS=B, RHS=C, it is implied that these can be done in either order; if the
|
|
|
|
* B/C join is done first then the join to A can null C, so a qual actually
|
|
|
|
* mentioning only C cannot be applied below the join to A.
|
|
|
|
*
|
2007-02-16 21:57:19 +01:00
|
|
|
* For a non-pushed-down qual, this isn't going to determine where we place the
|
2009-04-16 22:42:16 +02:00
|
|
|
* qual, but we need to determine outerjoin_delayed and nullable_relids anyway
|
|
|
|
* for use later in the planning process.
|
2007-05-23 01:23:58 +02:00
|
|
|
*
|
|
|
|
* Lastly, a pushed-down qual that references the nullable side of any current
|
2008-08-14 20:48:00 +02:00
|
|
|
* join_info_list member and has to be evaluated above that OJ (because its
|
2007-05-23 01:23:58 +02:00
|
|
|
* required relids overlap the LHS too) causes that OJ's delay_upper_joins
|
|
|
|
* flag to be set TRUE. This will prevent any higher-level OJs from
|
|
|
|
* being interchanged with that OJ, which would result in not having any
|
2007-11-15 22:14:46 +01:00
|
|
|
* correct place to evaluate the qual. (The case we care about here is a
|
2007-05-23 01:23:58 +02:00
|
|
|
* sub-select WHERE clause within the RHS of some outer join. The WHERE
|
|
|
|
* clause must effectively be treated as a degenerate clause of that outer
|
|
|
|
* join's condition. Rather than trying to match such clauses with joins
|
|
|
|
* directly, we set delay_upper_joins here, and when the upper outer join
|
|
|
|
* is processed by make_outerjoininfo, it will refrain from allowing the
|
|
|
|
* two OJs to commute.)
|
2000-07-24 05:11:01 +02:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
static bool
|
2009-04-16 22:42:16 +02:00
|
|
|
check_outerjoin_delay(PlannerInfo *root,
|
2009-06-11 16:49:15 +02:00
|
|
|
Relids *relids_p, /* in/out parameter */
|
|
|
|
Relids *nullable_relids_p, /* output parameter */
|
2007-05-23 01:23:58 +02:00
|
|
|
bool is_pushed_down)
|
2000-07-24 05:11:01 +02:00
|
|
|
{
|
2009-04-16 22:42:16 +02:00
|
|
|
Relids relids;
|
|
|
|
Relids nullable_relids;
|
2007-01-20 21:45:41 +01:00
|
|
|
bool outerjoin_delayed;
|
|
|
|
bool found_some;
|
2003-02-08 21:20:55 +01:00
|
|
|
|
2009-04-16 22:42:16 +02:00
|
|
|
/* fast path if no special joins */
|
|
|
|
if (root->join_info_list == NIL)
|
|
|
|
{
|
|
|
|
*nullable_relids_p = NULL;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* must copy relids because we need the original value at the end */
|
|
|
|
relids = bms_copy(*relids_p);
|
|
|
|
nullable_relids = NULL;
|
2007-01-20 21:45:41 +01:00
|
|
|
outerjoin_delayed = false;
|
2007-11-15 22:14:46 +01:00
|
|
|
do
|
|
|
|
{
|
2007-01-20 21:45:41 +01:00
|
|
|
ListCell *l;
|
2003-01-24 04:58:44 +01:00
|
|
|
|
2007-01-20 21:45:41 +01:00
|
|
|
found_some = false;
|
2008-08-14 20:48:00 +02:00
|
|
|
foreach(l, root->join_info_list)
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
2008-08-14 20:48:00 +02:00
|
|
|
SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
/* do we reference any nullable rels of this OJ? */
|
2008-08-14 20:48:00 +02:00
|
|
|
if (bms_overlap(relids, sjinfo->min_righthand) ||
|
|
|
|
(sjinfo->jointype == JOIN_FULL &&
|
|
|
|
bms_overlap(relids, sjinfo->min_lefthand)))
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
2009-04-16 22:42:16 +02:00
|
|
|
/* yes; have we included all its rels in relids? */
|
2008-08-14 20:48:00 +02:00
|
|
|
if (!bms_is_subset(sjinfo->min_lefthand, relids) ||
|
|
|
|
!bms_is_subset(sjinfo->min_righthand, relids))
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
2007-01-20 21:45:41 +01:00
|
|
|
/* no, so add them in */
|
2008-08-14 20:48:00 +02:00
|
|
|
relids = bms_add_members(relids, sjinfo->min_lefthand);
|
|
|
|
relids = bms_add_members(relids, sjinfo->min_righthand);
|
2009-04-16 22:42:16 +02:00
|
|
|
outerjoin_delayed = true;
|
2007-01-20 21:45:41 +01:00
|
|
|
/* we'll need another iteration */
|
|
|
|
found_some = true;
|
2003-01-24 04:58:44 +01:00
|
|
|
}
|
2009-04-16 22:42:16 +02:00
|
|
|
/* track all the nullable rels of relevant OJs */
|
|
|
|
nullable_relids = bms_add_members(nullable_relids,
|
|
|
|
sjinfo->min_righthand);
|
|
|
|
if (sjinfo->jointype == JOIN_FULL)
|
|
|
|
nullable_relids = bms_add_members(nullable_relids,
|
|
|
|
sjinfo->min_lefthand);
|
2007-05-23 01:23:58 +02:00
|
|
|
/* set delay_upper_joins if needed */
|
2008-08-14 20:48:00 +02:00
|
|
|
if (is_pushed_down && sjinfo->jointype != JOIN_FULL &&
|
|
|
|
bms_overlap(relids, sjinfo->min_lefthand))
|
|
|
|
sjinfo->delay_upper_joins = true;
|
2003-01-24 04:58:44 +01:00
|
|
|
}
|
|
|
|
}
|
2007-01-20 21:45:41 +01:00
|
|
|
} while (found_some);
|
2003-01-24 04:58:44 +01:00
|
|
|
|
2009-04-16 22:42:16 +02:00
|
|
|
/* identify just the actually-referenced nullable rels */
|
|
|
|
nullable_relids = bms_int_members(nullable_relids, *relids_p);
|
|
|
|
|
|
|
|
/* replace *relids_p, and return nullable_relids */
|
|
|
|
bms_free(*relids_p);
|
2007-01-20 21:45:41 +01:00
|
|
|
*relids_p = relids;
|
2009-04-16 22:42:16 +02:00
|
|
|
*nullable_relids_p = nullable_relids;
|
2007-01-20 21:45:41 +01:00
|
|
|
return outerjoin_delayed;
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
/*
|
|
|
|
* check_equivalence_delay
|
|
|
|
* Detect whether a potential equivalence clause is rendered unsafe
|
|
|
|
* by outer-join-delay considerations. Return TRUE if it's safe.
|
|
|
|
*
|
|
|
|
* The initial tests in distribute_qual_to_rels will consider a mergejoinable
|
|
|
|
* clause to be a potential equivalence clause if it is not outerjoin_delayed.
|
|
|
|
* But since the point of equivalence processing is that we will recombine the
|
|
|
|
* two sides of the clause with others, we have to check that each side
|
|
|
|
* satisfies the not-outerjoin_delayed condition on its own; otherwise it might
|
|
|
|
* not be safe to evaluate everywhere we could place a derived equivalence
|
|
|
|
* condition.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_equivalence_delay(PlannerInfo *root,
|
|
|
|
RestrictInfo *restrictinfo)
|
|
|
|
{
|
|
|
|
Relids relids;
|
|
|
|
Relids nullable_relids;
|
|
|
|
|
|
|
|
/* fast path if no special joins */
|
|
|
|
if (root->join_info_list == NIL)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* must copy restrictinfo's relids to avoid changing it */
|
|
|
|
relids = bms_copy(restrictinfo->left_relids);
|
|
|
|
/* check left side does not need delay */
|
|
|
|
if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* and similarly for the right side */
|
|
|
|
relids = bms_copy(restrictinfo->right_relids);
|
|
|
|
if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-08-14 20:48:00 +02:00
|
|
|
/*
|
|
|
|
* check_redundant_nullability_qual
|
|
|
|
* Check to see if the qual is an IS NULL qual that is redundant with
|
|
|
|
* a lower JOIN_ANTI join.
|
|
|
|
*
|
|
|
|
* We want to suppress redundant IS NULL quals, not so much to save cycles
|
|
|
|
* as to avoid generating bogus selectivity estimates for them. So if
|
|
|
|
* redundancy is detected here, distribute_qual_to_rels() just throws away
|
|
|
|
* the qual.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
|
|
|
|
{
|
|
|
|
Var *forced_null_var;
|
|
|
|
Index forced_null_rel;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
/* Check for IS NULL, and identify the Var forced to NULL */
|
|
|
|
forced_null_var = find_forced_null_var(clause);
|
|
|
|
if (forced_null_var == NULL)
|
|
|
|
return false;
|
|
|
|
forced_null_rel = forced_null_var->varno;
|
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If the Var comes from the nullable side of a lower antijoin, the IS
|
|
|
|
* NULL condition is necessarily true.
|
2008-08-14 20:48:00 +02:00
|
|
|
*/
|
|
|
|
foreach(lc, root->join_info_list)
|
|
|
|
{
|
|
|
|
SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
|
|
|
|
|
|
|
|
if (sjinfo->jointype == JOIN_ANTI &&
|
|
|
|
bms_is_member(forced_null_rel, sjinfo->syn_righthand))
|
2009-02-20 01:01:03 +01:00
|
|
|
return true;
|
2008-08-14 20:48:00 +02:00
|
|
|
}
|
|
|
|
|
2009-02-20 01:01:03 +01:00
|
|
|
return false;
|
2008-08-14 20:48:00 +02:00
|
|
|
}
|
|
|
|
|
2007-01-20 21:45:41 +01:00
|
|
|
/*
|
|
|
|
* distribute_restrictinfo_to_rels
|
|
|
|
* Push a completed RestrictInfo into the proper restriction or join
|
|
|
|
* clause list(s).
|
|
|
|
*
|
|
|
|
* This is the last step of distribute_qual_to_rels() for ordinary qual
|
|
|
|
* clauses. Clauses that are interesting for equivalence-class processing
|
|
|
|
* are diverted to the EC machinery, but may ultimately get fed back here.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
distribute_restrictinfo_to_rels(PlannerInfo *root,
|
|
|
|
RestrictInfo *restrictinfo)
|
|
|
|
{
|
|
|
|
Relids relids = restrictinfo->required_relids;
|
|
|
|
RelOptInfo *rel;
|
|
|
|
|
|
|
|
switch (bms_membership(relids))
|
2000-07-24 05:11:01 +02:00
|
|
|
{
|
2007-01-20 21:45:41 +01:00
|
|
|
case BMS_SINGLETON:
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* There is only one relation participating in the clause, so it
|
|
|
|
* is a restriction clause for that relation.
|
2007-01-20 21:45:41 +01:00
|
|
|
*/
|
|
|
|
rel = find_base_rel(root, bms_singleton_member(relids));
|
|
|
|
|
|
|
|
/* Add clause to rel's restriction list */
|
|
|
|
rel->baserestrictinfo = lappend(rel->baserestrictinfo,
|
|
|
|
restrictinfo);
|
|
|
|
break;
|
|
|
|
case BMS_MULTIPLE:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The clause is a join clause, since there is more than one rel
|
|
|
|
* in its relid set.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Check for hashjoinable operators. (We don't bother setting the
|
2010-12-31 02:24:55 +01:00
|
|
|
* hashjoin info except in true join clauses.)
|
2007-01-20 21:45:41 +01:00
|
|
|
*/
|
2010-12-31 02:24:55 +01:00
|
|
|
check_hashjoinable(restrictinfo);
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add clause to the join lists of all the relevant relations.
|
|
|
|
*/
|
|
|
|
add_join_clause_to_rels(root, restrictinfo, relids);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* clause references no rels, and therefore we have no place to
|
|
|
|
* attach it. Shouldn't get here if callers are working properly.
|
|
|
|
*/
|
|
|
|
elog(ERROR, "cannot cope with variable-free clause");
|
|
|
|
break;
|
2000-07-24 05:11:01 +02:00
|
|
|
}
|
2007-01-20 21:45:41 +01:00
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2007-01-20 21:45:41 +01:00
|
|
|
/*
|
|
|
|
* process_implied_equality
|
|
|
|
* Create a restrictinfo item that says "item1 op item2", and push it
|
|
|
|
* into the appropriate lists. (In practice opno is always a btree
|
|
|
|
* equality operator.)
|
|
|
|
*
|
|
|
|
* "qualscope" is the nominal syntactic level to impute to the restrictinfo.
|
|
|
|
* This must contain at least all the rels used in the expressions, but it
|
|
|
|
* is used only to set the qual application level when both exprs are
|
|
|
|
* variable-free. Otherwise the qual is applied at the lowest join level
|
|
|
|
* that provides all its variables.
|
|
|
|
*
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* "nullable_relids" is the set of relids used in the expressions that are
|
|
|
|
* potentially nullable below the expressions. (This has to be supplied by
|
|
|
|
* caller because this function is used after deconstruct_jointree, so we
|
|
|
|
* don't have knowledge of where the clause items came from.)
|
|
|
|
*
|
2007-01-20 21:45:41 +01:00
|
|
|
* "both_const" indicates whether both items are known pseudo-constant;
|
|
|
|
* in this case it is worth applying eval_const_expressions() in case we
|
|
|
|
* can produce constant TRUE or constant FALSE. (Otherwise it's not,
|
|
|
|
* because the expressions went through eval_const_expressions already.)
|
|
|
|
*
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* Note: this function will copy item1 and item2, but it is caller's
|
|
|
|
* responsibility to make sure that the Relids parameters are fresh copies
|
|
|
|
* not shared with other uses.
|
|
|
|
*
|
2007-01-20 21:45:41 +01:00
|
|
|
* This is currently used only when an EquivalenceClass is found to
|
|
|
|
* contain pseudoconstants. See path/pathkeys.c for more details.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
process_implied_equality(PlannerInfo *root,
|
|
|
|
Oid opno,
|
2011-03-20 01:29:08 +01:00
|
|
|
Oid collation,
|
2007-01-20 21:45:41 +01:00
|
|
|
Expr *item1,
|
|
|
|
Expr *item2,
|
|
|
|
Relids qualscope,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
Relids nullable_relids,
|
2007-01-20 21:45:41 +01:00
|
|
|
bool below_outer_join,
|
|
|
|
bool both_const)
|
|
|
|
{
|
|
|
|
Expr *clause;
|
2000-07-24 05:11:01 +02:00
|
|
|
|
2004-02-27 22:42:00 +01:00
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* Build the new clause. Copy to ensure it shares no substructure with
|
|
|
|
* original (this is necessary in case there are subselects in there...)
|
2004-02-27 22:42:00 +01:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
clause = make_opclause(opno,
|
2003-08-04 02:43:34 +02:00
|
|
|
BOOLOID, /* opresulttype */
|
|
|
|
false, /* opretset */
|
2004-02-27 22:42:00 +01:00
|
|
|
(Expr *) copyObject(item1),
|
2011-03-20 01:29:08 +01:00
|
|
|
(Expr *) copyObject(item2),
|
|
|
|
InvalidOid,
|
|
|
|
collation);
|
2000-07-24 05:11:01 +02:00
|
|
|
|
2007-01-20 21:45:41 +01:00
|
|
|
/* If both constant, try to reduce to a boolean constant. */
|
|
|
|
if (both_const)
|
|
|
|
{
|
2008-04-01 02:48:33 +02:00
|
|
|
clause = (Expr *) eval_const_expressions(root, (Node *) clause);
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
/* If we produced const TRUE, just drop the clause */
|
|
|
|
if (clause && IsA(clause, Const))
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Const *cclause = (Const *) clause;
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
Assert(cclause->consttype == BOOLOID);
|
|
|
|
if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
/*
|
2003-01-15 20:35:48 +01:00
|
|
|
* Push the new clause into all the appropriate restrictinfo lists.
|
2000-09-29 20:21:41 +02:00
|
|
|
*/
|
|
|
|
distribute_qual_to_rels(root, (Node *) clause,
|
2008-10-25 21:51:32 +02:00
|
|
|
true, below_outer_join, JOIN_INNER,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
qualscope, NULL, NULL, nullable_relids);
|
2002-11-20 00:22:00 +01:00
|
|
|
}
|
|
|
|
|
2001-10-18 18:11:42 +02:00
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* build_implied_join_equality --- build a RestrictInfo for a derived equality
|
2003-01-24 04:58:44 +01:00
|
|
|
*
|
2007-01-20 21:45:41 +01:00
|
|
|
* This overlaps the functionality of process_implied_equality(), but we
|
|
|
|
* must return the RestrictInfo, not push it into the joininfo tree.
|
2010-10-29 17:52:16 +02:00
|
|
|
*
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
* Note: this function will copy item1 and item2, but it is caller's
|
|
|
|
* responsibility to make sure that the Relids parameters are fresh copies
|
|
|
|
* not shared with other uses.
|
|
|
|
*
|
2010-10-29 17:52:16 +02:00
|
|
|
* Note: we do not do initialize_mergeclause_eclasses() here. It is
|
|
|
|
* caller's responsibility that left_ec/right_ec be set as necessary.
|
2001-10-18 18:11:42 +02:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
RestrictInfo *
|
|
|
|
build_implied_join_equality(Oid opno,
|
2011-03-20 01:29:08 +01:00
|
|
|
Oid collation,
|
2007-01-20 21:45:41 +01:00
|
|
|
Expr *item1,
|
|
|
|
Expr *item2,
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
Relids qualscope,
|
|
|
|
Relids nullable_relids)
|
2001-10-18 18:11:42 +02:00
|
|
|
{
|
2007-01-20 21:45:41 +01:00
|
|
|
RestrictInfo *restrictinfo;
|
|
|
|
Expr *clause;
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-10-18 18:11:42 +02:00
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* Build the new clause. Copy to ensure it shares no substructure with
|
|
|
|
* original (this is necessary in case there are subselects in there...)
|
2001-10-18 18:11:42 +02:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
clause = make_opclause(opno,
|
|
|
|
BOOLOID, /* opresulttype */
|
|
|
|
false, /* opretset */
|
|
|
|
(Expr *) copyObject(item1),
|
2011-03-20 01:29:08 +01:00
|
|
|
(Expr *) copyObject(item2),
|
|
|
|
InvalidOid,
|
|
|
|
collation);
|
2001-10-18 18:11:42 +02:00
|
|
|
|
|
|
|
/*
|
2007-01-20 21:45:41 +01:00
|
|
|
* Build the RestrictInfo node itself.
|
2001-10-18 18:11:42 +02:00
|
|
|
*/
|
2007-01-20 21:45:41 +01:00
|
|
|
restrictinfo = make_restrictinfo(clause,
|
2007-11-15 22:14:46 +01:00
|
|
|
true, /* is_pushed_down */
|
|
|
|
false, /* outerjoin_delayed */
|
|
|
|
false, /* pseudoconstant */
|
2009-06-11 16:49:15 +02:00
|
|
|
qualscope, /* required_relids */
|
Revise parameterized-path mechanism to fix assorted issues.
This patch adjusts the treatment of parameterized paths so that all paths
with the same parameterization (same set of required outer rels) for the
same relation will have the same rowcount estimate. We cache the rowcount
estimates to ensure that property, and hopefully save a few cycles too.
Doing this makes it practical for add_path_precheck to operate without
a rowcount estimate: it need only assume that paths with different
parameterizations never dominate each other, which is close enough to
true anyway for coarse filtering, because normally a more-parameterized
path should yield fewer rows thanks to having more join clauses to apply.
In add_path, we do the full nine yards of comparing rowcount estimates
along with everything else, so that we can discard parameterized paths that
don't actually have an advantage. This fixes some issues I'd found with
add_path rejecting parameterized paths on the grounds that they were more
expensive than not-parameterized ones, even though they yielded many fewer
rows and hence would be cheaper once subsequent joining was considered.
To make the same-rowcounts assumption valid, we have to require that any
parameterized path enforce *all* join clauses that could be obtained from
the particular set of outer rels, even if not all of them are useful for
indexing. This is required at both base scans and joins. It's a good
thing anyway since the net impact is that join quals are checked at the
lowest practical level in the join tree. Hence, discard the original
rather ad-hoc mechanism for choosing parameterization joinquals, and build
a better one that has a more principled rule for when clauses can be moved.
The original rule was actually buggy anyway for lack of knowledge about
which relations are part of an outer join's outer side; getting this right
requires adding an outer_relids field to RestrictInfo.
2012-04-19 21:52:46 +02:00
|
|
|
NULL, /* outer_relids */
|
Fix planning of non-strict equivalence clauses above outer joins.
If a potential equivalence clause references a variable from the nullable
side of an outer join, the planner needs to take care that derived clauses
are not pushed to below the outer join; else they may use the wrong value
for the variable. (The problem arises only with non-strict clauses, since
if an upper clause can be proven strict then the outer join will get
simplified to a plain join.) The planner attempted to prevent this type
of error by checking that potential equivalence clauses aren't
outerjoin-delayed as a whole, but actually we have to check each side
separately, since the two sides of the clause will get moved around
separately if it's treated as an equivalence. Bugs of this type can be
demonstrated as far back as 7.4, even though releases before 8.3 had only
a very ad-hoc notion of equivalence clauses.
In addition, we neglected to account for the possibility that such clauses
might have nonempty nullable_relids even when not outerjoin-delayed; so the
equivalence-class machinery lacked logic to compute correct nullable_relids
values for clauses it constructs. This oversight was harmless before 9.2
because we were only using RestrictInfo.nullable_relids for OR clauses;
but as of 9.2 it could result in pushing constructed equivalence clauses
to incorrect places. (This accounts for bug #7604 from Bill MacArthur.)
Fix the first problem by adding a new test check_equivalence_delay() in
distribute_qual_to_rels, and fix the second one by adding code in
equivclass.c and called functions to set correct nullable_relids for
generated clauses. Although I believe the second part of this is not
currently necessary before 9.2, I chose to back-patch it anyway, partly to
keep the logic similar across branches and partly because it seems possible
we might find other reasons why we need valid values of nullable_relids in
the older branches.
Add regression tests illustrating these problems. In 9.0 and up, also
add test cases checking that we can push constants through outer joins,
since we've broken that optimization before and I nearly broke it again
with an overly simplistic patch for this problem.
2012-10-18 18:28:45 +02:00
|
|
|
nullable_relids); /* nullable_relids */
|
2007-01-20 21:45:41 +01:00
|
|
|
|
2010-12-31 02:24:55 +01:00
|
|
|
/* Set mergejoinability/hashjoinability flags */
|
2007-01-20 21:45:41 +01:00
|
|
|
check_mergejoinable(restrictinfo);
|
2010-12-31 02:24:55 +01:00
|
|
|
check_hashjoinable(restrictinfo);
|
2007-01-20 21:45:41 +01:00
|
|
|
|
|
|
|
return restrictinfo;
|
2001-10-18 18:11:42 +02:00
|
|
|
}
|
|
|
|
|
2000-07-24 05:11:01 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2000-02-15 21:49:31 +01:00
|
|
|
* CHECKS FOR MERGEJOINABLE AND HASHJOINABLE CLAUSES
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1999-08-16 04:17:58 +02:00
|
|
|
* check_mergejoinable
|
|
|
|
* If the restrictinfo's clause is mergejoinable, set the mergejoin
|
|
|
|
* info fields in the restrictinfo.
|
|
|
|
*
|
|
|
|
* Currently, we support mergejoin for binary opclauses where
|
2003-01-15 20:35:48 +01:00
|
|
|
* the operator is a mergejoinable operator. The arguments can be
|
|
|
|
* anything --- as long as there are no volatile functions in them.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1999-08-16 04:17:58 +02:00
|
|
|
static void
|
|
|
|
check_mergejoinable(RestrictInfo *restrictinfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-08-16 04:17:58 +02:00
|
|
|
Expr *clause = restrictinfo->clause;
|
2007-01-20 21:45:41 +01:00
|
|
|
Oid opno;
|
2010-10-31 02:55:20 +01:00
|
|
|
Node *leftarg;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
if (restrictinfo->pseudoconstant)
|
|
|
|
return;
|
2002-12-12 16:49:42 +01:00
|
|
|
if (!is_opclause(clause))
|
1999-08-16 04:17:58 +02:00
|
|
|
return;
|
2004-05-31 01:40:41 +02:00
|
|
|
if (list_length(((OpExpr *) clause)->args) != 2)
|
1999-08-16 04:17:58 +02:00
|
|
|
return;
|
1999-02-15 02:06:59 +01:00
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
opno = ((OpExpr *) clause)->opno;
|
2010-10-31 02:55:20 +01:00
|
|
|
leftarg = linitial(((OpExpr *) clause)->args);
|
1999-02-15 02:06:59 +01:00
|
|
|
|
2010-10-31 02:55:20 +01:00
|
|
|
if (op_mergejoinable(opno, exprType(leftarg)) &&
|
2003-01-15 20:35:48 +01:00
|
|
|
!contain_volatile_functions((Node *) clause))
|
2007-01-20 21:45:41 +01:00
|
|
|
restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Note: op_mergejoinable is just a hint; if we fail to find the operator
|
|
|
|
* in any btree opfamilies, mergeopfamilies remains NIL and so the clause
|
|
|
|
* is not treated as mergejoinable.
|
2007-01-20 21:45:41 +01:00
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1999-08-16 04:17:58 +02:00
|
|
|
* check_hashjoinable
|
|
|
|
* If the restrictinfo's clause is hashjoinable, set the hashjoin
|
|
|
|
* info fields in the restrictinfo.
|
|
|
|
*
|
|
|
|
* Currently, we support hashjoin for binary opclauses where
|
2003-08-04 02:43:34 +02:00
|
|
|
* the operator is a hashjoinable operator. The arguments can be
|
2003-01-15 20:35:48 +01:00
|
|
|
* anything --- as long as there are no volatile functions in them.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1999-08-16 04:17:58 +02:00
|
|
|
static void
|
|
|
|
check_hashjoinable(RestrictInfo *restrictinfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-08-16 04:17:58 +02:00
|
|
|
Expr *clause = restrictinfo->clause;
|
|
|
|
Oid opno;
|
2010-10-31 02:55:20 +01:00
|
|
|
Node *leftarg;
|
1999-02-15 02:06:59 +01:00
|
|
|
|
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
clauses containing no variables and no volatile functions. Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false. Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause. In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism. When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point. This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree. Per gripe from Phil Frost.
2006-07-01 20:38:33 +02:00
|
|
|
if (restrictinfo->pseudoconstant)
|
|
|
|
return;
|
2002-12-12 16:49:42 +01:00
|
|
|
if (!is_opclause(clause))
|
1999-08-16 04:17:58 +02:00
|
|
|
return;
|
2004-05-31 01:40:41 +02:00
|
|
|
if (list_length(((OpExpr *) clause)->args) != 2)
|
1999-08-16 04:17:58 +02:00
|
|
|
return;
|
|
|
|
|
2002-12-12 16:49:42 +01:00
|
|
|
opno = ((OpExpr *) clause)->opno;
|
2010-10-31 02:55:20 +01:00
|
|
|
leftarg = linitial(((OpExpr *) clause)->args);
|
1999-02-15 02:06:59 +01:00
|
|
|
|
2010-10-31 02:55:20 +01:00
|
|
|
if (op_hashjoinable(opno, exprType(leftarg)) &&
|
2003-01-15 20:35:48 +01:00
|
|
|
!contain_volatile_functions((Node *) clause))
|
1999-08-16 04:17:58 +02:00
|
|
|
restrictinfo->hashjoinoperator = opno;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|