From a4d82dd4b4725c12a64d87967719f7690a054cbd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 17 Jan 2003 02:01:21 +0000 Subject: [PATCH] Adjust API of expression_tree_mutator and query_tree_mutator to simplify callers. It turns out the common case is that the caller does want to recurse into sub-queries, so push support for that into these subroutines. --- src/backend/optimizer/plan/subselect.c | 10 +- src/backend/optimizer/prep/prepunion.c | 16 ++- src/backend/optimizer/util/clauses.c | 101 ++++++++++++++---- src/backend/optimizer/util/var.c | 97 +++-------------- src/backend/rewrite/rewriteDefine.c | 4 +- src/backend/rewrite/rewriteHandler.c | 4 +- src/backend/rewrite/rewriteManip.c | 139 ++++++++----------------- src/include/optimizer/clauses.h | 16 ++- 8 files changed, 167 insertions(+), 220 deletions(-) diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 3c72199777..b30454dcae 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.66 2003/01/13 18:10:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.67 2003/01/17 02:01:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -628,12 +628,12 @@ process_sublinks_mutator(Node *node, bool *isTopQual) } /* - * Note that we will never see a SubPlan expression in the input - * (since this is the very routine that creates 'em to begin with). So - * the code in expression_tree_mutator() that might do inappropriate - * things with SubPlans or SubLinks will not be exercised. + * We should never see a SubPlan expression in the input (since this is + * the very routine that creates 'em to begin with). We shouldn't find + * ourselves invoked directly on a Query, either. */ Assert(!is_subplan(node)); + Assert(!IsA(node, Query)); /* * If we recurse down through anything other than a List node, we are diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 4af395b860..807364fac8 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.86 2003/01/15 19:35:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.87 2003/01/17 02:01:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,11 +34,6 @@ #include "parser/parsetree.h" #include "utils/lsyscache.h" -/* macros borrowed from expression_tree_mutator */ - -#define FLATCOPY(newnode, node, nodetype) \ - ( (newnode) = makeNode(nodetype), \ - memcpy((newnode), (node), sizeof(nodetype)) ) typedef struct { @@ -765,12 +760,12 @@ adjust_inherited_attrs(Node *node, */ if (node && IsA(node, Query)) { - Query *query = (Query *) node; Query *newnode; - FLATCOPY(newnode, query, Query); - query_tree_mutator(newnode, adjust_inherited_attrs_mutator, - (void *) &context, QTW_IGNORE_SUBQUERIES); + newnode = query_tree_mutator((Query *) node, + adjust_inherited_attrs_mutator, + (void *) &context, + QTW_IGNORE_RT_SUBQUERIES); if (newnode->resultRelation == old_rt_index) { newnode->resultRelation = new_rt_index; @@ -899,6 +894,7 @@ adjust_inherited_attrs_mutator(Node *node, * already have been converted to subplans before we see them. */ Assert(!IsA(node, SubLink)); + Assert(!IsA(node, Query)); /* * BUT: although we don't need to recurse into subplans, we do need to diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 233a8cb894..d9bdfec54e 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.122 2003/01/15 19:35:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.123 2003/01/17 02:01:16 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2153,7 +2153,7 @@ substitute_actual_parameters_mutator(Node *node, * { * adjust context for subquery; * result = query_tree_walker((Query *) node, my_walker, context, - * 0); // to visit rtable items too + * 0); // adjust flags as needed * restore context if needed; * return result; * } @@ -2414,7 +2414,7 @@ query_tree_walker(Query *query, /* nothing to do */ break; case RTE_SUBQUERY: - if (! (flags & QTW_IGNORE_SUBQUERIES)) + if (! (flags & QTW_IGNORE_RT_SUBQUERIES)) if (walker(rte->subquery, context)) return true; break; @@ -2477,17 +2477,22 @@ query_tree_walker(Query *query, * expression_tree_mutator include all those normally found in target lists * and qualifier clauses during the planning stage. * + * expression_tree_mutator will handle SubLink nodes by recursing normally + * into the "lefthand" arguments (which are expressions belonging to the outer + * plan). It will also call the mutator on the sub-Query node; however, when + * expression_tree_mutator itself is called on a Query node, it does nothing + * and returns the unmodified Query node. The net effect is that unless the + * mutator does something special at a Query node, sub-selects will not be + * visited or modified; the original sub-select will be linked to by the new + * SubLink node. Mutators that want to descend into sub-selects will usually + * do so by recognizing Query nodes and calling query_tree_mutator (below). + * * expression_tree_mutator will handle a SubPlan node by recursing into * the "exprs" and "args" lists (which belong to the outer plan), but it * will simply copy the link to the inner plan, since that's typically what * expression tree mutators want. A mutator that wants to modify the subplan * can force appropriate behavior by recognizing SubPlan expression nodes * and doing the right thing. - * - * SubLink nodes are handled by recursing into the "lefthand" argument list - * only. (A SubLink will be seen only if the tree has not yet been - * processed by subselect.c.) Again, this can be overridden by the mutator, - * but it seems to be the most useful default behavior. *-------------------- */ @@ -2593,14 +2598,16 @@ expression_tree_mutator(Node *node, break; case T_SubLink: { - /* - * We transform the lefthand side, but not the subquery. - */ SubLink *sublink = (SubLink *) node; SubLink *newnode; FLATCOPY(newnode, sublink, SubLink); MUTATE(newnode->lefthand, sublink->lefthand, List *); + /* + * Also invoke the mutator on the sublink's Query node, so + * it can recurse into the sub-query if it wants to. + */ + MUTATE(newnode->subselect, sublink->subselect, Node *); return (Node *) newnode; } break; @@ -2707,6 +2714,9 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; + case T_Query: + /* Do nothing with a sub-Query, per discussion above */ + return node; case T_List: { /* @@ -2781,17 +2791,17 @@ expression_tree_mutator(Node *node, * mutator intends to descend into subqueries. It is also useful for * descending into subqueries within a mutator. * - * The specified Query node is modified-in-place; do a FLATCOPY() beforehand - * if you don't want to change the original. All substructure is safely - * copied, however. - * - * Some callers want to suppress mutating of certain items in the sub-Query, + * Some callers want to suppress mutating of certain items in the Query, * typically because they need to process them specially, or don't actually * want to recurse into subqueries. This is supported by the flags argument, * which is the bitwise OR of flag values to suppress mutating of * indicated items. (More flag bits may be added as needed.) + * + * Normally the Query node itself is copied, but some callers want it to be + * modified in-place; they must pass QTW_DONT_COPY_QUERY in flags. All + * modified substructure is safely copied in any case. */ -void +Query * query_tree_mutator(Query *query, Node *(*mutator) (), void *context, @@ -2802,6 +2812,14 @@ query_tree_mutator(Query *query, Assert(query != NULL && IsA(query, Query)); + if (! (flags & QTW_DONT_COPY_QUERY)) + { + Query *newquery; + + FLATCOPY(newquery, query, Query); + query = newquery; + } + MUTATE(query->targetList, query->targetList, List *); MUTATE(query->jointree, query->jointree, FromExpr *); MUTATE(query->setOperations, query->setOperations, Node *); @@ -2818,7 +2836,7 @@ query_tree_mutator(Query *query, /* nothing to do, don't bother to make a copy */ break; case RTE_SUBQUERY: - if (! (flags & QTW_IGNORE_SUBQUERIES)) + if (! (flags & QTW_IGNORE_RT_SUBQUERIES)) { FLATCOPY(newrte, rte, RangeTblEntry); CHECKFLATCOPY(newrte->subquery, rte->subquery, Query); @@ -2843,4 +2861,51 @@ query_tree_mutator(Query *query, newrt = lappend(newrt, rte); } query->rtable = newrt; + return query; +} + +/* + * query_or_expression_tree_walker --- hybrid form + * + * This routine will invoke query_tree_walker if called on a Query node, + * else will invoke the walker directly. This is a useful way of starting + * the recursion when the walker's normal change of state is not appropriate + * for the outermost Query node. + */ +bool +query_or_expression_tree_walker(Node *node, + bool (*walker) (), + void *context, + int flags) +{ + if (node && IsA(node, Query)) + return query_tree_walker((Query *) node, + walker, + context, + flags); + else + return walker(node, context); +} + +/* + * query_or_expression_tree_mutator --- hybrid form + * + * This routine will invoke query_tree_mutator if called on a Query node, + * else will invoke the mutator directly. This is a useful way of starting + * the recursion when the mutator's normal change of state is not appropriate + * for the outermost Query node. + */ +Node * +query_or_expression_tree_mutator(Node *node, + Node *(*mutator) (), + void *context, + int flags) +{ + if (node && IsA(node, Query)) + return (Node *) query_tree_mutator((Query *) node, + mutator, + context, + flags); + else + return mutator(node, context); } diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 47db90ad8a..1eb9d9774e 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.45 2003/01/16 18:26:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.46 2003/01/17 02:01:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,16 +20,6 @@ #include "parser/parsetree.h" -/* macros borrowed from expression_tree_mutator */ - -#define FLATCOPY(newnode, node, nodetype) \ - ( (newnode) = makeNode(nodetype), \ - memcpy((newnode), (node), sizeof(nodetype)) ) - -#define MUTATE(newfield, oldfield, fieldtype, mutator, context) \ - ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) ) - - typedef struct { List *varlist; @@ -87,14 +77,12 @@ pull_varnos(Node *node) /* * 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 it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - query_tree_walker((Query *) node, pull_varnos_walker, - (void *) &context, 0); - else - pull_varnos_walker(node, &context); + query_or_expression_tree_walker(node, + pull_varnos_walker, + (void *) &context, + 0); return context.varlist; } @@ -113,24 +101,6 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) context->varlist = lconsi(var->varno, context->varlist); return false; } - if (is_subplan(node)) - { - /* - * Already-planned subquery. Examine the args list (parameters to - * be passed to subquery), as well as the exprs list which is - * executed by the outer query. But short-circuit recursion into - * the subquery itself, which would be a waste of effort. - */ - SubPlan *subplan = (SubPlan *) node; - - if (pull_varnos_walker((Node *) subplan->exprs, - context)) - return true; - if (pull_varnos_walker((Node *) subplan->args, - context)) - return true; - return false; - } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ @@ -169,15 +139,12 @@ contain_var_reference(Node *node, int varno, int varattno, int 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 it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - return query_tree_walker((Query *) node, - contain_var_reference_walker, - (void *) &context, 0); - else - return contain_var_reference_walker(node, &context); + return query_or_expression_tree_walker(node, + contain_var_reference_walker, + (void *) &context, + 0); } static bool @@ -196,24 +163,6 @@ contain_var_reference_walker(Node *node, 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 exprs list which is - * executed by the outer query. But short-circuit recursion into - * the subquery itself, which would be a waste of effort. - */ - SubPlan *subplan = (SubPlan *) node; - - if (contain_var_reference_walker((Node *) subplan->exprs, - context)) - return true; - if (contain_var_reference_walker((Node *) subplan->args, - context)) - return true; - return false; - } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ @@ -361,32 +310,16 @@ flatten_join_alias_vars_mutator(Node *node, return flatten_join_alias_vars_mutator(newvar, context); } - /* - * Since expression_tree_mutator won't touch subselects, we have to - * handle them specially. - */ - if (IsA(node, SubLink)) - { - SubLink *sublink = (SubLink *) node; - SubLink *newnode; - - FLATCOPY(newnode, sublink, SubLink); - MUTATE(newnode->lefthand, sublink->lefthand, List *, - flatten_join_alias_vars_mutator, context); - MUTATE(newnode->subselect, sublink->subselect, Node *, - flatten_join_alias_vars_mutator, context); - return (Node *) newnode; - } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ - Query *query = (Query *) node; Query *newnode; - FLATCOPY(newnode, query, Query); context->sublevels_up++; - query_tree_mutator(newnode, flatten_join_alias_vars_mutator, - (void *) context, QTW_IGNORE_JOINALIASES); + newnode = query_tree_mutator((Query *) node, + flatten_join_alias_vars_mutator, + (void *) context, + QTW_IGNORE_JOINALIASES); context->sublevels_up--; return (Node *) newnode; } diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 3d13b9dd42..fb7412ca05 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.81 2002/12/05 04:04:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.82 2003/01/17 02:01:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -467,7 +467,7 @@ setRuleCheckAsUser(Query *qry, AclId userid) /* ignore subqueries in rtable because we already processed them */ if (qry->hasSubLinks) query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) &userid, - QTW_IGNORE_SUBQUERIES); + QTW_IGNORE_RT_SUBQUERIES); } /* diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index c19d15b4f0..5ddee1ab19 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.115 2002/12/17 01:18:32 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.116 2003/01/17 02:01:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -820,7 +820,7 @@ fireRIRrules(Query *parsetree) */ if (parsetree->hasSubLinks) query_tree_walker(parsetree, fireRIRonSubLink, NULL, - QTW_IGNORE_SUBQUERIES); + QTW_IGNORE_RT_SUBQUERIES); /* * If the query was marked having aggregates, check if this is still diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 22e7eee306..4a4f6824b7 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.68 2002/12/12 15:49:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.69 2003/01/17 02:01:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,15 +22,6 @@ #include "utils/lsyscache.h" -/* macros borrowed from expression_tree_mutator */ - -#define FLATCOPY(newnode, node, nodetype) \ - ( (newnode) = makeNode(nodetype), \ - memcpy((newnode), (node), sizeof(nodetype)) ) - -#define MUTATE(newfield, oldfield, fieldtype, mutator, context) \ - ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) ) - static bool checkExprHasAggs_walker(Node *node, void *context); static bool checkExprHasSubLink_walker(Node *node, void *context); @@ -47,11 +38,10 @@ checkExprHasAggs(Node *node) * If a Query is passed, examine it --- but we will not recurse into * sub-Queries. */ - if (node && IsA(node, Query)) - return query_tree_walker((Query *) node, checkExprHasAggs_walker, - NULL, QTW_IGNORE_SUBQUERIES); - else - return checkExprHasAggs_walker(node, NULL); + return query_or_expression_tree_walker(node, + checkExprHasAggs_walker, + NULL, + QTW_IGNORE_RT_SUBQUERIES); } static bool @@ -77,11 +67,10 @@ checkExprHasSubLink(Node *node) * If a Query is passed, examine it --- but we will not recurse into * sub-Queries. */ - if (node && IsA(node, Query)) - return query_tree_walker((Query *) node, checkExprHasSubLink_walker, - NULL, QTW_IGNORE_SUBQUERIES); - else - return checkExprHasSubLink_walker(node, NULL); + return query_or_expression_tree_walker(node, + checkExprHasSubLink_walker, + NULL, + QTW_IGNORE_RT_SUBQUERIES); } static bool @@ -380,14 +369,12 @@ IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, /* * 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 it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - query_tree_walker((Query *) node, IncrementVarSublevelsUp_walker, - (void *) &context, 0); - else - IncrementVarSublevelsUp_walker(node, &context); + query_or_expression_tree_walker(node, + IncrementVarSublevelsUp_walker, + (void *) &context, + 0); } @@ -461,14 +448,12 @@ rangeTableEntry_used(Node *node, int rt_index, int sublevels_up) /* * 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 it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - return query_tree_walker((Query *) node, rangeTableEntry_used_walker, - (void *) &context, 0); - else - return rangeTableEntry_used_walker(node, &context); + return query_or_expression_tree_walker(node, + rangeTableEntry_used_walker, + (void *) &context, + 0); } @@ -527,14 +512,12 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up) /* * 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 it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - return query_tree_walker((Query *) node, attribute_used_walker, - (void *) &context, 0); - else - return attribute_used_walker(node, &context); + return query_or_expression_tree_walker(node, + attribute_used_walker, + (void *) &context, + 0); } @@ -820,30 +803,16 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context) /* otherwise fall through to copy the var normally */ } - /* - * Since expression_tree_mutator won't touch subselects, we have to - * handle them specially. - */ - if (IsA(node, SubLink)) - { - SubLink *sublink = (SubLink *) node; - SubLink *newnode; - - FLATCOPY(newnode, sublink, SubLink); - MUTATE(newnode->lefthand, sublink->lefthand, List *, - ResolveNew_mutator, context); - MUTATE(newnode->subselect, sublink->subselect, Node *, - ResolveNew_mutator, context); - return (Node *) newnode; - } if (IsA(node, Query)) { - Query *query = (Query *) node; + /* Recurse into RTE subquery or not-yet-planned sublink subquery */ Query *newnode; - FLATCOPY(newnode, query, Query); context->sublevels_up++; - query_tree_mutator(newnode, ResolveNew_mutator, context, 0); + newnode = query_tree_mutator((Query *) node, + ResolveNew_mutator, + (void *) context, + 0); context->sublevels_up--; return (Node *) newnode; } @@ -865,21 +834,12 @@ ResolveNew(Node *node, int target_varno, int sublevels_up, /* * Must be prepared to start with a Query or a bare expression tree; - * if it's a Query, go straight to query_tree_mutator to make sure - * that sublevels_up doesn't get incremented prematurely. + * if it's a Query, we don't want to increment sublevels_up. */ - if (node && IsA(node, Query)) - { - Query *query = (Query *) node; - Query *newnode; - - FLATCOPY(newnode, query, Query); - query_tree_mutator(newnode, ResolveNew_mutator, - (void *) &context, 0); - return (Node *) newnode; - } - else - return ResolveNew_mutator(node, &context); + return query_or_expression_tree_mutator(node, + ResolveNew_mutator, + (void *) &context, + 0); } @@ -959,31 +919,16 @@ HandleRIRAttributeRule_mutator(Node *node, /* otherwise fall through to copy the var normally */ } - /* - * Since expression_tree_mutator won't touch subselects, we have to - * handle them specially. - */ - if (IsA(node, SubLink)) - { - SubLink *sublink = (SubLink *) node; - SubLink *newnode; - - FLATCOPY(newnode, sublink, SubLink); - MUTATE(newnode->lefthand, sublink->lefthand, List *, - HandleRIRAttributeRule_mutator, context); - MUTATE(newnode->subselect, sublink->subselect, Node *, - HandleRIRAttributeRule_mutator, context); - return (Node *) newnode; - } if (IsA(node, Query)) { - Query *query = (Query *) node; + /* Recurse into RTE subquery or not-yet-planned sublink subquery */ Query *newnode; - FLATCOPY(newnode, query, Query); context->sublevels_up++; - query_tree_mutator(newnode, HandleRIRAttributeRule_mutator, - context, 0); + newnode = query_tree_mutator((Query *) node, + HandleRIRAttributeRule_mutator, + (void *) context, + 0); context->sublevels_up--; return (Node *) newnode; } @@ -1010,8 +955,10 @@ HandleRIRAttributeRule(Query *parsetree, context.badsql = badsql; context.sublevels_up = 0; - query_tree_mutator(parsetree, HandleRIRAttributeRule_mutator, - (void *) &context, 0); + query_tree_mutator(parsetree, + HandleRIRAttributeRule_mutator, + (void *) &context, + QTW_DONT_COPY_QUERY); } #endif /* NOT_USED */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 4ed022b15e..024c1599a4 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: clauses.h,v 1.59 2003/01/15 19:35:47 tgl Exp $ + * $Id: clauses.h,v 1.60 2003/01/17 02:01:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,12 +75,18 @@ extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (), void *context); /* flags bits for query_tree_walker and query_tree_mutator */ -#define QTW_IGNORE_SUBQUERIES 0x01 /* subqueries in rtable */ -#define QTW_IGNORE_JOINALIASES 0x02 /* JOIN alias var lists */ +#define QTW_IGNORE_RT_SUBQUERIES 0x01 /* subqueries in rtable */ +#define QTW_IGNORE_JOINALIASES 0x02 /* JOIN alias var lists */ +#define QTW_DONT_COPY_QUERY 0x04 /* do not copy top Query */ extern bool query_tree_walker(Query *query, bool (*walker) (), void *context, int flags); -extern void query_tree_mutator(Query *query, Node *(*mutator) (), - void *context, int flags); +extern Query *query_tree_mutator(Query *query, Node *(*mutator) (), + void *context, int flags); + +extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (), + void *context, int flags); +extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (), + void *context, int flags); #endif /* CLAUSES_H */