diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 1232 |
1 files changed, 4 insertions, 1228 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 6a06b0806c2..c015be9e9bf 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.263 2008/08/22 00:16:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.264 2008/08/25 22:42:33 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -28,16 +28,14 @@ #include "executor/functions.h" #include "miscadmin.h" #include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/planmain.h" -#include "optimizer/planner.h" #include "optimizer/prep.h" #include "optimizer/var.h" #include "parser/analyze.h" -#include "parser/parse_clause.h" #include "parser/parse_coerce.h" -#include "parser/parse_expr.h" #include "rewrite/rewriteManip.h" #include "tcop/tcopprot.h" #include "utils/acl.h" @@ -73,7 +71,6 @@ typedef struct static bool contain_agg_clause_walker(Node *node, void *context); static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts); -static bool expression_returns_set_walker(Node *node, void *context); static bool expression_returns_set_rows_walker(Node *node, double *count); static bool contain_subplans_walker(Node *node, void *context); static bool contain_mutable_functions_walker(Node *node, void *context); @@ -518,81 +515,13 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) *****************************************************************************/ /* - * expression_returns_set - * Test whether an expression returns a set result. - * - * Because we use expression_tree_walker(), this can also be applied to - * whole targetlists; it'll produce TRUE if any one of the tlist items - * returns a set. - */ -bool -expression_returns_set(Node *clause) -{ - return expression_returns_set_walker(clause, NULL); -} - -static bool -expression_returns_set_walker(Node *node, void *context) -{ - if (node == NULL) - return false; - if (IsA(node, FuncExpr)) - { - FuncExpr *expr = (FuncExpr *) node; - - if (expr->funcretset) - return true; - /* else fall through to check args */ - } - if (IsA(node, OpExpr)) - { - OpExpr *expr = (OpExpr *) node; - - if (expr->opretset) - return true; - /* else fall through to check args */ - } - - /* Avoid recursion for some cases that can't return a set */ - if (IsA(node, Aggref)) - return false; - if (IsA(node, DistinctExpr)) - return false; - if (IsA(node, ScalarArrayOpExpr)) - return false; - if (IsA(node, BoolExpr)) - return false; - if (IsA(node, SubLink)) - return false; - if (IsA(node, SubPlan)) - return false; - if (IsA(node, AlternativeSubPlan)) - return false; - if (IsA(node, ArrayExpr)) - return false; - if (IsA(node, RowExpr)) - return false; - if (IsA(node, RowCompareExpr)) - return false; - if (IsA(node, CoalesceExpr)) - return false; - if (IsA(node, MinMaxExpr)) - return false; - if (IsA(node, XmlExpr)) - return false; - if (IsA(node, NullIfExpr)) - return false; - - return expression_tree_walker(node, expression_returns_set_walker, - context); -} - -/* * expression_returns_set_rows * Estimate the number of rows in a set result. * * We use the product of the rowcount estimates of all the functions in * the given tree. The result is 1 if there are no set-returning functions. + * + * Note: keep this in sync with expression_returns_set() in nodes/nodeFuncs.c. */ double expression_returns_set_rows(Node *clause) @@ -3936,1156 +3865,3 @@ substitute_actual_srf_parameters_mutator(Node *node, substitute_actual_srf_parameters_mutator, (void *) context); } - - -/* - * Standard expression-tree walking support - * - * We used to have near-duplicate code in many different routines that - * understood how to recurse through an expression node tree. That was - * a pain to maintain, and we frequently had bugs due to some particular - * routine neglecting to support a particular node type. In most cases, - * these routines only actually care about certain node types, and don't - * care about other types except insofar as they have to recurse through - * non-primitive node types. Therefore, we now provide generic tree-walking - * logic to consolidate the redundant "boilerplate" code. There are - * two versions: expression_tree_walker() and expression_tree_mutator(). - */ - -/*-------------------- - * expression_tree_walker() is designed to support routines that traverse - * a tree in a read-only fashion (although it will also work for routines - * that modify nodes in-place but never add/delete/replace nodes). - * A walker routine should look like this: - * - * bool my_walker (Node *node, my_struct *context) - * { - * if (node == NULL) - * return false; - * // check for nodes that special work is required for, eg: - * if (IsA(node, Var)) - * { - * ... do special actions for Var nodes - * } - * else if (IsA(node, ...)) - * { - * ... do special actions for other node types - * } - * // for any node type not specially processed, do: - * return expression_tree_walker(node, my_walker, (void *) context); - * } - * - * The "context" argument points to a struct that holds whatever context - * information the walker routine needs --- it can be used to return data - * gathered by the walker, too. This argument is not touched by - * expression_tree_walker, but it is passed down to recursive sub-invocations - * of my_walker. The tree walk is started from a setup routine that - * fills in the appropriate context struct, calls my_walker with the top-level - * node of the tree, and then examines the results. - * - * The walker routine should return "false" to continue the tree walk, or - * "true" to abort the walk and immediately return "true" to the top-level - * caller. This can be used to short-circuit the traversal if the walker - * has found what it came for. "false" is returned to the top-level caller - * iff no invocation of the walker returned "true". - * - * The node types handled by expression_tree_walker include all those - * normally found in target lists and qualifier clauses during the planning - * stage. In particular, it handles List nodes since a cnf-ified qual clause - * will have List structure at the top level, and it handles TargetEntry nodes - * so that a scan of a target list can be handled without additional code. - * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are - * handled, so that query jointrees and setOperation trees can be processed - * without additional code. - * - * expression_tree_walker will handle SubLink nodes by recursing normally - * into the "testexpr" subtree (which is an expression belonging to the outer - * plan). It will also call the walker on the sub-Query node; however, when - * expression_tree_walker itself is called on a Query node, it does nothing - * and returns "false". The net effect is that unless the walker does - * something special at a Query node, sub-selects will not be visited during - * an expression tree walk. This is exactly the behavior wanted in many cases - * --- and for those walkers that do want to recurse into sub-selects, special - * behavior is typically needed anyway at the entry to a sub-select (such as - * incrementing a depth counter). A walker that wants to examine sub-selects - * should include code along the lines of: - * - * if (IsA(node, Query)) - * { - * adjust context for subquery; - * result = query_tree_walker((Query *) node, my_walker, context, - * 0); // adjust flags as needed - * restore context if needed; - * return result; - * } - * - * query_tree_walker is a convenience routine (see below) that calls the - * walker on all the expression subtrees of the given Query node. - * - * expression_tree_walker will handle SubPlan nodes by recursing normally - * into the "testexpr" and the "args" list (which are expressions belonging to - * the outer plan). It will not touch the completed subplan, however. Since - * there is no link to the original Query, it is not possible to recurse into - * subselects of an already-planned expression tree. This is OK for current - * uses, but may need to be revisited in future. - *-------------------- - */ - -bool -expression_tree_walker(Node *node, - bool (*walker) (), - void *context) -{ - ListCell *temp; - - /* - * The walker has already visited the current node, and so we need only - * recurse into any sub-nodes it has. - * - * We assume that the walker is not interested in List nodes per se, so - * when we expect a List we just recurse directly to self without - * bothering to call the walker. - */ - if (node == NULL) - return false; - - /* Guard against stack overflow due to overly complex expressions */ - check_stack_depth(); - - switch (nodeTag(node)) - { - case T_Var: - case T_Const: - case T_Param: - case T_CoerceToDomainValue: - case T_CaseTestExpr: - case T_SetToDefault: - case T_CurrentOfExpr: - case T_RangeTblRef: - /* primitive node types with no expression subnodes */ - break; - case T_Aggref: - { - Aggref *expr = (Aggref *) node; - - /* recurse directly on List */ - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_ArrayRef: - { - ArrayRef *aref = (ArrayRef *) node; - - /* recurse directly for upper/lower array index lists */ - if (expression_tree_walker((Node *) aref->refupperindexpr, - walker, context)) - return true; - if (expression_tree_walker((Node *) aref->reflowerindexpr, - walker, context)) - return true; - /* walker must see the refexpr and refassgnexpr, however */ - if (walker(aref->refexpr, context)) - return true; - if (walker(aref->refassgnexpr, context)) - return true; - } - break; - case T_FuncExpr: - { - FuncExpr *expr = (FuncExpr *) node; - - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_OpExpr: - { - OpExpr *expr = (OpExpr *) node; - - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_DistinctExpr: - { - DistinctExpr *expr = (DistinctExpr *) node; - - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_ScalarArrayOpExpr: - { - ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; - - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_BoolExpr: - { - BoolExpr *expr = (BoolExpr *) node; - - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; - case T_SubLink: - { - SubLink *sublink = (SubLink *) node; - - if (walker(sublink->testexpr, context)) - return true; - - /* - * Also invoke the walker on the sublink's Query node, so it - * can recurse into the sub-query if it wants to. - */ - return walker(sublink->subselect, context); - } - break; - case T_SubPlan: - { - SubPlan *subplan = (SubPlan *) node; - - /* recurse into the testexpr, but not into the Plan */ - if (walker(subplan->testexpr, context)) - return true; - /* also examine args list */ - if (expression_tree_walker((Node *) subplan->args, - walker, context)) - return true; - } - break; - case T_AlternativeSubPlan: - return walker(((AlternativeSubPlan *) node)->subplans, context); - case T_FieldSelect: - return walker(((FieldSelect *) node)->arg, context); - case T_FieldStore: - { - FieldStore *fstore = (FieldStore *) node; - - if (walker(fstore->arg, context)) - return true; - if (walker(fstore->newvals, context)) - return true; - } - break; - case T_RelabelType: - return walker(((RelabelType *) node)->arg, context); - case T_CoerceViaIO: - return walker(((CoerceViaIO *) node)->arg, context); - case T_ArrayCoerceExpr: - return walker(((ArrayCoerceExpr *) node)->arg, context); - case T_ConvertRowtypeExpr: - return walker(((ConvertRowtypeExpr *) node)->arg, context); - case T_CaseExpr: - { - CaseExpr *caseexpr = (CaseExpr *) node; - - if (walker(caseexpr->arg, context)) - return true; - /* we assume walker doesn't care about CaseWhens, either */ - foreach(temp, caseexpr->args) - { - CaseWhen *when = (CaseWhen *) lfirst(temp); - - Assert(IsA(when, CaseWhen)); - if (walker(when->expr, context)) - return true; - if (walker(when->result, context)) - return true; - } - if (walker(caseexpr->defresult, context)) - return true; - } - break; - case T_ArrayExpr: - return walker(((ArrayExpr *) node)->elements, context); - case T_RowExpr: - return walker(((RowExpr *) node)->args, context); - case T_RowCompareExpr: - { - RowCompareExpr *rcexpr = (RowCompareExpr *) node; - - if (walker(rcexpr->largs, context)) - return true; - if (walker(rcexpr->rargs, context)) - return true; - } - break; - case T_CoalesceExpr: - return walker(((CoalesceExpr *) node)->args, context); - case T_MinMaxExpr: - return walker(((MinMaxExpr *) node)->args, context); - case T_XmlExpr: - { - XmlExpr *xexpr = (XmlExpr *) node; - - if (walker(xexpr->named_args, context)) - return true; - /* we assume walker doesn't care about arg_names */ - if (walker(xexpr->args, context)) - return true; - } - break; - case T_NullIfExpr: - return walker(((NullIfExpr *) node)->args, context); - case T_NullTest: - return walker(((NullTest *) node)->arg, context); - case T_BooleanTest: - return walker(((BooleanTest *) node)->arg, context); - case T_CoerceToDomain: - return walker(((CoerceToDomain *) node)->arg, context); - case T_TargetEntry: - return walker(((TargetEntry *) node)->expr, context); - case T_Query: - /* Do nothing with a sub-Query, per discussion above */ - break; - case T_List: - foreach(temp, (List *) node) - { - if (walker((Node *) lfirst(temp), context)) - return true; - } - break; - case T_FromExpr: - { - FromExpr *from = (FromExpr *) node; - - if (walker(from->fromlist, context)) - return true; - if (walker(from->quals, context)) - return true; - } - break; - case T_JoinExpr: - { - JoinExpr *join = (JoinExpr *) node; - - if (walker(join->larg, context)) - return true; - if (walker(join->rarg, context)) - return true; - if (walker(join->quals, context)) - return true; - - /* - * alias clause, using list are deemed uninteresting. - */ - } - break; - case T_SetOperationStmt: - { - SetOperationStmt *setop = (SetOperationStmt *) node; - - if (walker(setop->larg, context)) - return true; - if (walker(setop->rarg, context)) - return true; - - /* groupClauses are deemed uninteresting */ - } - break; - case T_FlattenedSubLink: - { - FlattenedSubLink *fslink = (FlattenedSubLink *) node; - - if (expression_tree_walker((Node *) fslink->quals, - walker, context)) - return true; - } - break; - case T_AppendRelInfo: - { - AppendRelInfo *appinfo = (AppendRelInfo *) node; - - if (expression_tree_walker((Node *) appinfo->translated_vars, - walker, context)) - return true; - } - break; - default: - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(node)); - break; - } - return false; -} - -/* - * query_tree_walker --- initiate a walk of a Query's expressions - * - * This routine exists just to reduce the number of places that need to know - * where all the expression subtrees of a Query are. Note it can be used - * for starting a walk at top level of a Query regardless of whether the - * walker intends to descend into subqueries. It is also useful for - * descending into subqueries within a walker. - * - * Some callers want to suppress visitation of certain items in the sub-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 visitation of - * indicated items. (More flag bits may be added as needed.) - */ -bool -query_tree_walker(Query *query, - bool (*walker) (), - void *context, - int flags) -{ - Assert(query != NULL && IsA(query, Query)); - - if (walker((Node *) query->targetList, context)) - return true; - if (walker((Node *) query->returningList, context)) - return true; - if (walker((Node *) query->jointree, context)) - return true; - if (walker(query->setOperations, context)) - return true; - if (walker(query->havingQual, context)) - return true; - if (walker(query->limitOffset, context)) - return true; - if (walker(query->limitCount, context)) - return true; - if (range_table_walker(query->rtable, walker, context, flags)) - return true; - return false; -} - -/* - * range_table_walker is just the part of query_tree_walker that scans - * a query's rangetable. This is split out since it can be useful on - * its own. - */ -bool -range_table_walker(List *rtable, - bool (*walker) (), - void *context, - int flags) -{ - ListCell *rt; - - foreach(rt, rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); - - switch (rte->rtekind) - { - case RTE_RELATION: - case RTE_SPECIAL: - /* nothing to do */ - break; - case RTE_SUBQUERY: - if (!(flags & QTW_IGNORE_RT_SUBQUERIES)) - if (walker(rte->subquery, context)) - return true; - break; - case RTE_JOIN: - if (!(flags & QTW_IGNORE_JOINALIASES)) - if (walker(rte->joinaliasvars, context)) - return true; - break; - case RTE_FUNCTION: - if (walker(rte->funcexpr, context)) - return true; - break; - case RTE_VALUES: - if (walker(rte->values_lists, context)) - return true; - break; - } - } - return false; -} - - -/*-------------------- - * expression_tree_mutator() is designed to support routines that make a - * modified copy of an expression tree, with some nodes being added, - * removed, or replaced by new subtrees. The original tree is (normally) - * not changed. Each recursion level is responsible for returning a copy of - * (or appropriately modified substitute for) the subtree it is handed. - * A mutator routine should look like this: - * - * Node * my_mutator (Node *node, my_struct *context) - * { - * if (node == NULL) - * return NULL; - * // check for nodes that special work is required for, eg: - * if (IsA(node, Var)) - * { - * ... create and return modified copy of Var node - * } - * else if (IsA(node, ...)) - * { - * ... do special transformations of other node types - * } - * // for any node type not specially processed, do: - * return expression_tree_mutator(node, my_mutator, (void *) context); - * } - * - * The "context" argument points to a struct that holds whatever context - * information the mutator routine needs --- it can be used to return extra - * data gathered by the mutator, too. This argument is not touched by - * expression_tree_mutator, but it is passed down to recursive sub-invocations - * of my_mutator. The tree walk is started from a setup routine that - * fills in the appropriate context struct, calls my_mutator with the - * top-level node of the tree, and does any required post-processing. - * - * Each level of recursion must return an appropriately modified Node. - * If expression_tree_mutator() is called, it will make an exact copy - * of the given Node, but invoke my_mutator() to copy the sub-node(s) - * of that Node. In this way, my_mutator() has full control over the - * copying process but need not directly deal with expression trees - * that it has no interest in. - * - * Just as for expression_tree_walker, the node types handled by - * 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 "testexpr" subtree (which is an expression 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 - * "testexpr" and the "args" list (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. - *-------------------- - */ - -Node * -expression_tree_mutator(Node *node, - Node *(*mutator) (), - void *context) -{ - /* - * The mutator has already decided not to modify the current node, but we - * must call the mutator for any sub-nodes. - */ - -#define FLATCOPY(newnode, node, nodetype) \ - ( (newnode) = (nodetype *) palloc(sizeof(nodetype)), \ - memcpy((newnode), (node), sizeof(nodetype)) ) - -#define CHECKFLATCOPY(newnode, node, nodetype) \ - ( AssertMacro(IsA((node), nodetype)), \ - (newnode) = (nodetype *) palloc(sizeof(nodetype)), \ - memcpy((newnode), (node), sizeof(nodetype)) ) - -#define MUTATE(newfield, oldfield, fieldtype) \ - ( (newfield) = (fieldtype) mutator((Node *) (oldfield), context) ) - - if (node == NULL) - return NULL; - - /* Guard against stack overflow due to overly complex expressions */ - check_stack_depth(); - - switch (nodeTag(node)) - { - /* - * Primitive node types with no expression subnodes. Var and - * Const are frequent enough to deserve special cases, the others - * we just use copyObject for. - */ - case T_Var: - { - Var *var = (Var *) node; - Var *newnode; - - FLATCOPY(newnode, var, Var); - return (Node *) newnode; - } - break; - case T_Const: - { - Const *oldnode = (Const *) node; - Const *newnode; - - FLATCOPY(newnode, oldnode, Const); - /* XXX we don't bother with datumCopy; should we? */ - return (Node *) newnode; - } - break; - case T_Param: - case T_CoerceToDomainValue: - case T_CaseTestExpr: - case T_SetToDefault: - case T_CurrentOfExpr: - case T_RangeTblRef: - return (Node *) copyObject(node); - case T_Aggref: - { - Aggref *aggref = (Aggref *) node; - Aggref *newnode; - - FLATCOPY(newnode, aggref, Aggref); - MUTATE(newnode->args, aggref->args, List *); - return (Node *) newnode; - } - break; - case T_ArrayRef: - { - ArrayRef *arrayref = (ArrayRef *) node; - ArrayRef *newnode; - - FLATCOPY(newnode, arrayref, ArrayRef); - MUTATE(newnode->refupperindexpr, arrayref->refupperindexpr, - List *); - MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr, - List *); - MUTATE(newnode->refexpr, arrayref->refexpr, - Expr *); - MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr, - Expr *); - return (Node *) newnode; - } - break; - case T_FuncExpr: - { - FuncExpr *expr = (FuncExpr *) node; - FuncExpr *newnode; - - FLATCOPY(newnode, expr, FuncExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_OpExpr: - { - OpExpr *expr = (OpExpr *) node; - OpExpr *newnode; - - FLATCOPY(newnode, expr, OpExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_DistinctExpr: - { - DistinctExpr *expr = (DistinctExpr *) node; - DistinctExpr *newnode; - - FLATCOPY(newnode, expr, DistinctExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_ScalarArrayOpExpr: - { - ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; - ScalarArrayOpExpr *newnode; - - FLATCOPY(newnode, expr, ScalarArrayOpExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_BoolExpr: - { - BoolExpr *expr = (BoolExpr *) node; - BoolExpr *newnode; - - FLATCOPY(newnode, expr, BoolExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_SubLink: - { - SubLink *sublink = (SubLink *) node; - SubLink *newnode; - - FLATCOPY(newnode, sublink, SubLink); - MUTATE(newnode->testexpr, sublink->testexpr, Node *); - - /* - * 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; - case T_SubPlan: - { - SubPlan *subplan = (SubPlan *) node; - SubPlan *newnode; - - FLATCOPY(newnode, subplan, SubPlan); - /* transform testexpr */ - MUTATE(newnode->testexpr, subplan->testexpr, Node *); - /* transform args list (params to be passed to subplan) */ - MUTATE(newnode->args, subplan->args, List *); - /* but not the sub-Plan itself, which is referenced as-is */ - return (Node *) newnode; - } - break; - case T_AlternativeSubPlan: - { - AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; - AlternativeSubPlan *newnode; - - FLATCOPY(newnode, asplan, AlternativeSubPlan); - MUTATE(newnode->subplans, asplan->subplans, List *); - return (Node *) newnode; - } - break; - case T_FieldSelect: - { - FieldSelect *fselect = (FieldSelect *) node; - FieldSelect *newnode; - - FLATCOPY(newnode, fselect, FieldSelect); - MUTATE(newnode->arg, fselect->arg, Expr *); - return (Node *) newnode; - } - break; - case T_FieldStore: - { - FieldStore *fstore = (FieldStore *) node; - FieldStore *newnode; - - FLATCOPY(newnode, fstore, FieldStore); - MUTATE(newnode->arg, fstore->arg, Expr *); - MUTATE(newnode->newvals, fstore->newvals, List *); - newnode->fieldnums = list_copy(fstore->fieldnums); - return (Node *) newnode; - } - break; - case T_RelabelType: - { - RelabelType *relabel = (RelabelType *) node; - RelabelType *newnode; - - FLATCOPY(newnode, relabel, RelabelType); - MUTATE(newnode->arg, relabel->arg, Expr *); - return (Node *) newnode; - } - break; - case T_CoerceViaIO: - { - CoerceViaIO *iocoerce = (CoerceViaIO *) node; - CoerceViaIO *newnode; - - FLATCOPY(newnode, iocoerce, CoerceViaIO); - MUTATE(newnode->arg, iocoerce->arg, Expr *); - return (Node *) newnode; - } - break; - case T_ArrayCoerceExpr: - { - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; - ArrayCoerceExpr *newnode; - - FLATCOPY(newnode, acoerce, ArrayCoerceExpr); - MUTATE(newnode->arg, acoerce->arg, Expr *); - return (Node *) newnode; - } - break; - case T_ConvertRowtypeExpr: - { - ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node; - ConvertRowtypeExpr *newnode; - - FLATCOPY(newnode, convexpr, ConvertRowtypeExpr); - MUTATE(newnode->arg, convexpr->arg, Expr *); - return (Node *) newnode; - } - break; - case T_CaseExpr: - { - CaseExpr *caseexpr = (CaseExpr *) node; - CaseExpr *newnode; - - FLATCOPY(newnode, caseexpr, CaseExpr); - MUTATE(newnode->arg, caseexpr->arg, Expr *); - MUTATE(newnode->args, caseexpr->args, List *); - MUTATE(newnode->defresult, caseexpr->defresult, Expr *); - return (Node *) newnode; - } - break; - case T_CaseWhen: - { - CaseWhen *casewhen = (CaseWhen *) node; - CaseWhen *newnode; - - FLATCOPY(newnode, casewhen, CaseWhen); - MUTATE(newnode->expr, casewhen->expr, Expr *); - MUTATE(newnode->result, casewhen->result, Expr *); - return (Node *) newnode; - } - break; - case T_ArrayExpr: - { - ArrayExpr *arrayexpr = (ArrayExpr *) node; - ArrayExpr *newnode; - - FLATCOPY(newnode, arrayexpr, ArrayExpr); - MUTATE(newnode->elements, arrayexpr->elements, List *); - return (Node *) newnode; - } - break; - case T_RowExpr: - { - RowExpr *rowexpr = (RowExpr *) node; - RowExpr *newnode; - - FLATCOPY(newnode, rowexpr, RowExpr); - MUTATE(newnode->args, rowexpr->args, List *); - return (Node *) newnode; - } - break; - case T_RowCompareExpr: - { - RowCompareExpr *rcexpr = (RowCompareExpr *) node; - RowCompareExpr *newnode; - - FLATCOPY(newnode, rcexpr, RowCompareExpr); - MUTATE(newnode->largs, rcexpr->largs, List *); - MUTATE(newnode->rargs, rcexpr->rargs, List *); - return (Node *) newnode; - } - break; - case T_CoalesceExpr: - { - CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; - CoalesceExpr *newnode; - - FLATCOPY(newnode, coalesceexpr, CoalesceExpr); - MUTATE(newnode->args, coalesceexpr->args, List *); - return (Node *) newnode; - } - break; - case T_MinMaxExpr: - { - MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; - MinMaxExpr *newnode; - - FLATCOPY(newnode, minmaxexpr, MinMaxExpr); - MUTATE(newnode->args, minmaxexpr->args, List *); - return (Node *) newnode; - } - break; - case T_XmlExpr: - { - XmlExpr *xexpr = (XmlExpr *) node; - XmlExpr *newnode; - - FLATCOPY(newnode, xexpr, XmlExpr); - MUTATE(newnode->named_args, xexpr->named_args, List *); - /* assume mutator does not care about arg_names */ - MUTATE(newnode->args, xexpr->args, List *); - return (Node *) newnode; - } - break; - case T_NullIfExpr: - { - NullIfExpr *expr = (NullIfExpr *) node; - NullIfExpr *newnode; - - FLATCOPY(newnode, expr, NullIfExpr); - MUTATE(newnode->args, expr->args, List *); - return (Node *) newnode; - } - break; - case T_NullTest: - { - NullTest *ntest = (NullTest *) node; - NullTest *newnode; - - FLATCOPY(newnode, ntest, NullTest); - MUTATE(newnode->arg, ntest->arg, Expr *); - return (Node *) newnode; - } - break; - case T_BooleanTest: - { - BooleanTest *btest = (BooleanTest *) node; - BooleanTest *newnode; - - FLATCOPY(newnode, btest, BooleanTest); - MUTATE(newnode->arg, btest->arg, Expr *); - return (Node *) newnode; - } - break; - case T_CoerceToDomain: - { - CoerceToDomain *ctest = (CoerceToDomain *) node; - CoerceToDomain *newnode; - - FLATCOPY(newnode, ctest, CoerceToDomain); - MUTATE(newnode->arg, ctest->arg, Expr *); - return (Node *) newnode; - } - break; - case T_TargetEntry: - { - TargetEntry *targetentry = (TargetEntry *) node; - TargetEntry *newnode; - - FLATCOPY(newnode, targetentry, TargetEntry); - MUTATE(newnode->expr, targetentry->expr, Expr *); - return (Node *) newnode; - } - break; - case T_Query: - /* Do nothing with a sub-Query, per discussion above */ - return node; - case T_List: - { - /* - * We assume the mutator isn't interested in the list nodes - * per se, so just invoke it on each list element. NOTE: this - * would fail badly on a list with integer elements! - */ - List *resultlist; - ListCell *temp; - - resultlist = NIL; - foreach(temp, (List *) node) - { - resultlist = lappend(resultlist, - mutator((Node *) lfirst(temp), - context)); - } - return (Node *) resultlist; - } - break; - case T_FromExpr: - { - FromExpr *from = (FromExpr *) node; - FromExpr *newnode; - - FLATCOPY(newnode, from, FromExpr); - MUTATE(newnode->fromlist, from->fromlist, List *); - MUTATE(newnode->quals, from->quals, Node *); - return (Node *) newnode; - } - break; - case T_JoinExpr: - { - JoinExpr *join = (JoinExpr *) node; - JoinExpr *newnode; - - FLATCOPY(newnode, join, JoinExpr); - MUTATE(newnode->larg, join->larg, Node *); - MUTATE(newnode->rarg, join->rarg, Node *); - MUTATE(newnode->quals, join->quals, Node *); - /* We do not mutate alias or using by default */ - return (Node *) newnode; - } - break; - case T_SetOperationStmt: - { - SetOperationStmt *setop = (SetOperationStmt *) node; - SetOperationStmt *newnode; - - FLATCOPY(newnode, setop, SetOperationStmt); - MUTATE(newnode->larg, setop->larg, Node *); - MUTATE(newnode->rarg, setop->rarg, Node *); - /* We do not mutate groupClauses by default */ - return (Node *) newnode; - } - break; - case T_FlattenedSubLink: - { - FlattenedSubLink *fslink = (FlattenedSubLink *) node; - FlattenedSubLink *newnode; - - FLATCOPY(newnode, fslink, FlattenedSubLink); - /* Assume we need not copy the relids bitmapsets */ - MUTATE(newnode->quals, fslink->quals, Expr *); - return (Node *) newnode; - } - break; - case T_AppendRelInfo: - { - AppendRelInfo *appinfo = (AppendRelInfo *) node; - AppendRelInfo *newnode; - - FLATCOPY(newnode, appinfo, AppendRelInfo); - MUTATE(newnode->translated_vars, appinfo->translated_vars, List *); - return (Node *) newnode; - } - break; - default: - elog(ERROR, "unrecognized node type: %d", - (int) nodeTag(node)); - break; - } - /* can't get here, but keep compiler happy */ - return NULL; -} - - -/* - * query_tree_mutator --- initiate modification of a Query's expressions - * - * This routine exists just to reduce the number of places that need to know - * where all the expression subtrees of a Query are. Note it can be used - * for starting a walk at top level of a Query regardless of whether the - * mutator intends to descend into subqueries. It is also useful for - * descending into subqueries within a mutator. - * - * 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. - */ -Query * -query_tree_mutator(Query *query, - Node *(*mutator) (), - void *context, - int flags) -{ - 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->returningList, query->returningList, List *); - MUTATE(query->jointree, query->jointree, FromExpr *); - MUTATE(query->setOperations, query->setOperations, Node *); - MUTATE(query->havingQual, query->havingQual, Node *); - MUTATE(query->limitOffset, query->limitOffset, Node *); - MUTATE(query->limitCount, query->limitCount, Node *); - query->rtable = range_table_mutator(query->rtable, - mutator, context, flags); - return query; -} - -/* - * range_table_mutator is just the part of query_tree_mutator that processes - * a query's rangetable. This is split out since it can be useful on - * its own. - */ -List * -range_table_mutator(List *rtable, - Node *(*mutator) (), - void *context, - int flags) -{ - List *newrt = NIL; - ListCell *rt; - - foreach(rt, rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); - RangeTblEntry *newrte; - - FLATCOPY(newrte, rte, RangeTblEntry); - switch (rte->rtekind) - { - case RTE_RELATION: - case RTE_SPECIAL: - /* we don't bother to copy eref, aliases, etc; OK? */ - break; - case RTE_SUBQUERY: - if (!(flags & QTW_IGNORE_RT_SUBQUERIES)) - { - CHECKFLATCOPY(newrte->subquery, rte->subquery, Query); - MUTATE(newrte->subquery, newrte->subquery, Query *); - } - else - { - /* else, copy RT subqueries as-is */ - newrte->subquery = copyObject(rte->subquery); - } - break; - case RTE_JOIN: - if (!(flags & QTW_IGNORE_JOINALIASES)) - MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *); - else - { - /* else, copy join aliases as-is */ - newrte->joinaliasvars = copyObject(rte->joinaliasvars); - } - break; - case RTE_FUNCTION: - MUTATE(newrte->funcexpr, rte->funcexpr, Node *); - break; - case RTE_VALUES: - MUTATE(newrte->values_lists, rte->values_lists, List *); - break; - } - newrt = lappend(newrt, newrte); - } - return newrt; -} - -/* - * 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); -} |