diff options
Diffstat (limited to 'src/backend/rewrite/rewriteManip.c')
| -rw-r--r-- | src/backend/rewrite/rewriteManip.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 3943b9d237..0d3dbe7d6e 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.71 2003/02/08 20:20:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.72 2003/06/06 15:04:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,13 @@ #include "utils/lsyscache.h" -static bool checkExprHasAggs_walker(Node *node, void *context); +typedef struct +{ + int sublevels_up; +} checkExprHasAggs_context; + +static bool checkExprHasAggs_walker(Node *node, + checkExprHasAggs_context *context); static bool checkExprHasSubLink_walker(Node *node, void *context); static Relids offset_relid_set(Relids relids, int offset); static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid); @@ -32,29 +38,55 @@ static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid); * checkExprHasAggs - * Queries marked hasAggs might not have them any longer after * rewriting. Check it. + * + * The objective of this routine is to detect whether there are aggregates + * belonging to the initial query level. Aggregates belonging to subqueries + * or outer queries do NOT cause a true result. We must recurse into + * subqueries to detect outer-reference aggregates that logically belong to + * the initial query level. */ bool checkExprHasAggs(Node *node) { + checkExprHasAggs_context context; + + context.sublevels_up = 0; /* - * If a Query is passed, examine it --- but we will not recurse into - * sub-Queries. + * Must be prepared to start with a Query or a bare expression tree; + * if it's a Query, we don't want to increment sublevels_up. */ return query_or_expression_tree_walker(node, checkExprHasAggs_walker, - NULL, - QTW_IGNORE_RT_SUBQUERIES); + (void *) &context, + 0); } static bool -checkExprHasAggs_walker(Node *node, void *context) +checkExprHasAggs_walker(Node *node, checkExprHasAggs_context *context) { if (node == NULL) return false; if (IsA(node, Aggref)) - return true; /* abort the tree traversal and return + { + if (((Aggref *) node)->agglevelsup == context->sublevels_up) + return true; /* abort the tree traversal and return * true */ - return expression_tree_walker(node, checkExprHasAggs_walker, context); + /* else fall through to examine argument */ + } + if (IsA(node, Query)) + { + /* Recurse into subselects */ + bool result; + + context->sublevels_up++; + result = query_tree_walker((Query *) node, + checkExprHasAggs_walker, + (void *) context, 0); + context->sublevels_up--; + return result; + } + return expression_tree_walker(node, checkExprHasAggs_walker, + (void *) context); } /* @@ -380,6 +412,8 @@ adjust_relid_set(Relids relids, int oldrelid, int newrelid) * that sublink are not affected, only outer references to vars that belong * to the expression's original query level or parents thereof. * + * Aggref nodes are adjusted similarly. + * * NOTE: although this has the form of a walker, we cheat and modify the * Var nodes in-place. The given expression tree should have been copied * earlier to ensure that no unwanted side-effects occur! @@ -403,7 +437,15 @@ IncrementVarSublevelsUp_walker(Node *node, if (var->varlevelsup >= context->min_sublevels_up) var->varlevelsup += context->delta_sublevels_up; - return false; + return false; /* done here */ + } + if (IsA(node, Aggref)) + { + Aggref *agg = (Aggref *) node; + + if (agg->agglevelsup >= context->min_sublevels_up) + agg->agglevelsup += context->delta_sublevels_up; + /* fall through to recurse into argument */ } if (IsA(node, Query)) { |
