1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Make the world safe for passing whole rows of views to functions. This

already worked fine for whole rows of tables, but not so well for views...
This commit is contained in:
Tom Lane
2001-04-18 20:42:56 +00:00
parent e4c06b2125
commit d5096af2c4
7 changed files with 161 additions and 44 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.103 2001/04/01 22:37:19 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.104 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -271,8 +271,12 @@ pull_up_subqueries(Query *parse, Node *jtnode)
/*
* Is this a subquery RTE, and if so, is the subquery simple
* enough to pull up? (If not, do nothing at this node.)
*
* Note: even if the subquery itself is simple enough, we can't
* pull it up if there is a reference to its whole tuple result.
*/
if (subquery && is_simple_subquery(subquery))
if (subquery && is_simple_subquery(subquery) &&
!contain_whole_tuple_var((Node *) parse, varno, 0))
{
int rtoffset;
Node *subjointree;

View File

@ -8,12 +8,10 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.30 2001/03/22 03:59:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.31 2001/04/18 20:42:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/types.h>
#include "postgres.h"
#include "nodes/plannodes.h"
@ -27,6 +25,12 @@ typedef struct
int sublevels_up;
} pull_varnos_context;
typedef struct
{
int varno;
int sublevels_up;
} contain_whole_tuple_var_context;
typedef struct
{
List *varlist;
@ -35,6 +39,8 @@ typedef struct
static bool pull_varnos_walker(Node *node,
pull_varnos_context *context);
static bool contain_whole_tuple_var_walker(Node *node,
contain_whole_tuple_var_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);
@ -46,11 +52,10 @@ static bool pull_var_clause_walker(Node *node,
* 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.
* NOTE: this 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)
@ -122,17 +127,105 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
(void *) context);
}
/*
* contain_whole_tuple_var
*
* Detect whether a parsetree contains any references to the whole
* tuple of a given rtable entry (ie, a Var with varattno = 0).
*
* NOTE: this 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 entry! But when we find a completed
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
bool
contain_whole_tuple_var(Node *node, int varno, int levelsup)
{
contain_whole_tuple_var_context context;
context.varno = varno;
context.sublevels_up = levelsup;
/*
* 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))
return query_tree_walker((Query *) node,
contain_whole_tuple_var_walker,
(void *) &context, true);
else
return contain_whole_tuple_var_walker(node, &context);
}
static bool
contain_whole_tuple_var_walker(Node *node,
contain_whole_tuple_var_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->varno &&
var->varlevelsup == context->sublevels_up &&
var->varattno == InvalidAttrNumber)
return true;
return false;
}
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 (contain_whole_tuple_var_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
context))
return true;
if (contain_whole_tuple_var_walker((Node *) expr->args,
context))
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_whole_tuple_var_walker,
(void *) context, true);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, contain_whole_tuple_var_walker,
(void *) context);
}
/*
* contain_var_clause
* Recursively scan a clause to discover whether it contains any Var nodes
* (of the current query level).
*
* Returns true if any varnode found.
*
* Does not examine subqueries, therefore must only be used after reduction
* of sublinks to subplans!
*/
bool
contain_var_clause(Node *clause)
contain_var_clause(Node *node)
{
return contain_var_clause_walker(clause, NULL);
return contain_var_clause_walker(node, NULL);
}
static bool
@ -150,6 +243,7 @@ contain_var_clause_walker(Node *node, void *context)
return expression_tree_walker(node, contain_var_clause_walker, context);
}
/*
* pull_var_clause
* Recursively pulls all var nodes from an expression clause.
@ -160,16 +254,19 @@ contain_var_clause_walker(Node *node, void *context)
*
* Returns list of varnodes found. Note the varnodes themselves are not
* copied, only referenced.
*
* Does not examine subqueries, therefore must only be used after reduction
* of sublinks to subplans!
*/
List *
pull_var_clause(Node *clause, bool includeUpperVars)
pull_var_clause(Node *node, bool includeUpperVars)
{
pull_var_clause_context context;
context.varlist = NIL;
context.includeUpperVars = includeUpperVars;
pull_var_clause_walker(clause, &context);
pull_var_clause_walker(node, &context);
return context.varlist;
}