mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
IN clauses appearing at top level of WHERE can now be handled as joins.
There are two implementation techniques: the executor understands a new JOIN_IN jointype, which emits at most one matching row per left-hand row, or the result of the IN's sub-select can be fed through a DISTINCT filter and then joined as an ordinary relation. Along the way, some minor code cleanup in the optimizer; notably, break out most of the jointree-rearrangement preprocessing in planner.c and put it in a new file prep/prepjointree.c.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.46 2003/01/17 02:01:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.47 2003/01/20 18:54:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
@ -41,7 +42,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
List *rtable;
|
||||
Query *root;
|
||||
int sublevels_up;
|
||||
} flatten_join_alias_vars_context;
|
||||
|
||||
@ -50,10 +51,13 @@ static bool pull_varnos_walker(Node *node,
|
||||
static bool contain_var_reference_walker(Node *node,
|
||||
contain_var_reference_context *context);
|
||||
static bool contain_var_clause_walker(Node *node, void *context);
|
||||
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
|
||||
static bool contain_vars_above_level_walker(Node *node, int *sublevels_up);
|
||||
static bool pull_var_clause_walker(Node *node,
|
||||
pull_var_clause_context *context);
|
||||
static Node *flatten_join_alias_vars_mutator(Node *node,
|
||||
flatten_join_alias_vars_context *context);
|
||||
static List *alias_rtindex_list(Query *root, List *rtlist);
|
||||
|
||||
|
||||
/*
|
||||
@ -224,6 +228,103 @@ contain_var_clause_walker(Node *node, void *context)
|
||||
return expression_tree_walker(node, contain_var_clause_walker, context);
|
||||
}
|
||||
|
||||
/*
|
||||
* contain_vars_of_level
|
||||
* Recursively scan a clause to discover whether it contains any Var nodes
|
||||
* of the specified query level.
|
||||
*
|
||||
* Returns true if any such Var found.
|
||||
*
|
||||
* Will recurse into sublinks. Also, may be invoked directly on a Query.
|
||||
*/
|
||||
bool
|
||||
contain_vars_of_level(Node *node, int levelsup)
|
||||
{
|
||||
int sublevels_up = levelsup;
|
||||
|
||||
return query_or_expression_tree_walker(node,
|
||||
contain_vars_of_level_walker,
|
||||
(void *) &sublevels_up,
|
||||
0);
|
||||
}
|
||||
|
||||
static bool
|
||||
contain_vars_of_level_walker(Node *node, int *sublevels_up)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, Var))
|
||||
{
|
||||
if (((Var *) node)->varlevelsup == *sublevels_up)
|
||||
return true; /* abort tree traversal and return true */
|
||||
}
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
/* Recurse into subselects */
|
||||
bool result;
|
||||
|
||||
(*sublevels_up)++;
|
||||
result = query_tree_walker((Query *) node,
|
||||
contain_vars_of_level_walker,
|
||||
(void *) sublevels_up,
|
||||
0);
|
||||
(*sublevels_up)--;
|
||||
return result;
|
||||
}
|
||||
return expression_tree_walker(node,
|
||||
contain_vars_of_level_walker,
|
||||
(void *) sublevels_up);
|
||||
}
|
||||
|
||||
/*
|
||||
* contain_vars_above_level
|
||||
* Recursively scan a clause to discover whether it contains any Var nodes
|
||||
* above the specified query level. (For example, pass zero to detect
|
||||
* all nonlocal Vars.)
|
||||
*
|
||||
* Returns true if any such Var found.
|
||||
*
|
||||
* Will recurse into sublinks. Also, may be invoked directly on a Query.
|
||||
*/
|
||||
bool
|
||||
contain_vars_above_level(Node *node, int levelsup)
|
||||
{
|
||||
int sublevels_up = levelsup;
|
||||
|
||||
return query_or_expression_tree_walker(node,
|
||||
contain_vars_above_level_walker,
|
||||
(void *) &sublevels_up,
|
||||
0);
|
||||
}
|
||||
|
||||
static bool
|
||||
contain_vars_above_level_walker(Node *node, int *sublevels_up)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, Var))
|
||||
{
|
||||
if (((Var *) node)->varlevelsup > *sublevels_up)
|
||||
return true; /* abort tree traversal and return true */
|
||||
}
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
/* Recurse into subselects */
|
||||
bool result;
|
||||
|
||||
(*sublevels_up)++;
|
||||
result = query_tree_walker((Query *) node,
|
||||
contain_vars_above_level_walker,
|
||||
(void *) sublevels_up,
|
||||
0);
|
||||
(*sublevels_up)--;
|
||||
return result;
|
||||
}
|
||||
return expression_tree_walker(node,
|
||||
contain_vars_above_level_walker,
|
||||
(void *) sublevels_up);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* pull_var_clause
|
||||
@ -277,11 +378,11 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
||||
* to be applied directly to a Query node.
|
||||
*/
|
||||
Node *
|
||||
flatten_join_alias_vars(Node *node, List *rtable)
|
||||
flatten_join_alias_vars(Query *root, Node *node)
|
||||
{
|
||||
flatten_join_alias_vars_context context;
|
||||
|
||||
context.rtable = rtable;
|
||||
context.root = root;
|
||||
context.sublevels_up = 0;
|
||||
|
||||
return flatten_join_alias_vars_mutator(node, &context);
|
||||
@ -301,7 +402,7 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
|
||||
if (var->varlevelsup != context->sublevels_up)
|
||||
return node; /* no need to copy, really */
|
||||
rte = rt_fetch(var->varno, context->rtable);
|
||||
rte = rt_fetch(var->varno, context->root->rtable);
|
||||
if (rte->rtekind != RTE_JOIN)
|
||||
return node;
|
||||
Assert(var->varattno > 0);
|
||||
@ -309,6 +410,24 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
/* expand it; recurse in case join input is itself a join */
|
||||
return flatten_join_alias_vars_mutator(newvar, context);
|
||||
}
|
||||
if (IsA(node, InClauseInfo))
|
||||
{
|
||||
/* Copy the InClauseInfo node with correct mutation of subnodes */
|
||||
InClauseInfo *ininfo;
|
||||
|
||||
ininfo = (InClauseInfo *) expression_tree_mutator(node,
|
||||
flatten_join_alias_vars_mutator,
|
||||
(void *) context);
|
||||
/* now fix InClauseInfo's rtindex lists */
|
||||
if (context->sublevels_up == 0)
|
||||
{
|
||||
ininfo->lefthand = alias_rtindex_list(context->root,
|
||||
ininfo->lefthand);
|
||||
ininfo->righthand = alias_rtindex_list(context->root,
|
||||
ininfo->righthand);
|
||||
}
|
||||
return (Node *) ininfo;
|
||||
}
|
||||
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
@ -329,3 +448,27 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
/*
|
||||
* alias_rtindex_list: in a list of RT indexes, replace joins by their
|
||||
* underlying base relids
|
||||
*/
|
||||
static List *
|
||||
alias_rtindex_list(Query *root, List *rtlist)
|
||||
{
|
||||
List *result = NIL;
|
||||
List *l;
|
||||
|
||||
foreach(l, rtlist)
|
||||
{
|
||||
int rtindex = lfirsti(l);
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = rt_fetch(rtindex, root->rtable);
|
||||
if (rte->rtekind == RTE_JOIN)
|
||||
result = nconc(result, get_relids_for_join(root, rtindex));
|
||||
else
|
||||
result = lappendi(result, rtindex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user