summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/plan/planner.c8
-rw-r--r--src/backend/optimizer/util/var.c121
-rw-r--r--src/backend/rewrite/rewriteManip.c11
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)
{