aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c111
1 files changed, 103 insertions, 8 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 06c67daebfc..f52ec6d2d87 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.76 2000/09/29 18:21:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.77 2000/10/05 19:11:32 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1636,8 +1636,8 @@ simplify_op_or_func(Expr *expr, List *args)
* so that a scan of a target list can be handled without additional code.
* (But only the "expr" part of a TargetEntry is examined, unless the walker
* chooses to process TargetEntry nodes specially.) Also, RangeTblRef,
- * FromExpr, and JoinExpr nodes are handled, so that qual expressions in a
- * jointree can be processed without additional code.
+ * 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 and SubPlan nodes by recursing
* normally into the "lefthand" arguments (which belong to the outer plan).
@@ -1654,7 +1654,8 @@ simplify_op_or_func(Expr *expr, List *args)
* if (IsA(node, Query))
* {
* adjust context for subquery;
- * result = query_tree_walker((Query *) node, my_walker, context);
+ * result = query_tree_walker((Query *) node, my_walker, context,
+ * true); // to visit subquery RTEs too
* restore context if needed;
* return result;
* }
@@ -1827,6 +1828,16 @@ expression_tree_walker(Node *node,
*/
}
break;
+ case T_SetOperationStmt:
+ {
+ SetOperationStmt *setop = (SetOperationStmt *) node;
+
+ if (walker(setop->larg, context))
+ return true;
+ if (walker(setop->rarg, context))
+ return true;
+ }
+ break;
default:
elog(ERROR, "expression_tree_walker: Unexpected node type %d",
nodeTag(node));
@@ -1843,11 +1854,17 @@ expression_tree_walker(Node *node,
* 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.
+ *
+ * If visitQueryRTEs is true, the walker will also be called on sub-Query
+ * nodes present in subquery rangetable entries of the given Query. This
+ * is optional since some callers handle those sub-queries separately,
+ * or don't really want to see subqueries anyway.
*/
bool
query_tree_walker(Query *query,
bool (*walker) (),
- void *context)
+ void *context,
+ bool visitQueryRTEs)
{
Assert(query != NULL && IsA(query, Query));
@@ -1855,11 +1872,23 @@ query_tree_walker(Query *query,
return true;
if (walker((Node *) query->jointree, context))
return true;
+ if (walker(query->setOperations, context))
+ return true;
if (walker(query->havingQual, context))
return true;
- /*
- * XXX for subselect-in-FROM, may need to examine rtable as well?
- */
+ if (visitQueryRTEs)
+ {
+ List *rt;
+
+ foreach(rt, query->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+
+ if (rte->subquery)
+ if (walker(rte->subquery, context))
+ return true;
+ }
+ }
return false;
}
@@ -2158,6 +2187,17 @@ expression_tree_mutator(Node *node,
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 *);
+ return (Node *) newnode;
+ }
+ break;
default:
elog(ERROR, "expression_tree_mutator: Unexpected node type %d",
nodeTag(node));
@@ -2166,3 +2206,58 @@ expression_tree_mutator(Node *node,
/* 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.
+ *
+ * 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.
+ *
+ * If visitQueryRTEs is true, the mutator will also be called on sub-Query
+ * nodes present in subquery rangetable entries of the given Query. This
+ * is optional since some callers handle those sub-queries separately,
+ * or don't really want to see subqueries anyway.
+ */
+void
+query_tree_mutator(Query *query,
+ Node *(*mutator) (),
+ void *context,
+ bool visitQueryRTEs)
+{
+ Assert(query != NULL && IsA(query, Query));
+
+ MUTATE(query->targetList, query->targetList, List *);
+ MUTATE(query->jointree, query->jointree, FromExpr *);
+ MUTATE(query->setOperations, query->setOperations, Node *);
+ MUTATE(query->havingQual, query->havingQual, Node *);
+ if (visitQueryRTEs)
+ {
+ List *newrt = NIL;
+ List *rt;
+
+ foreach(rt, query->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+
+ if (rte->subquery)
+ {
+ RangeTblEntry *newrte;
+
+ FLATCOPY(newrte, rte, RangeTblEntry);
+ CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
+ MUTATE(newrte->subquery, newrte->subquery, Query *);
+ rte = newrte;
+ }
+ newrt = lappend(newrt, rte);
+ }
+ query->rtable = newrt;
+ }
+}