Commit 86f36719 authored by Tom Lane's avatar Tom Lane

Create a generic expression-tree-walker subroutine, which

will gradually replace all of the boilerplate tree-walk-recursion code that
currently exists in O(N) slightly different forms in N subroutines.
I've had it with adding missing cases to these subroutines...
parent d30c4b05
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.19 1999/05/25 16:10:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.20 1999/06/19 03:41:45 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
#include "postgres.h" #include "postgres.h"
#include <nodes/relation.h> #include "nodes/relation.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
#include "nodes/plannodes.h" #include "nodes/plannodes.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
...@@ -27,43 +26,40 @@ ...@@ -27,43 +26,40 @@
#include "parser/parsetree.h" #include "parser/parsetree.h"
static bool pull_varnos_walker(Node *node, List **listptr);
static bool contain_var_clause_walker(Node *node, void *context);
static bool pull_var_clause_walker(Node *node, List **listptr);
/* /*
* find_varnos * pull_varnos
* *
* Descends down part of a parsetree (qual or tlist), * Create a list of all the distinct varnos present in a parsetree
* * (tlist or qual).
* XXX assumes varno's are always integers, which shouldn't be true...
* (though it currently is, see primnodes.h)
*/ */
List * List *
pull_varnos(Node *me) pull_varnos(Node *node)
{ {
List *i, List *result = NIL;
*result = NIL;
if (me == NULL) pull_varnos_walker(node, &result);
return NIL; return result;
}
switch (nodeTag(me)) static bool
pull_varnos_walker(Node *node, List **listptr)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{ {
case T_List: Var *var = (Var *) node;
foreach(i, (List *) me) if (!intMember(var->varno, *listptr))
result = nconc(result, pull_varnos(lfirst(i))); *listptr = lconsi(var->varno, *listptr);
break; return false;
case T_ArrayRef:
foreach(i, ((ArrayRef *) me)->refupperindexpr)
result = nconc(result, pull_varnos(lfirst(i)));
foreach(i, ((ArrayRef *) me)->reflowerindexpr)
result = nconc(result, pull_varnos(lfirst(i)));
result = nconc(result, pull_varnos(((ArrayRef *) me)->refassgnexpr));
break;
case T_Var:
result = lconsi(((Var *) me)->varno, NIL);
break;
default:
break;
} }
return result; return expression_tree_walker(node, pull_varnos_walker, (void *) listptr);
} }
/* /*
...@@ -75,92 +71,22 @@ pull_varnos(Node *me) ...@@ -75,92 +71,22 @@ pull_varnos(Node *me)
bool bool
contain_var_clause(Node *clause) contain_var_clause(Node *clause)
{ {
List *temp; return contain_var_clause_walker(clause, NULL);
}
if (clause == NULL)
return FALSE;
else if (IsA(clause, Var))
return TRUE;
else if (single_node(clause))
return FALSE;
else if (IsA(clause, Iter))
return contain_var_clause(((Iter *) clause)->iterexpr);
else if (is_subplan(clause))
{
foreach(temp, ((Expr *) clause)->args)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
/* Also check left sides of Oper-s */
foreach(temp, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
{
if (contain_var_clause(lfirst(((Expr *) lfirst(temp))->args)))
return TRUE;
}
return FALSE;
}
else if (IsA(clause, Expr))
{
/*
* Recursively scan the arguments of an expression. NOTE: this
* must come after is_subplan() case since subplan is a kind of
* Expr node.
*/
foreach(temp, ((Expr *) clause)->args)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
return FALSE;
}
else if (IsA(clause, Aggref))
return contain_var_clause(((Aggref *) clause)->target);
else if (IsA(clause, ArrayRef))
{
foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
if (contain_var_clause(((ArrayRef *) clause)->refexpr))
return TRUE;
if (contain_var_clause(((ArrayRef *) clause)->refassgnexpr))
return TRUE;
return FALSE;
}
else if (case_clause(clause))
{
foreach(temp, ((CaseExpr *) clause)->args)
{
CaseWhen *when = (CaseWhen *) lfirst(temp);
if (contain_var_clause(when->expr))
return TRUE;
if (contain_var_clause(when->result))
return TRUE;
}
return (contain_var_clause(((CaseExpr *) clause)->defresult));
}
else
{
elog(ERROR, "contain_var_clause: Cannot handle node type %d",
nodeTag(clause));
}
return FALSE; static bool
contain_var_clause_walker(Node *node, void *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
return true; /* abort the tree traversal and return true */
return expression_tree_walker(node, contain_var_clause_walker, context);
} }
/* /*
* pull_var_clause * pull_var_clause
* Recursively pulls all var nodes from a clause by pulling vars from the * Recursively pulls all var nodes from an expression clause.
* left and right operands of the clause.
* *
* Returns list of varnodes found. Note the varnodes themselves are not * Returns list of varnodes found. Note the varnodes themselves are not
* copied, only referenced. * copied, only referenced.
...@@ -168,68 +94,24 @@ contain_var_clause(Node *clause) ...@@ -168,68 +94,24 @@ contain_var_clause(Node *clause)
List * List *
pull_var_clause(Node *clause) pull_var_clause(Node *clause)
{ {
List *retval = NIL; List *result = NIL;
List *temp;
if (clause == NULL)
return NIL;
else if (IsA(clause, Var))
retval = lcons(clause, NIL);
else if (single_node(clause))
retval = NIL;
else if (IsA(clause, Iter))
retval = pull_var_clause(((Iter *) clause)->iterexpr);
else if (is_subplan(clause))
{
foreach(temp, ((Expr *) clause)->args)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
/* Also get Var-s from left sides of Oper-s */
foreach(temp, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
retval = nconc(retval,
pull_var_clause(lfirst(((Expr *) lfirst(temp))->args)));
}
else if (IsA(clause, Expr))
{
/* pull_var_clause_walker(clause, &result);
* Recursively scan the arguments of an expression. NOTE: this return result;
* must come after is_subplan() case since subplan is a kind of }
* Expr node.
*/
foreach(temp, ((Expr *) clause)->args)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
}
else if (IsA(clause, Aggref))
retval = pull_var_clause(((Aggref *) clause)->target);
else if (IsA(clause, ArrayRef))
{
foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
retval = nconc(retval,
pull_var_clause(((ArrayRef *) clause)->refexpr));
retval = nconc(retval,
pull_var_clause(((ArrayRef *) clause)->refassgnexpr));
}
else if (case_clause(clause))
{
foreach(temp, ((CaseExpr *) clause)->args)
{
CaseWhen *when = (CaseWhen *) lfirst(temp);
retval = nconc(retval, pull_var_clause(when->expr)); static bool
retval = nconc(retval, pull_var_clause(when->result)); pull_var_clause_walker(Node *node, List **listptr)
} {
retval = nconc(retval, pull_var_clause(((CaseExpr *) clause)->defresult)); if (node == NULL)
} return false;
else if (IsA(node, Var))
{ {
elog(ERROR, "pull_var_clause: Cannot handle node type %d", *listptr = lappend(*listptr, node);
nodeTag(clause)); return false;
} }
return expression_tree_walker(node, pull_var_clause_walker,
return retval; (void *) listptr);
} }
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: clauses.h,v 1.18 1999/05/25 22:43:03 momjian Exp $ * $Id: clauses.h,v 1.19 1999/06/19 03:41:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <nodes/relation.h> #include <nodes/relation.h>
extern Expr *make_clause(int type, Node *oper, List *args); extern Expr *make_clause(int type, Node *oper, List *args);
extern bool is_opclause(Node *clause); extern bool is_opclause(Node *clause);
extern Expr *make_opclause(Oper *op, Var *leftop, Var *rightop); extern Expr *make_opclause(Oper *op, Var *leftop, Var *rightop);
extern Var *get_leftop(Expr *clause); extern Var *get_leftop(Expr *clause);
...@@ -51,8 +52,11 @@ extern void get_rels_atts(Node *clause, int *relid1, ...@@ -51,8 +52,11 @@ extern void get_rels_atts(Node *clause, int *relid1,
AttrNumber *attno1, int *relid2, AttrNumber *attno2); AttrNumber *attno1, int *relid2, AttrNumber *attno2);
extern void CommuteClause(Node *clause); extern void CommuteClause(Node *clause);
#define is_subplan(clause) ((Node*) clause != NULL && \ extern bool expression_tree_walker(Node *node, bool (*walker) (),
nodeTag((Node*) clause) == T_Expr && \ void *context);
((Expr *) clause)->opType == SUBPLAN_EXPR)
#define is_subplan(clause) ((Node*) (clause) != NULL && \
nodeTag((Node*) (clause)) == T_Expr && \
((Expr *) (clause))->opType == SUBPLAN_EXPR)
#endif /* CLAUSES_H */ #endif /* CLAUSES_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment