mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
First cut at full support for OUTER JOINs. There are still a few loose
ends to clean up (see my message of same date to pghackers), but mostly it works. INITDB REQUIRED!
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.26 2000/04/12 17:15:24 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.27 2000/09/12 21:06:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,17 +16,25 @@
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/var.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
List *varlist;
|
||||
int sublevels_up;
|
||||
} pull_varnos_context;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
List *varlist;
|
||||
bool includeUpperVars;
|
||||
} pull_var_clause_context;
|
||||
|
||||
static bool pull_varnos_walker(Node *node, List **listptr);
|
||||
static bool pull_varnos_walker(Node *node,
|
||||
pull_varnos_context *context);
|
||||
static bool contain_var_clause_walker(Node *node, void *context);
|
||||
static bool pull_var_clause_walker(Node *node,
|
||||
pull_var_clause_context *context);
|
||||
@@ -35,21 +43,39 @@ static bool pull_var_clause_walker(Node *node,
|
||||
/*
|
||||
* pull_varnos
|
||||
*
|
||||
* Create a list of all the distinct varnos present in a parsetree
|
||||
* (tlist or qual). Note that only varnos attached to level-zero
|
||||
* Vars are considered --- upper Vars refer to some other rtable!
|
||||
* Create a list of all the distinct varnos present in a parsetree.
|
||||
* Only varnos that reference level-zero rtable entries are considered.
|
||||
*
|
||||
* NOTE: unlike other routines in this file, pull_varnos() is used on
|
||||
* not-yet-planned expressions. It may therefore find bare SubLinks,
|
||||
* and if so it needs to recurse into them to look for uplevel references
|
||||
* to the desired rtable level! But when we find a completed SubPlan,
|
||||
* we only need to look at the parameters passed to the subplan.
|
||||
*/
|
||||
List *
|
||||
pull_varnos(Node *node)
|
||||
{
|
||||
List *result = NIL;
|
||||
pull_varnos_context context;
|
||||
|
||||
pull_varnos_walker(node, &result);
|
||||
return result;
|
||||
context.varlist = NIL;
|
||||
context.sublevels_up = 0;
|
||||
|
||||
/*
|
||||
* Must be prepared to start with a Query or a bare expression tree;
|
||||
* if it's a Query, go straight to query_tree_walker to make sure that
|
||||
* sublevels_up doesn't get incremented prematurely.
|
||||
*/
|
||||
if (node && IsA(node, Query))
|
||||
query_tree_walker((Query *) node, pull_varnos_walker,
|
||||
(void *) &context);
|
||||
else
|
||||
pull_varnos_walker(node, &context);
|
||||
|
||||
return context.varlist;
|
||||
}
|
||||
|
||||
static bool
|
||||
pull_varnos_walker(Node *node, List **listptr)
|
||||
pull_varnos_walker(Node *node, pull_varnos_context *context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
@@ -57,11 +83,42 @@ pull_varnos_walker(Node *node, List **listptr)
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
|
||||
if (var->varlevelsup == 0 && !intMember(var->varno, *listptr))
|
||||
*listptr = lconsi(var->varno, *listptr);
|
||||
if (var->varlevelsup == context->sublevels_up &&
|
||||
!intMember(var->varno, context->varlist))
|
||||
context->varlist = lconsi(var->varno, context->varlist);
|
||||
return false;
|
||||
}
|
||||
return expression_tree_walker(node, pull_varnos_walker, (void *) listptr);
|
||||
if (is_subplan(node))
|
||||
{
|
||||
/*
|
||||
* Already-planned subquery. Examine the args list (parameters
|
||||
* to be passed to subquery), as well as the "oper" list which
|
||||
* is executed by the outer query. But short-circuit recursion into
|
||||
* the subquery itself, which would be a waste of effort.
|
||||
*/
|
||||
Expr *expr = (Expr *) node;
|
||||
|
||||
if (pull_varnos_walker((Node*) ((SubPlan*) expr->oper)->sublink->oper,
|
||||
context))
|
||||
return true;
|
||||
if (pull_varnos_walker((Node *) expr->args,
|
||||
context))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (IsA(node, Query))
|
||||
{
|
||||
/* Recurse into not-yet-planned subquery */
|
||||
bool result;
|
||||
|
||||
context->sublevels_up++;
|
||||
result = query_tree_walker((Query *) node, pull_varnos_walker,
|
||||
(void *) context);
|
||||
context->sublevels_up--;
|
||||
return result;
|
||||
}
|
||||
return expression_tree_walker(node, pull_varnos_walker,
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user