aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c145
-rw-r--r--src/backend/optimizer/util/tlist.c179
-rw-r--r--src/backend/optimizer/util/var.c28
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;
-}