summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/var.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/var.c')
-rw-r--r--src/backend/optimizer/util/var.c360
1 files changed, 29 insertions, 331 deletions
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 81aad81c0f3..ee861c3557e 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,18 +8,16 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.35 2002/04/11 20:00:00 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.36 2002/04/28 19:54:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "nodes/makefuncs.h"
#include "nodes/plannodes.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
-#include "parser/parse_coerce.h"
typedef struct
@@ -44,7 +42,7 @@ typedef struct
typedef struct
{
Query *root;
- int expandRTI;
+ bool force;
} flatten_join_alias_vars_context;
static bool pull_varnos_walker(Node *node,
@@ -56,8 +54,6 @@ static bool pull_var_clause_walker(Node *node,
pull_var_clause_context *context);
static Node *flatten_join_alias_vars_mutator(Node *node,
flatten_join_alias_vars_context *context);
-static Node *flatten_join_alias_var(Var *var, Query *root, int expandRTI);
-static Node *find_jointree_item(Node *jtnode, int rtindex);
/*
@@ -314,26 +310,30 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
/*
* flatten_join_alias_vars
- * Whereever possible, replace Vars that reference JOIN outputs with
- * references to the original relation variables instead. This allows
- * quals involving such vars to be pushed down. Vars that cannot be
- * simplified to non-join Vars are replaced by COALESCE expressions
- * if they have varno = expandRTI, and are left as JOIN RTE references
- * otherwise. (Pass expandRTI = 0 to prevent all COALESCE expansion.)
+ * Replace Vars that reference JOIN outputs with references to the original
+ * relation variables instead. This allows quals involving such vars to be
+ * pushed down.
*
- * Upper-level vars (with varlevelsup > 0) are ignored; normally there
- * should not be any by the time this routine is called.
+ * If force is TRUE then we will reduce all JOIN alias Vars to non-alias Vars
+ * or expressions thereof (there may be COALESCE and/or type conversions
+ * involved). If force is FALSE we will not expand a Var to a non-Var
+ * expression. This is a hack to avoid confusing mergejoin planning, which
+ * currently cannot cope with non-Var join items --- we leave the join vars
+ * as Vars till after planning is done, then expand them during setrefs.c.
+ *
+ * Upper-level vars (with varlevelsup > 0) are ignored; normally there
+ * should not be any by the time this routine is called.
*
* Does not examine subqueries, therefore must only be used after reduction
* of sublinks to subplans!
*/
Node *
-flatten_join_alias_vars(Node *node, Query *root, int expandRTI)
+flatten_join_alias_vars(Node *node, Query *root, bool force)
{
flatten_join_alias_vars_context context;
context.root = root;
- context.expandRTI = expandRTI;
+ context.force = force;
return flatten_join_alias_vars_mutator(node, &context);
}
@@ -347,326 +347,24 @@ flatten_join_alias_vars_mutator(Node *node,
if (IsA(node, Var))
{
Var *var = (Var *) node;
+ RangeTblEntry *rte;
+ Node *newvar;
if (var->varlevelsup != 0)
return node; /* no need to copy, really */
- return flatten_join_alias_var(var, context->root, context->expandRTI);
- }
- return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
- (void *) context);
-}
-
-static Node *
-flatten_join_alias_var(Var *var, Query *root, int expandRTI)
-{
- Index varno = var->varno;
- AttrNumber varattno = var->varattno;
- Oid vartype = var->vartype;
- int32 vartypmod = var->vartypmod;
- JoinExpr *jexpr = NULL;
-
- /*
- * Loop to cope with joins of joins
- */
- for (;;)
- {
- RangeTblEntry *rte = rt_fetch(varno, root->rtable);
- Index leftrti,
- rightrti;
- AttrNumber leftattno,
- rightattno;
- RangeTblEntry *subrte;
- Oid subtype;
- int32 subtypmod;
-
+ rte = rt_fetch(var->varno, context->root->rtable);
if (rte->rtekind != RTE_JOIN)
- break; /* reached a non-join RTE */
- /*
- * Find the RT indexes of the left and right children of the
- * join node. We have to search the join tree to do this,
- * which is a major pain in the neck --- but keeping RT indexes
- * in other RT entries is worse, because it makes modifying
- * querytrees difficult. (Perhaps we can improve on the
- * rangetable/jointree datastructure someday.) One thing we
- * can do is avoid repeated searches while tracing a single
- * variable down to its baserel.
- */
- if (jexpr == NULL)
- jexpr = (JoinExpr *)
- find_jointree_item((Node *) root->jointree, varno);
- if (jexpr == NULL ||
- !IsA(jexpr, JoinExpr) ||
- jexpr->rtindex != varno)
- elog(ERROR, "flatten_join_alias_var: failed to find JoinExpr");
- if (IsA(jexpr->larg, RangeTblRef))
- leftrti = ((RangeTblRef *) jexpr->larg)->rtindex;
- else if (IsA(jexpr->larg, JoinExpr))
- leftrti = ((JoinExpr *) jexpr->larg)->rtindex;
- else
- {
- elog(ERROR, "flatten_join_alias_var: unexpected subtree type");
- leftrti = 0; /* keep compiler quiet */
- }
- if (IsA(jexpr->rarg, RangeTblRef))
- rightrti = ((RangeTblRef *) jexpr->rarg)->rtindex;
- else if (IsA(jexpr->rarg, JoinExpr))
- rightrti = ((JoinExpr *) jexpr->rarg)->rtindex;
- else
- {
- elog(ERROR, "flatten_join_alias_var: unexpected subtree type");
- rightrti = 0; /* keep compiler quiet */
- }
- /*
- * See if the join var is from the left side, the right side,
- * or both (ie, it is a USING/NATURAL JOIN merger column).
- */
- Assert(varattno > 0);
- leftattno = (AttrNumber) nthi(varattno-1, rte->joinleftcols);
- rightattno = (AttrNumber) nthi(varattno-1, rte->joinrightcols);
- if (leftattno && rightattno)
- {
- /*
- * Var is a merge var. If a left or right join, we can replace
- * it by the left or right input var respectively; we only need
- * a COALESCE for a full join. However, beware of the possibility
- * that there's been a type promotion to make the input vars
- * compatible; do not replace a var by one of a different type!
- */
- if (rte->jointype == JOIN_INNER ||
- rte->jointype == JOIN_LEFT)
- {
- subrte = rt_fetch(leftrti, root->rtable);
- get_rte_attribute_type(subrte, leftattno,
- &subtype, &subtypmod);
- if (vartype == subtype && vartypmod == subtypmod)
- {
- varno = leftrti;
- varattno = leftattno;
- jexpr = (JoinExpr *) jexpr->larg;
- continue;
- }
- }
- if (rte->jointype == JOIN_INNER ||
- rte->jointype == JOIN_RIGHT)
- {
- subrte = rt_fetch(rightrti, root->rtable);
- get_rte_attribute_type(subrte, rightattno,
- &subtype, &subtypmod);
- if (vartype == subtype && vartypmod == subtypmod)
- {
- varno = rightrti;
- varattno = rightattno;
- jexpr = (JoinExpr *) jexpr->rarg;
- continue;
- }
- }
- /*
- * This var cannot be substituted directly, only with a COALESCE.
- * Do so only if it belongs to the particular join indicated by
- * the caller.
- */
- if (varno != expandRTI)
- break;
- {
- Node *l_var,
- *r_var;
- CaseExpr *c = makeNode(CaseExpr);
- CaseWhen *w = makeNode(CaseWhen);
- NullTest *n = makeNode(NullTest);
-
- subrte = rt_fetch(leftrti, root->rtable);
- get_rte_attribute_type(subrte, leftattno,
- &subtype, &subtypmod);
- l_var = (Node *) makeVar(leftrti,
- leftattno,
- subtype,
- subtypmod,
- 0);
- if (subtype != vartype)
- {
- l_var = coerce_type(NULL, l_var, subtype,
- vartype, vartypmod, false);
- l_var = coerce_type_typmod(NULL, l_var,
- vartype, vartypmod);
- }
- else if (subtypmod != vartypmod)
- l_var = coerce_type_typmod(NULL, l_var,
- vartype, vartypmod);
-
- subrte = rt_fetch(rightrti, root->rtable);
- get_rte_attribute_type(subrte, rightattno,
- &subtype, &subtypmod);
- r_var = (Node *) makeVar(rightrti,
- rightattno,
- subtype,
- subtypmod,
- 0);
- if (subtype != vartype)
- {
- r_var = coerce_type(NULL, r_var, subtype,
- vartype, vartypmod, false);
- r_var = coerce_type_typmod(NULL, r_var,
- vartype, vartypmod);
- }
- else if (subtypmod != vartypmod)
- r_var = coerce_type_typmod(NULL, r_var,
- vartype, vartypmod);
-
- n->arg = l_var;
- n->nulltesttype = IS_NOT_NULL;
- w->expr = (Node *) n;
- w->result = l_var;
- c->casetype = vartype;
- c->args = makeList1(w);
- c->defresult = r_var;
- return (Node *) c;
- }
- }
- else if (leftattno)
- {
- /* Here we do not need to check the type */
- varno = leftrti;
- varattno = leftattno;
- jexpr = (JoinExpr *) jexpr->larg;
- }
- else
- {
- Assert(rightattno);
- /* Here we do not need to check the type */
- varno = rightrti;
- varattno = rightattno;
- jexpr = (JoinExpr *) jexpr->rarg;
- }
- }
-
- /*
- * When we fall out of the loop, we've reached the base Var.
- */
- return (Node *) makeVar(varno,
- varattno,
- vartype,
- vartypmod,
- 0);
-}
-
-/*
- * Given a join alias Var, construct Vars for the two input vars it directly
- * depends on. Note that this should *only* be called for merger alias Vars.
- * In practice it is only used for Vars that got past flatten_join_alias_vars.
- */
-void
-build_join_alias_subvars(Query *root, Var *aliasvar,
- Var **leftsubvar, Var **rightsubvar)
-{
- Index varno = aliasvar->varno;
- AttrNumber varattno = aliasvar->varattno;
- RangeTblEntry *rte;
- JoinExpr *jexpr;
- Index leftrti,
- rightrti;
- AttrNumber leftattno,
- rightattno;
- RangeTblEntry *subrte;
- Oid subtype;
- int32 subtypmod;
-
- Assert(aliasvar->varlevelsup == 0);
- rte = rt_fetch(varno, root->rtable);
- Assert(rte->rtekind == RTE_JOIN);
-
- /*
- * Find the RT indexes of the left and right children of the
- * join node.
- */
- jexpr = (JoinExpr *) find_jointree_item((Node *) root->jointree, varno);
- if (jexpr == NULL ||
- !IsA(jexpr, JoinExpr) ||
- jexpr->rtindex != varno)
- elog(ERROR, "build_join_alias_subvars: failed to find JoinExpr");
- if (IsA(jexpr->larg, RangeTblRef))
- leftrti = ((RangeTblRef *) jexpr->larg)->rtindex;
- else if (IsA(jexpr->larg, JoinExpr))
- leftrti = ((JoinExpr *) jexpr->larg)->rtindex;
- else
- {
- elog(ERROR, "build_join_alias_subvars: unexpected subtree type");
- leftrti = 0; /* keep compiler quiet */
- }
- if (IsA(jexpr->rarg, RangeTblRef))
- rightrti = ((RangeTblRef *) jexpr->rarg)->rtindex;
- else if (IsA(jexpr->rarg, JoinExpr))
- rightrti = ((JoinExpr *) jexpr->rarg)->rtindex;
- else
- {
- elog(ERROR, "build_join_alias_subvars: unexpected subtree type");
- rightrti = 0; /* keep compiler quiet */
- }
-
- Assert(varattno > 0);
- leftattno = (AttrNumber) nthi(varattno-1, rte->joinleftcols);
- rightattno = (AttrNumber) nthi(varattno-1, rte->joinrightcols);
- if (!(leftattno && rightattno))
- elog(ERROR, "build_join_alias_subvars: non-merger variable");
-
- subrte = rt_fetch(leftrti, root->rtable);
- get_rte_attribute_type(subrte, leftattno,
- &subtype, &subtypmod);
- *leftsubvar = makeVar(leftrti,
- leftattno,
- subtype,
- subtypmod,
- 0);
-
- subrte = rt_fetch(rightrti, root->rtable);
- get_rte_attribute_type(subrte, rightattno,
- &subtype, &subtypmod);
- *rightsubvar = makeVar(rightrti,
- rightattno,
- subtype,
- subtypmod,
- 0);
-}
-
-/*
- * Find jointree item matching the specified RT index
- */
-static Node *
-find_jointree_item(Node *jtnode, int rtindex)
-{
- if (jtnode == NULL)
- return NULL;
- if (IsA(jtnode, RangeTblRef))
- {
- if (((RangeTblRef *) jtnode)->rtindex == rtindex)
- return jtnode;
- }
- else if (IsA(jtnode, FromExpr))
- {
- FromExpr *f = (FromExpr *) jtnode;
- List *l;
-
- foreach(l, f->fromlist)
+ return node;
+ Assert(var->varattno > 0);
+ newvar = (Node *) nth(var->varattno - 1, rte->joinaliasvars);
+ if (IsA(newvar, Var) || context->force)
{
- jtnode = find_jointree_item(lfirst(l), rtindex);
- if (jtnode)
- return jtnode;
+ /* expand it; recurse in case join input is itself a join */
+ return flatten_join_alias_vars_mutator(newvar, context);
}
+ /* we don't want to force expansion of this alias Var */
+ return node;
}
- else if (IsA(jtnode, JoinExpr))
- {
- JoinExpr *j = (JoinExpr *) jtnode;
-
- if (j->rtindex == rtindex)
- return jtnode;
- jtnode = find_jointree_item(j->larg, rtindex);
- if (jtnode)
- return jtnode;
- jtnode = find_jointree_item(j->rarg, rtindex);
- if (jtnode)
- return jtnode;
- }
- else
- elog(ERROR, "find_jointree_item: unexpected node type %d",
- nodeTag(jtnode));
- return NULL;
+ return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
+ (void *) context);
}