mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
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...
This commit is contained in:
parent
d30c4b0562
commit
86f36719db
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.35 1999/05/25 22:41:46 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.36 1999/06/19 03:41:45 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -35,7 +35,8 @@
|
|||||||
#include "optimizer/internal.h"
|
#include "optimizer/internal.h"
|
||||||
#include "optimizer/var.h"
|
#include "optimizer/var.h"
|
||||||
|
|
||||||
static bool agg_clause(Node *clause);
|
|
||||||
|
static bool fix_opid_walker(Node *node, void *context);
|
||||||
|
|
||||||
|
|
||||||
Expr *
|
Expr *
|
||||||
@ -139,16 +140,6 @@ get_rightop(Expr *clause)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* AGG clause functions
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
static bool
|
|
||||||
agg_clause(Node *clause)
|
|
||||||
{
|
|
||||||
return (clause != NULL && nodeTag(clause) == T_Aggref);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* FUNC clause functions
|
* FUNC clause functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@ -163,7 +154,8 @@ bool
|
|||||||
is_funcclause(Node *clause)
|
is_funcclause(Node *clause)
|
||||||
{
|
{
|
||||||
return (clause != NULL &&
|
return (clause != NULL &&
|
||||||
nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == FUNC_EXPR);
|
nodeTag(clause) == T_Expr &&
|
||||||
|
((Expr *) clause)->opType == FUNC_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -235,7 +227,8 @@ bool
|
|||||||
not_clause(Node *clause)
|
not_clause(Node *clause)
|
||||||
{
|
{
|
||||||
return (clause != NULL &&
|
return (clause != NULL &&
|
||||||
nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == NOT_EXPR);
|
nodeTag(clause) == T_Expr &&
|
||||||
|
((Expr *) clause)->opType == NOT_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -283,7 +276,8 @@ bool
|
|||||||
and_clause(Node *clause)
|
and_clause(Node *clause)
|
||||||
{
|
{
|
||||||
return (clause != NULL &&
|
return (clause != NULL &&
|
||||||
nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == AND_EXPR);
|
nodeTag(clause) == T_Expr &&
|
||||||
|
((Expr *) clause)->opType == AND_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -374,20 +368,20 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
|||||||
List *clvars = pull_var_clause(clause);
|
List *clvars = pull_var_clause(clause);
|
||||||
List *var_list = NIL;
|
List *var_list = NIL;
|
||||||
List *varno_list = NIL;
|
List *varno_list = NIL;
|
||||||
List *i = NIL;
|
List *i;
|
||||||
|
|
||||||
foreach(i, clvars)
|
foreach(i, clvars)
|
||||||
{
|
{
|
||||||
Var *var = (Var *) lfirst(i);
|
Var *var = (Var *) lfirst(i);
|
||||||
List *vi;
|
List *vi;
|
||||||
|
|
||||||
|
Assert(var->varlevelsup == 0);
|
||||||
if (!intMember(var->varno, varno_list))
|
if (!intMember(var->varno, varno_list))
|
||||||
varno_list = lappendi(varno_list, var->varno);
|
varno_list = lappendi(varno_list, var->varno);
|
||||||
foreach(vi, var_list)
|
foreach(vi, var_list)
|
||||||
{
|
{
|
||||||
Var *in_list = (Var *) lfirst(vi);
|
Var *in_list = (Var *) lfirst(vi);
|
||||||
|
|
||||||
Assert(var->varlevelsup == 0);
|
|
||||||
if (in_list->varno == var->varno &&
|
if (in_list->varno == var->varno &&
|
||||||
in_list->varattno == var->varattno)
|
in_list->varattno == var->varattno)
|
||||||
break;
|
break;
|
||||||
@ -398,7 +392,6 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
|||||||
|
|
||||||
*relids = varno_list;
|
*relids = varno_list;
|
||||||
*vars = var_list;
|
*vars = var_list;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -411,8 +404,8 @@ int
|
|||||||
NumRelids(Node *clause)
|
NumRelids(Node *clause)
|
||||||
{
|
{
|
||||||
List *vars = pull_var_clause(clause);
|
List *vars = pull_var_clause(clause);
|
||||||
List *i = NIL;
|
|
||||||
List *var_list = NIL;
|
List *var_list = NIL;
|
||||||
|
List *i;
|
||||||
|
|
||||||
foreach(i, vars)
|
foreach(i, vars)
|
||||||
{
|
{
|
||||||
@ -431,6 +424,8 @@ NumRelids(Node *clause)
|
|||||||
* Returns t iff the clause is a 'not' clause or if any of the
|
* Returns t iff the clause is a 'not' clause or if any of the
|
||||||
* subclauses within an 'or' clause contain 'not's.
|
* subclauses within an 'or' clause contain 'not's.
|
||||||
*
|
*
|
||||||
|
* NOTE that only the top-level AND/OR structure is searched for NOTs;
|
||||||
|
* we are not interested in buried substructure.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
contains_not(Node *clause)
|
contains_not(Node *clause)
|
||||||
@ -524,81 +519,40 @@ qual_clause_p(Node *clause)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* fix_opid
|
* fix_opid
|
||||||
* Calculate the opfid from the opno...
|
* Calculate opid field from opno for each Oper node in given tree.
|
||||||
*
|
*
|
||||||
* Returns nothing.
|
* Returns nothing.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fix_opid(Node *clause)
|
fix_opid(Node *clause)
|
||||||
{
|
{
|
||||||
if (clause == NULL || single_node(clause))
|
/* This tree walk requires no special setup, so away we go... */
|
||||||
;
|
fix_opid_walker(clause, NULL);
|
||||||
else if (or_clause(clause) || and_clause(clause))
|
|
||||||
fix_opids(((Expr *) clause)->args);
|
|
||||||
else if (is_funcclause(clause))
|
|
||||||
fix_opids(((Expr *) clause)->args);
|
|
||||||
else if (IsA(clause, ArrayRef))
|
|
||||||
{
|
|
||||||
ArrayRef *aref = (ArrayRef *) clause;
|
|
||||||
|
|
||||||
fix_opids(aref->refupperindexpr);
|
|
||||||
fix_opids(aref->reflowerindexpr);
|
|
||||||
fix_opid(aref->refexpr);
|
|
||||||
fix_opid(aref->refassgnexpr);
|
|
||||||
}
|
|
||||||
else if (not_clause(clause))
|
|
||||||
fix_opid((Node *) get_notclausearg((Expr *) clause));
|
|
||||||
else if (is_opclause(clause))
|
|
||||||
{
|
|
||||||
replace_opid((Oper *) ((Expr *) clause)->oper);
|
|
||||||
fix_opid((Node *) get_leftop((Expr *) clause));
|
|
||||||
fix_opid((Node *) get_rightop((Expr *) clause));
|
|
||||||
}
|
|
||||||
else if (agg_clause(clause))
|
|
||||||
fix_opid(((Aggref *) clause)->target);
|
|
||||||
else if (is_subplan(clause) &&
|
|
||||||
((SubPlan *) ((Expr *) clause)->oper)->sublink->subLinkType != EXISTS_SUBLINK)
|
|
||||||
{
|
|
||||||
List *lst;
|
|
||||||
|
|
||||||
foreach(lst, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
|
|
||||||
{
|
|
||||||
replace_opid((Oper *) ((Expr *) lfirst(lst))->oper);
|
|
||||||
fix_opid((Node *) get_leftop((Expr *) lfirst(lst)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (case_clause(clause))
|
|
||||||
{
|
|
||||||
List *lst;
|
|
||||||
|
|
||||||
fix_opid(((CaseExpr *) clause)->defresult);
|
|
||||||
|
|
||||||
/* Run through the WHEN clauses... */
|
|
||||||
foreach(lst, ((CaseExpr *) clause)->args)
|
|
||||||
{
|
|
||||||
fix_opid(((CaseWhen *) lfirst(lst))->expr);
|
|
||||||
fix_opid(((CaseWhen *) lfirst(lst))->result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fix_opid_walker (Node *node, void *context)
|
||||||
|
{
|
||||||
|
if (node == NULL)
|
||||||
|
return false;
|
||||||
|
if (is_opclause(node))
|
||||||
|
replace_opid((Oper *) ((Expr *) node)->oper);
|
||||||
|
return expression_tree_walker(node, fix_opid_walker, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fix_opids
|
* fix_opids
|
||||||
* Calculate the opfid from the opno for all the clauses...
|
* Calculate the opid from the opno for all the clauses...
|
||||||
*
|
*
|
||||||
* Returns its argument.
|
* Returns its argument.
|
||||||
*
|
*
|
||||||
|
* XXX This could and should be merged with fix_opid.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
fix_opids(List *clauses)
|
fix_opids(List *clauses)
|
||||||
{
|
{
|
||||||
List *clause;
|
fix_opid((Node *) clauses);
|
||||||
|
|
||||||
foreach(clause, clauses)
|
|
||||||
fix_opid(lfirst(clause));
|
|
||||||
|
|
||||||
return clauses;
|
return clauses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,6 +725,10 @@ get_rels_atts(Node *clause,
|
|||||||
*attno2 = _SELEC_VALUE_UNKNOWN_;
|
*attno2 = _SELEC_VALUE_UNKNOWN_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------
|
||||||
|
* CommuteClause: commute a binary operator clause
|
||||||
|
*--------------------
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
CommuteClause(Node *clause)
|
CommuteClause(Node *clause)
|
||||||
{
|
{
|
||||||
@ -805,3 +763,179 @@ CommuteClause(Node *clause)
|
|||||||
lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
|
lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
|
||||||
lsecond(((Expr *) clause)->args) = temp;
|
lsecond(((Expr *) clause)->args) = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 or delete 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* (But only the "expr" part of a TargetEntry is examined, unless the walker
|
||||||
|
* chooses to process TargetEntry nodes specially.)
|
||||||
|
*
|
||||||
|
* expression_tree_walker will handle a SUBPLAN_EXPR node by recursing into
|
||||||
|
* the args and slink->oper lists (which belong to the outer plan), but it
|
||||||
|
* will *not* visit the inner plan, since that's typically what expression
|
||||||
|
* tree walkers want. A walker that wants to visit the subplan can force
|
||||||
|
* appropriate behavior by recognizing subplan nodes and doing the right
|
||||||
|
* thing.
|
||||||
|
*
|
||||||
|
* Bare SubLink nodes (without a SUBPLAN_EXPR) will trigger an error unless
|
||||||
|
* detected and processed by the walker. We expect that walkers used before
|
||||||
|
* sublink processing is done will handle them properly. (XXX Maybe ignoring
|
||||||
|
* them would be better default behavior?)
|
||||||
|
*--------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
expression_tree_walker(Node *node, bool (*walker) (), void *context)
|
||||||
|
{
|
||||||
|
List *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;
|
||||||
|
switch (nodeTag(node))
|
||||||
|
{
|
||||||
|
case T_Ident:
|
||||||
|
case T_Const:
|
||||||
|
case T_Var:
|
||||||
|
case T_Param:
|
||||||
|
/* primitive node types with no subnodes */
|
||||||
|
break;
|
||||||
|
case T_Expr:
|
||||||
|
{
|
||||||
|
Expr *expr = (Expr *) node;
|
||||||
|
if (expr->opType == SUBPLAN_EXPR)
|
||||||
|
{
|
||||||
|
/* examine args list (params to be passed to subplan) */
|
||||||
|
if (expression_tree_walker((Node *) expr->args,
|
||||||
|
walker, context))
|
||||||
|
return true;
|
||||||
|
/* examine oper list as well */
|
||||||
|
if (expression_tree_walker(
|
||||||
|
(Node *) ((SubPlan *) expr->oper)->sublink->oper,
|
||||||
|
walker, context))
|
||||||
|
return true;
|
||||||
|
/* but not the subplan itself */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* for other Expr node types, just examine args list */
|
||||||
|
if (expression_tree_walker((Node *) expr->args,
|
||||||
|
walker, context))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_Aggref:
|
||||||
|
return walker(((Aggref *) node)->target, context);
|
||||||
|
case T_Iter:
|
||||||
|
return walker(((Iter *) node)->iterexpr, context);
|
||||||
|
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_CaseExpr:
|
||||||
|
{
|
||||||
|
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
/* caseexpr->arg should be null, but we'll check it anyway */
|
||||||
|
if (walker(caseexpr->arg, context))
|
||||||
|
return true;
|
||||||
|
if (walker(caseexpr->defresult, context))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_List:
|
||||||
|
foreach(temp, (List *) node)
|
||||||
|
{
|
||||||
|
if (walker((Node *) lfirst(temp), context))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case T_TargetEntry:
|
||||||
|
return walker(((TargetEntry *) node)->expr, context);
|
||||||
|
default:
|
||||||
|
elog(ERROR, "expression_tree_walker: Unexpected node type %d",
|
||||||
|
nodeTag(node));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -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 @@
|
|||||||
|
|
||||||
#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,45 +26,42 @@
|
|||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
switch (nodeTag(me))
|
|
||||||
{
|
|
||||||
case T_List:
|
|
||||||
foreach(i, (List *) me)
|
|
||||||
result = nconc(result, pull_varnos(lfirst(i)));
|
|
||||||
break;
|
|
||||||
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 result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
pull_varnos_walker(Node *node, List **listptr)
|
||||||
|
{
|
||||||
|
if (node == NULL)
|
||||||
|
return false;
|
||||||
|
if (IsA(node, Var))
|
||||||
|
{
|
||||||
|
Var *var = (Var *) node;
|
||||||
|
if (!intMember(var->varno, *listptr))
|
||||||
|
*listptr = lconsi(var->varno, *listptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return expression_tree_walker(node, pull_varnos_walker, (void *) listptr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* contain_var_clause
|
* contain_var_clause
|
||||||
* Recursively scan a clause to discover whether it contains any Var nodes.
|
* Recursively scan a clause to discover whether it contains any Var nodes.
|
||||||
@ -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)
|
|||||||
List *
|
List *
|
||||||
pull_var_clause(Node *clause)
|
pull_var_clause(Node *clause)
|
||||||
{
|
{
|
||||||
List *retval = NIL;
|
List *result = NIL;
|
||||||
List *temp;
|
|
||||||
|
|
||||||
if (clause == NULL)
|
pull_var_clause_walker(clause, &result);
|
||||||
return NIL;
|
return result;
|
||||||
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))
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
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));
|
|
||||||
retval = nconc(retval, pull_var_clause(when->result));
|
|
||||||
}
|
|
||||||
retval = nconc(retval, pull_var_clause(((CaseExpr *) clause)->defresult));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elog(ERROR, "pull_var_clause: Cannot handle node type %d",
|
|
||||||
nodeTag(clause));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
static bool
|
||||||
|
pull_var_clause_walker(Node *node, List **listptr)
|
||||||
|
{
|
||||||
|
if (node == NULL)
|
||||||
|
return false;
|
||||||
|
if (IsA(node, Var))
|
||||||
|
{
|
||||||
|
*listptr = lappend(*listptr, node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return expression_tree_walker(node, pull_var_clause_walker,
|
||||||
|
(void *) listptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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 @@
|
|||||||
#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,
|
|||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user