mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Implement SEMI and ANTI joins in the planner and executor. (Semijoins replace
the old JOIN_IN code, but antijoins are new functionality.) Teach the planner to convert appropriate EXISTS and NOT EXISTS subqueries into semi and anti joins respectively. Also, LEFT JOINs with suitable upper-level IS NULL filters are recognized as being anti joins. Unify the InClauseInfo and OuterJoinInfo infrastructure into "SpecialJoinInfo". With that change, it becomes possible to associate a SpecialJoinInfo with every join attempt, which permits some cleanup of join selectivity estimation. That needs to be taken much further than this patch does, but the next step is to change the API for oprjoin selectivity functions, which seems like material for a separate patch. So for the moment the output size estimates for semi and especially anti joins are quite bogus.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.240 2008/08/07 01:11:50 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.241 2008/08/14 18:47:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -55,8 +55,7 @@ planner_hook_type planner_hook = NULL;
|
||||
#define EXPRKIND_RTFUNC 2
|
||||
#define EXPRKIND_VALUES 3
|
||||
#define EXPRKIND_LIMIT 4
|
||||
#define EXPRKIND_ININFO 5
|
||||
#define EXPRKIND_APPINFO 6
|
||||
#define EXPRKIND_APPINFO 5
|
||||
|
||||
|
||||
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
|
||||
@ -255,6 +254,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
PlannerInfo *root;
|
||||
Plan *plan;
|
||||
List *newHaving;
|
||||
bool hasOuterJoins;
|
||||
ListCell *l;
|
||||
|
||||
/* Create a PlannerInfo data structure for this subquery */
|
||||
@ -265,23 +265,22 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
root->planner_cxt = CurrentMemoryContext;
|
||||
root->init_plans = NIL;
|
||||
root->eq_classes = NIL;
|
||||
root->in_info_list = NIL;
|
||||
root->append_rel_list = NIL;
|
||||
|
||||
/*
|
||||
* Look for IN clauses at the top level of WHERE, and transform them into
|
||||
* joins. Note that this step only handles IN clauses originally at top
|
||||
* level of WHERE; if we pull up any subqueries below, their INs are
|
||||
* processed just before pulling them up.
|
||||
* Look for ANY and EXISTS SubLinks at the top level of WHERE, and try to
|
||||
* transform them into joins. Note that this step only handles SubLinks
|
||||
* originally at top level of WHERE; if we pull up any subqueries below,
|
||||
* their SubLinks are processed just before pulling them up.
|
||||
*/
|
||||
if (parse->hasSubLinks)
|
||||
parse->jointree->quals = pull_up_IN_clauses(root,
|
||||
parse->jointree->quals);
|
||||
parse->jointree->quals = pull_up_sublinks(root,
|
||||
parse->jointree->quals);
|
||||
|
||||
/*
|
||||
* Scan the rangetable for set-returning functions, and inline them
|
||||
* if possible (producing subqueries that might get pulled up next).
|
||||
* Recursion issues here are handled in the same way as for IN clauses.
|
||||
* Recursion issues here are handled in the same way as for SubLinks.
|
||||
*/
|
||||
inline_set_returning_functions(root);
|
||||
|
||||
@ -295,16 +294,11 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
/*
|
||||
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
|
||||
* avoid the expense of doing flatten_join_alias_vars(). Also check for
|
||||
* outer joins --- if none, we can skip reduce_outer_joins() and some
|
||||
* other processing. This must be done after we have done
|
||||
* pull_up_subqueries, of course.
|
||||
*
|
||||
* Note: if reduce_outer_joins manages to eliminate all outer joins,
|
||||
* root->hasOuterJoins is not reset currently. This is OK since its
|
||||
* purpose is merely to suppress unnecessary processing in simple cases.
|
||||
* outer joins --- if none, we can skip reduce_outer_joins().
|
||||
* This must be done after we have done pull_up_subqueries, of course.
|
||||
*/
|
||||
root->hasJoinRTEs = false;
|
||||
root->hasOuterJoins = false;
|
||||
hasOuterJoins = false;
|
||||
foreach(l, parse->rtable)
|
||||
{
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
||||
@ -314,7 +308,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
root->hasJoinRTEs = true;
|
||||
if (IS_OUTER_JOIN(rte->jointype))
|
||||
{
|
||||
root->hasOuterJoins = true;
|
||||
hasOuterJoins = true;
|
||||
/* Can quit scanning once we find an outer join */
|
||||
break;
|
||||
}
|
||||
@ -362,9 +356,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
parse->limitCount = preprocess_expression(root, parse->limitCount,
|
||||
EXPRKIND_LIMIT);
|
||||
|
||||
root->in_info_list = (List *)
|
||||
preprocess_expression(root, (Node *) root->in_info_list,
|
||||
EXPRKIND_ININFO);
|
||||
root->append_rel_list = (List *)
|
||||
preprocess_expression(root, (Node *) root->append_rel_list,
|
||||
EXPRKIND_APPINFO);
|
||||
@ -442,7 +433,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
* This step is most easily done after we've done expression
|
||||
* preprocessing.
|
||||
*/
|
||||
if (root->hasOuterJoins)
|
||||
if (hasOuterJoins)
|
||||
reduce_outer_joins(root);
|
||||
|
||||
/*
|
||||
@ -639,20 +630,15 @@ inheritance_planner(PlannerInfo *root)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Generate modified query with this rel as target. We have to be
|
||||
* prepared to translate varnos in in_info_list as well as in the
|
||||
* Query proper.
|
||||
* Generate modified query with this rel as target.
|
||||
*/
|
||||
memcpy(&subroot, root, sizeof(PlannerInfo));
|
||||
subroot.parse = (Query *)
|
||||
adjust_appendrel_attrs((Node *) parse,
|
||||
appinfo);
|
||||
subroot.in_info_list = (List *)
|
||||
adjust_appendrel_attrs((Node *) root->in_info_list,
|
||||
appinfo);
|
||||
subroot.init_plans = NIL;
|
||||
/* There shouldn't be any OJ info to translate, as yet */
|
||||
Assert(subroot.oj_info_list == NIL);
|
||||
Assert(subroot.join_info_list == NIL);
|
||||
|
||||
/* Generate plan */
|
||||
subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );
|
||||
|
Reference in New Issue
Block a user