* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.9 2002/09/04 20:31:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.10 2002/09/11 14:48:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Recursively search an expression tree for object references.
+ *
+ * Note: we avoid creating references to columns of tables that participate
+ * in an SQL JOIN construct, but are not actually used anywhere in the query.
+ * To do so, we do not scan the joinaliasvars list of a join RTE while
+ * scanning the query rangetable, but instead scan each individual entry
+ * of the alias list when we find a reference to it.
*/
static bool
find_expr_references_walker(Node *node,
elog(ERROR, "find_expr_references_walker: bogus varno %d",
var->varno);
rte = rt_fetch(var->varno, rtable);
- /* If it's a plain relation, reference this column */
if (rte->rtekind == RTE_RELATION)
+ {
+ /* If it's a plain relation, reference this column */
+ /* NB: this code works for whole-row Var with attno 0, too */
add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
&context->addrs);
+ }
+ else if (rte->rtekind == RTE_JOIN)
+ {
+ /* Scan join output column to add references to join inputs */
+ if (var->varattno <= 0 ||
+ var->varattno > length(rte->joinaliasvars))
+ elog(ERROR, "find_expr_references_walker: bogus varattno %d",
+ var->varattno);
+ find_expr_references_walker((Node *) nth(var->varattno - 1,
+ rte->joinaliasvars),
+ context);
+ }
return false;
}
if (IsA(node, Expr))
* Add whole-relation refs for each plain relation mentioned in
* the subquery's rtable. (Note: query_tree_walker takes care of
* recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need
- * to do that here.)
+ * to do that here. But keep it from looking at join alias lists.)
*/
foreach(rtable, query->rtable)
{
context->rtables = lcons(query->rtable, context->rtables);
result = query_tree_walker(query,
find_expr_references_walker,
- (void *) context, true);
+ (void *) context,
+ QTW_IGNORE_JOINALIASES);
context->rtables = lnext(context->rtables);
return result;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.78 2002/09/04 20:31:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.79 2002/09/11 14:48:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (newnode->resultRelation == old_rt_index)
newnode->resultRelation = new_rt_index;
query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
- (void *) &context, false);
+ (void *) &context, QTW_IGNORE_SUBQUERIES);
return (Node *) newnode;
}
else
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.108 2002/09/04 20:31:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.109 2002/09/11 14:48:54 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
* {
* adjust context for subquery;
* result = query_tree_walker((Query *) node, my_walker, context,
- * true); // to visit subquery RTEs too
+ * 0); // to visit rtable items too
* restore context if needed;
* return result;
* }
* 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.
+ * 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,
- bool visitQueryRTEs)
+ int flags)
{
List *rt;
/* nothing to do */
break;
case RTE_SUBQUERY:
- if (visitQueryRTEs)
+ if (! (flags & QTW_IGNORE_SUBQUERIES))
if (walker(rte->subquery, context))
return true;
break;
case RTE_JOIN:
- if (walker(rte->joinaliasvars, context))
- return true;
+ if (! (flags & QTW_IGNORE_JOINALIASES))
+ if (walker(rte->joinaliasvars, context))
+ return true;
break;
case RTE_FUNCTION:
if (walker(rte->funcexpr, context))
* 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.
+ * Some callers want to suppress mutating 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 mutating of
+ * indicated items. (More flag bits may be added as needed.)
*/
void
query_tree_mutator(Query *query,
Node *(*mutator) (),
void *context,
- bool visitQueryRTEs)
+ int flags)
{
List *newrt = NIL;
List *rt;
/* nothing to do, don't bother to make a copy */
break;
case RTE_SUBQUERY:
- if (visitQueryRTEs)
+ if (! (flags & QTW_IGNORE_SUBQUERIES))
{
FLATCOPY(newrte, rte, RangeTblEntry);
CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
}
break;
case RTE_JOIN:
- FLATCOPY(newrte, rte, RangeTblEntry);
- MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
- rte = newrte;
+ if (! (flags & QTW_IGNORE_JOINALIASES))
+ {
+ FLATCOPY(newrte, rte, RangeTblEntry);
+ MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
+ rte = newrte;
+ }
break;
case RTE_FUNCTION:
FLATCOPY(newrte, rte, RangeTblEntry);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.39 2002/09/04 20:31:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.40 2002/09/11 14:48:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (node && IsA(node, Query))
query_tree_walker((Query *) node, pull_varnos_walker,
- (void *) &context, true);
+ (void *) &context, 0);
else
pull_varnos_walker(node, &context);
context->sublevels_up++;
result = query_tree_walker((Query *) node, pull_varnos_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
if (node && IsA(node, Query))
return query_tree_walker((Query *) node,
contain_var_reference_walker,
- (void *) &context, true);
+ (void *) &context, 0);
else
return contain_var_reference_walker(node, &context);
}
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_var_reference_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.79 2002/09/04 20:31:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.80 2002/09/11 14:48:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
/* If there are sublinks, search for them and process their RTEs */
+ /* ignore subqueries in rtable because we already processed them */
if (qry->hasSubLinks)
query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) &userid,
- false /* already did the ones in rtable */ );
+ QTW_IGNORE_SUBQUERIES);
}
/*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.108 2002/09/04 20:31:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.109 2002/09/11 14:48:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
/*
- * Recurse into sublink subqueries, too.
+ * Recurse into sublink subqueries, too. But we already did the ones
+ * in the rtable.
*/
if (parsetree->hasSubLinks)
query_tree_walker(parsetree, fireRIRonSubLink, NULL,
- false /* already handled the ones in rtable */ );
+ QTW_IGNORE_SUBQUERIES);
/*
* If the query was marked having aggregates, check if this is still
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.65 2002/09/04 20:31:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.66 2002/09/11 14:48:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, checkExprHasAggs_walker,
- NULL, false);
+ NULL, QTW_IGNORE_SUBQUERIES);
else
return checkExprHasAggs_walker(node, NULL);
}
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, checkExprHasSubLink_walker,
- NULL, false);
+ NULL, QTW_IGNORE_SUBQUERIES);
else
return checkExprHasSubLink_walker(node, NULL);
}
context->sublevels_up++;
result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
lfirsti(l) += offset;
}
query_tree_walker(qry, OffsetVarNodes_walker,
- (void *) &context, true);
+ (void *) &context, 0);
}
else
OffsetVarNodes_walker(node, &context);
context->sublevels_up++;
result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
}
}
query_tree_walker(qry, ChangeVarNodes_walker,
- (void *) &context, true);
+ (void *) &context, 0);
}
else
ChangeVarNodes_walker(node, &context);
context->min_sublevels_up++;
result = query_tree_walker((Query *) node,
IncrementVarSublevelsUp_walker,
- (void *) context, true);
+ (void *) context, 0);
context->min_sublevels_up--;
return result;
}
*/
if (node && IsA(node, Query))
query_tree_walker((Query *) node, IncrementVarSublevelsUp_walker,
- (void *) &context, true);
+ (void *) &context, 0);
else
IncrementVarSublevelsUp_walker(node, &context);
}
context->sublevels_up++;
result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, rangeTableEntry_used_walker,
- (void *) &context, true);
+ (void *) &context, 0);
else
return rangeTableEntry_used_walker(node, &context);
}
context->sublevels_up++;
result = query_tree_walker((Query *) node, attribute_used_walker,
- (void *) context, true);
+ (void *) context, 0);
context->sublevels_up--;
return result;
}
*/
if (node && IsA(node, Query))
return query_tree_walker((Query *) node, attribute_used_walker,
- (void *) &context, true);
+ (void *) &context, 0);
else
return attribute_used_walker(node, &context);
}
FLATCOPY(newnode, query, Query);
context->sublevels_up++;
- query_tree_mutator(newnode, ResolveNew_mutator, context, true);
+ query_tree_mutator(newnode, ResolveNew_mutator, context, 0);
context->sublevels_up--;
return (Node *) newnode;
}
FLATCOPY(newnode, query, Query);
query_tree_mutator(newnode, ResolveNew_mutator,
- (void *) &context, true);
+ (void *) &context, 0);
return (Node *) newnode;
}
else
FLATCOPY(newnode, query, Query);
context->sublevels_up++;
query_tree_mutator(newnode, HandleRIRAttributeRule_mutator,
- context, true);
+ context, 0);
context->sublevels_up--;
return (Node *) newnode;
}
context.sublevels_up = 0;
query_tree_mutator(parsetree, HandleRIRAttributeRule_mutator,
- (void *) &context, true);
+ (void *) &context, 0);
}
#endif /* NOT_USED */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: clauses.h,v 1.53 2002/06/20 20:29:51 momjian Exp $
+ * $Id: clauses.h,v 1.54 2002/09/11 14:48:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
void *context);
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 */
+
extern bool query_tree_walker(Query *query, bool (*walker) (),
- void *context, bool visitQueryRTEs);
+ void *context, int flags);
extern void query_tree_mutator(Query *query, Node *(*mutator) (),
- void *context, bool visitQueryRTEs);
+ void *context, int flags);
#define is_subplan(clause) ((clause) != NULL && \
IsA(clause, Expr) && \