diff options
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 145 | ||||
-rw-r--r-- | src/backend/optimizer/util/tlist.c | 179 | ||||
-rw-r--r-- | src/backend/optimizer/util/var.c | 28 |
3 files changed, 137 insertions, 215 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 diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 37a790cc3dd..dfe2963581f 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.39 1999/08/21 03:49:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.40 1999/08/22 20:14:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,8 +19,6 @@ #include "optimizer/tlist.h" #include "optimizer/var.h" -static Node *unflatten_tlist_mutator(Node *node, List *flat_tlist); - /***************************************************************************** * ---------- RELATION node target list routines ---------- *****************************************************************************/ @@ -28,39 +26,38 @@ static Node *unflatten_tlist_mutator(Node *node, List *flat_tlist); /* * tlistentry_member * Finds the (first) member of the given tlist whose expression is - * var_equal() to the given var. Result is NULL if no such member. + * equal() to the given expression. Result is NULL if no such member. */ TargetEntry * -tlistentry_member(Var *var, List *targetlist) +tlistentry_member(Node *node, List *targetlist) { - if (var && IsA(var, Var)) + List *temp; + + foreach(temp, targetlist) { - List *temp; + TargetEntry *tlentry = (TargetEntry *) lfirst(temp); - foreach(temp, targetlist) - { - if (var_equal(var, get_expr(lfirst(temp)))) - return (TargetEntry *) lfirst(temp); - } + if (equal(node, tlentry->expr)) + return tlentry; } return NULL; } /* - * matching_tlist_var + * matching_tlist_expr * Same as tlistentry_member(), except returns the tlist expression * rather than its parent TargetEntry node. */ -Expr * -matching_tlist_var(Var *var, List *targetlist) +Node * +matching_tlist_expr(Node *node, List *targetlist) { TargetEntry *tlentry; - tlentry = tlistentry_member(var, targetlist); + tlentry = tlistentry_member(node, targetlist); if (tlentry) - return (Expr *) get_expr(tlentry); + return tlentry->expr; - return (Expr *) NULL; + return (Node *) NULL; } /* @@ -69,11 +66,11 @@ matching_tlist_var(Var *var, List *targetlist) * rather than its parent TargetEntry node. */ Resdom * -tlist_member(Var *var, List *tlist) +tlist_member(Node *node, List *targetlist) { TargetEntry *tlentry; - tlentry = tlistentry_member(var, tlist); + tlentry = tlistentry_member(node, targetlist); if (tlentry) return tlentry->resdom; @@ -89,7 +86,7 @@ tlist_member(Var *var, List *tlist) void add_var_to_tlist(RelOptInfo *rel, Var *var) { - if (! tlistentry_member(var, rel->targetlist)) + if (! tlistentry_member((Node *) var, rel->targetlist)) { /* XXX is copyObject necessary here? */ rel->targetlist = lappend(rel->targetlist, @@ -116,85 +113,11 @@ create_tl_element(Var *var, int resdomno) (Node *) var); } -/* - * get_actual_tlist - * Returns the targetlist elements from a relation tlist. - * - */ -List * -get_actual_tlist(List *tlist) -{ - - /* - * this function is not making sense. - ay 10/94 - */ -#ifdef NOT_USED - List *element = NIL; - List *result = NIL; - - if (tlist == NULL) - { - elog(DEBUG, "calling get_actual_tlist with empty tlist"); - return NIL; - } - - /* - * XXX - it is unclear to me what exactly get_entry should be doing, - * as it is unclear to me the exact relationship between "TL" "TLE" - * and joinlists - */ - - foreach(element, tlist) - result = lappend(result, lfirst((List *) lfirst(element))); - - return result; -#endif - return tlist; -} - /***************************************************************************** * ---------- GENERAL target list routines ---------- *****************************************************************************/ /* - * match_varid - * Searches a target list for an entry matching a given var. - * - * Returns the target list entry (resdom var) of the matching var, - * or NULL if no match. - */ -TargetEntry * -match_varid(Var *test_var, List *tlist) -{ - List *tl; - - Assert(test_var->varlevelsup == 0); /* XXX why? */ - - foreach(tl, tlist) - { - TargetEntry *entry = lfirst(tl); - Var *tlvar = get_expr(entry); - - if (!IsA(tlvar, Var)) - continue; - - /* - * we test the original varno, instead of varno which might be - * changed to INNER/OUTER. XXX is test on vartype necessary? - */ - Assert(tlvar->varlevelsup == 0); - - if (tlvar->varnoold == test_var->varnoold && - tlvar->varoattno == test_var->varoattno && - tlvar->vartype == test_var->vartype) - return entry; - } - - return NULL; -} - - -/* * new_unsorted_tlist * Creates a copy of a target list by creating new resdom nodes * without sort information. @@ -221,37 +144,6 @@ new_unsorted_tlist(List *targetlist) } /* - * copy_vars - * Replaces the var nodes in the first target list with those from - * the second target list. The two target lists are assumed to be - * identical except their actual resdoms and vars are different. - * - * 'target' is the target list to be replaced - * 'source' is the target list to be copied - * - * Returns a new target list. - * - */ -List * -copy_vars(List *target, List *source) -{ - List *result = NIL; - List *src; - List *dest; - - for (src = source, dest = target; - src != NIL && dest != NIL; - src = lnext(src), dest = lnext(dest)) - { - TargetEntry *temp = makeTargetEntry(((TargetEntry *) lfirst(dest))->resdom, - (Node *) get_expr(lfirst(src))); - - result = lappend(result, temp); - } - return result; -} - -/* * flatten_tlist * Create a target list that only contains unique variables. * @@ -292,7 +184,7 @@ add_to_flat_tlist(List *tlist, List *vars) { Var *var = lfirst(v); - if (! tlistentry_member(var, tlist)) + if (! tlistentry_member((Node *) var, tlist)) { Resdom *r; @@ -310,39 +202,6 @@ add_to_flat_tlist(List *tlist, List *vars) return tlist; } -/* - * unflatten_tlist - * Reconstructs the target list of a query by replacing vars within - * target expressions with vars from the 'flattened' target list. - * - * XXX is this really necessary? Why can't we just use the tlist as is? - * - * 'full_tlist' is the original target list - * 'flat_tlist' is the flattened (var-only) target list - * - * Returns the rebuilt target list. The original is not modified. - * - */ -List * -unflatten_tlist(List *full_tlist, List *flat_tlist) -{ - return (List *) unflatten_tlist_mutator((Node *) full_tlist, - flat_tlist); -} - -static Node * -unflatten_tlist_mutator(Node *node, List *flat_tlist) -{ - if (node == NULL) - return NULL; - if (IsA(node, Var)) - return (Node *) get_expr(match_varid((Var *) node, - flat_tlist)); - return expression_tree_mutator(node, unflatten_tlist_mutator, - (void *) flat_tlist); -} - - Var * get_expr(TargetEntry *tle) { diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index be181ea626f..a544041122b 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.22 1999/08/10 03:00:15 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.23 1999/08/22 20:14:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -105,29 +105,3 @@ pull_var_clause_walker(Node *node, List **listptr) return expression_tree_walker(node, pull_var_clause_walker, (void *) listptr); } - -/* - * var_equal - * - * This is like equal() except that it does NOT test varnoold and - * varoattno. Also, it will not compare non-Var nodes. - * - * Returns t iff two var nodes correspond to the same attribute. - */ -bool -var_equal(Var *var1, Var *var2) -{ - if (var1 != NULL && IsA(var1, Var) && - var2 != NULL && IsA(var2, Var) && - var1->varno == var2->varno && - var1->varattno == var2->varattno && - var1->vartype == var2->vartype && - var1->vartypmod == var2->vartypmod && - var1->varlevelsup == var2->varlevelsup) - { - Assert(var1->varlevelsup == 0); /* XXX why do this here??? */ - return true; - } - else - return false; -} |