diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 8 | ||||
| -rw-r--r-- | src/backend/optimizer/util/var.c | 121 | ||||
| -rw-r--r-- | src/backend/rewrite/rewriteManip.c | 11 |
3 files changed, 123 insertions, 17 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 199d27973b..3026fdf058 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -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; diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index cac0eee827..30f02de5c7 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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" @@ -29,12 +27,20 @@ typedef struct typedef struct { + int varno; + int sublevels_up; +} contain_whole_tuple_var_context; + +typedef struct +{ List *varlist; bool includeUpperVars; } pull_var_clause_context; 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; } diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 663b67708e..45115b8d04 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.56 2001/03/22 03:59:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.57 2001/04/18 20:42:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -765,8 +765,13 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context) if (this_varno == context->target_varno && this_varlevelsup == context->sublevels_up) { - Node *n = FindMatchingNew(context->targetlist, - var->varattno); + Node *n; + + /* band-aid: don't do the wrong thing with a whole-tuple Var */ + if (var->varattno == InvalidAttrNumber) + elog(ERROR, "ResolveNew: can't handle whole-tuple reference"); + + n = FindMatchingNew(context->targetlist, var->varattno); if (n == NULL) { |
