diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-08-22 20:15:04 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-08-22 20:15:04 +0000 |
commit | 78114cd4d4fd99feb0c753de34d358b16d1ff0ee (patch) | |
tree | 58838858badf427beddaafe425a9def510741d37 /src/backend/optimizer/util/clauses.c | |
parent | db436adf761bd5cb7990745ceba2959ac4bfca7c (diff) | |
download | postgresql-78114cd4d4fd99feb0c753de34d358b16d1ff0ee.tar.gz postgresql-78114cd4d4fd99feb0c753de34d358b16d1ff0ee.zip |
Further planner/optimizer cleanups. Move all set_tlist_references
and fix_opids processing to a single recursive pass over the plan tree
executed at the very tail end of planning, rather than haphazardly here
and there at different places. Now that tlist Vars do not get modified
until the very end, it's possible to get rid of the klugy var_equal and
match_varid partial-matching routines, and just use plain equal()
throughout the optimizer. This is a step towards allowing merge and
hash joins to be done on expressions instead of only Vars ...
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 145 |
1 files changed, 117 insertions, 28 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index ca4353f6085..fbb5a98e83d 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.47 1999/08/16 02:17:56 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.48 1999/08/22 20:14:53 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -24,11 +24,19 @@ #include "nodes/plannodes.h" #include "optimizer/clauses.h" #include "optimizer/internal.h" +#include "optimizer/tlist.h" #include "optimizer/var.h" #include "utils/lsyscache.h" -static bool fix_opids_walker(Node *node, void *context); +typedef struct { + List *groupClause; + List *targetList; +} check_subplans_for_ungrouped_vars_context; + +static bool pull_agg_clause_walker(Node *node, List **listptr); +static bool check_subplans_for_ungrouped_vars_walker(Node *node, + check_subplans_for_ungrouped_vars_context *context); static int is_single_func(Node *node); @@ -351,12 +359,118 @@ pull_constant_clauses(List *quals, List **constantQual) else restqual = lcons(lfirst(q), restqual); } - freeList(quals); /* XXX seems a tad risky? */ *constantQual = constqual; return restqual; } /* + * pull_agg_clause + * Recursively pulls all Aggref nodes from an expression tree. + * + * Returns list of Aggref nodes found. Note the nodes themselves are not + * copied, only referenced. + */ +List * +pull_agg_clause(Node *clause) +{ + List *result = NIL; + + pull_agg_clause_walker(clause, &result); + return result; +} + +static bool +pull_agg_clause_walker(Node *node, List **listptr) +{ + if (node == NULL) + return false; + if (IsA(node, Aggref)) + { + *listptr = lappend(*listptr, node); + /* continue, to iterate over agg's arg as well (do nested aggregates + * actually work?) + */ + } + return expression_tree_walker(node, pull_agg_clause_walker, + (void *) listptr); +} + +/* + * check_subplans_for_ungrouped_vars + * Check for subplans that are being passed ungrouped variables as + * parameters; return TRUE if any are found. + * + * In most contexts, ungrouped variables will be detected by the parser (see + * parse_agg.c, exprIsAggOrGroupCol()). But that routine currently does not + * check subplans, because the necessary info is not computed until the + * planner runs. So we do it here, after we have processed the subplan. + * This ought to be cleaned up someday. + * + * 'clause' is the expression tree to be searched for subplans. + * 'groupClause' is the GROUP BY list (a list of GroupClause nodes). + * 'targetList' is the target list that the group clauses refer to. + */ +bool +check_subplans_for_ungrouped_vars(Node *clause, + List *groupClause, + List *targetList) +{ + check_subplans_for_ungrouped_vars_context context; + + context.groupClause = groupClause; + context.targetList = targetList; + return check_subplans_for_ungrouped_vars_walker(clause, &context); +} + +static bool +check_subplans_for_ungrouped_vars_walker(Node *node, + check_subplans_for_ungrouped_vars_context *context) +{ + if (node == NULL) + return false; + /* + * We can ignore Vars other than in subplan args lists, + * since the parser already checked 'em. + */ + if (is_subplan(node)) + { + /* + * The args list of the subplan node represents attributes from + * outside passed into the sublink. + */ + List *t; + + foreach(t, ((Expr *) node)->args) + { + Node *thisarg = lfirst(t); + bool contained_in_group_clause = false; + List *gl; + + foreach(gl, context->groupClause) + { + GroupClause *gcl = lfirst(gl); + Node *groupexpr; + + groupexpr = get_sortgroupclause_expr(gcl, + context->targetList); + if (equal(thisarg, groupexpr)) + { + contained_in_group_clause = true; + break; + } + } + + if (!contained_in_group_clause) + return true; /* found an ungrouped argument */ + } + } + return expression_tree_walker(node, + check_subplans_for_ungrouped_vars_walker, + (void *) context); +} + + +/* * clause_relids_vars * Retrieves distinct relids and vars appearing within a clause. * @@ -417,31 +531,6 @@ NumRelids(Node *clause) } /* - * fix_opids - * Calculate opid field from opno for each Oper node in given tree. - * (The given tree can be anything expression_tree_walker handles.) - * - * Returns its argument, which has been modified in-place. - */ -List * -fix_opids(List *clauses) -{ - /* This tree walk requires no special setup, so away we go... */ - fix_opids_walker((Node *) clauses, NULL); - return clauses; -} - -static bool -fix_opids_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_opids_walker, context); -} - -/* * get_relattval * Extract information from a restriction or join clause for * selectivity estimation. The inputs are an expression |