var.c 9.93 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * var.c
4
 *	  Var node manipulation routines
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.40 2002/09/11 14:48:54 tgl Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
Marc G. Fournier's avatar
Marc G. Fournier committed
15 16
#include "postgres.h"

17
#include "nodes/plannodes.h"
18 19
#include "optimizer/clauses.h"
#include "optimizer/var.h"
20
#include "parser/parsetree.h"
21 22


23 24 25 26 27 28
typedef struct
{
	List	   *varlist;
	int			sublevels_up;
} pull_varnos_context;

29 30 31
typedef struct
{
	int			varno;
32
	int			varattno;
33
	int			sublevels_up;
34
} contain_var_reference_context;
35

36 37
typedef struct
{
38 39 40 41
	List	   *varlist;
	bool		includeUpperVars;
} pull_var_clause_context;

42 43
typedef struct
{
44
	List	   *rtable;
45
	bool		force;
46 47
} flatten_join_alias_vars_context;

48
static bool pull_varnos_walker(Node *node,
49
				   pull_varnos_context *context);
50
static bool contain_var_reference_walker(Node *node,
51
							 contain_var_reference_context *context);
52
static bool contain_var_clause_walker(Node *node, void *context);
53
static bool pull_var_clause_walker(Node *node,
54
					   pull_var_clause_context *context);
55
static Node *flatten_join_alias_vars_mutator(Node *node,
Bruce Momjian's avatar
Bruce Momjian committed
56
								flatten_join_alias_vars_context *context);
57 58


59
/*
60
 *		pull_varnos
61
 *
62 63 64
 *		Create a list of all the distinct varnos present in a parsetree.
 *		Only varnos that reference level-zero rtable entries are considered.
 *
65 66
 * NOTE: this is used on not-yet-planned expressions.  It may therefore find
 * bare SubLinks, and if so it needs to recurse into them to look for uplevel
67
 * references to the desired rtable level!	But when we find a completed
68
 * SubPlan, we only need to look at the parameters passed to the subplan.
69
 */
70
List *
71
pull_varnos(Node *node)
72
{
73 74 75 76 77 78 79 80 81 82 83 84
	pull_varnos_context context;

	context.varlist = NIL;
	context.sublevels_up = 0;

	/*
	 * Must be prepared to start with a Query or a bare expression tree;
	 * if it's a Query, go straight to query_tree_walker to make sure that
	 * sublevels_up doesn't get incremented prematurely.
	 */
	if (node && IsA(node, Query))
		query_tree_walker((Query *) node, pull_varnos_walker,
85
						  (void *) &context, 0);
86 87
	else
		pull_varnos_walker(node, &context);
88

89
	return context.varlist;
90
}
91

92
static bool
93
pull_varnos_walker(Node *node, pull_varnos_context *context)
94 95 96 97
{
	if (node == NULL)
		return false;
	if (IsA(node, Var))
98
	{
99 100
		Var		   *var = (Var *) node;

101 102 103
		if (var->varlevelsup == context->sublevels_up &&
			!intMember(var->varno, context->varlist))
			context->varlist = lconsi(var->varno, context->varlist);
104
		return false;
105
	}
106 107 108
	if (is_subplan(node))
	{
		/*
109 110 111
		 * Already-planned subquery.  Examine the args list (parameters to
		 * be passed to subquery), as well as the "oper" list which is
		 * executed by the outer query.  But short-circuit recursion into
112 113 114 115
		 * the subquery itself, which would be a waste of effort.
		 */
		Expr	   *expr = (Expr *) node;

116
		if (pull_varnos_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
117 118 119 120 121 122 123 124 125
							   context))
			return true;
		if (pull_varnos_walker((Node *) expr->args,
							   context))
			return true;
		return false;
	}
	if (IsA(node, Query))
	{
126
		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
127 128 129 130
		bool		result;

		context->sublevels_up++;
		result = query_tree_walker((Query *) node, pull_varnos_walker,
131
								   (void *) context, 0);
132 133 134 135 136
		context->sublevels_up--;
		return result;
	}
	return expression_tree_walker(node, pull_varnos_walker,
								  (void *) context);
137 138
}

139 140

/*
141
 *		contain_var_reference
142
 *
143 144
 *		Detect whether a parsetree contains any references to a specified
 *		attribute of a specified rtable entry.
145 146 147
 *
 * NOTE: this is used on not-yet-planned expressions.  It may therefore find
 * bare SubLinks, and if so it needs to recurse into them to look for uplevel
148
 * references to the desired rtable entry!	But when we find a completed
149 150 151
 * SubPlan, we only need to look at the parameters passed to the subplan.
 */
bool
152
contain_var_reference(Node *node, int varno, int varattno, int levelsup)
153
{
154
	contain_var_reference_context context;
155 156

	context.varno = varno;
157
	context.varattno = varattno;
158 159 160 161 162 163 164 165 166
	context.sublevels_up = levelsup;

	/*
	 * Must be prepared to start with a Query or a bare expression tree;
	 * if it's a Query, go straight to query_tree_walker to make sure that
	 * sublevels_up doesn't get incremented prematurely.
	 */
	if (node && IsA(node, Query))
		return query_tree_walker((Query *) node,
167
								 contain_var_reference_walker,
168
								 (void *) &context, 0);
169
	else
170
		return contain_var_reference_walker(node, &context);
171 172 173
}

static bool
174 175
contain_var_reference_walker(Node *node,
							 contain_var_reference_context *context)
176 177 178 179 180 181 182 183
{
	if (node == NULL)
		return false;
	if (IsA(node, Var))
	{
		Var		   *var = (Var *) node;

		if (var->varno == context->varno &&
184 185
			var->varattno == context->varattno &&
			var->varlevelsup == context->sublevels_up)
186 187 188 189 190 191 192 193 194 195 196 197 198
			return true;
		return false;
	}
	if (is_subplan(node))
	{
		/*
		 * Already-planned subquery.  Examine the args list (parameters to
		 * be passed to subquery), as well as the "oper" list which is
		 * executed by the outer query.  But short-circuit recursion into
		 * the subquery itself, which would be a waste of effort.
		 */
		Expr	   *expr = (Expr *) node;

199 200
		if (contain_var_reference_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper,
										 context))
201
			return true;
202 203
		if (contain_var_reference_walker((Node *) expr->args,
										 context))
204 205 206 207 208 209 210 211 212 213
			return true;
		return false;
	}
	if (IsA(node, Query))
	{
		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
		bool		result;

		context->sublevels_up++;
		result = query_tree_walker((Query *) node,
214
								   contain_var_reference_walker,
215
								   (void *) context, 0);
216 217 218
		context->sublevels_up--;
		return result;
	}
219
	return expression_tree_walker(node, contain_var_reference_walker,
220 221 222 223
								  (void *) context);
}


224 225 226 227 228 229 230 231 232 233 234 235 236
/*
 *		contain_whole_tuple_var
 *
 *		Detect whether a parsetree contains any references to the whole
 *		tuple of a given rtable entry (ie, a Var with varattno = 0).
 */
bool
contain_whole_tuple_var(Node *node, int varno, int levelsup)
{
	return contain_var_reference(node, varno, InvalidAttrNumber, levelsup);
}


237
/*
238
 * contain_var_clause
239 240
 *	  Recursively scan a clause to discover whether it contains any Var nodes
 *	  (of the current query level).
241 242
 *
 *	  Returns true if any varnode found.
243 244 245
 *
 * Does not examine subqueries, therefore must only be used after reduction
 * of sublinks to subplans!
246
 */
247
bool
248
contain_var_clause(Node *node)
249
{
250
	return contain_var_clause_walker(node, NULL);
251
}
252

253 254 255 256 257 258
static bool
contain_var_clause_walker(Node *node, void *context)
{
	if (node == NULL)
		return false;
	if (IsA(node, Var))
259 260
	{
		if (((Var *) node)->varlevelsup == 0)
261 262
			return true;		/* abort the tree traversal and return
								 * true */
263 264
		return false;
	}
265
	return expression_tree_walker(node, contain_var_clause_walker, context);
266 267
}

268

269
/*
270
 * pull_var_clause
271
 *	  Recursively pulls all var nodes from an expression clause.
272
 *
273
 *	  Upper-level vars (with varlevelsup > 0) are included only
274
 *	  if includeUpperVars is true.	Most callers probably want
275 276
 *	  to ignore upper-level vars.
 *
277 278
 *	  Returns list of varnodes found.  Note the varnodes themselves are not
 *	  copied, only referenced.
279 280 281
 *
 * Does not examine subqueries, therefore must only be used after reduction
 * of sublinks to subplans!
282
 */
283
List *
284
pull_var_clause(Node *node, bool includeUpperVars)
285
{
286
	pull_var_clause_context context;
287

288 289 290
	context.varlist = NIL;
	context.includeUpperVars = includeUpperVars;

291
	pull_var_clause_walker(node, &context);
292
	return context.varlist;
293
}
Bruce Momjian's avatar
Bruce Momjian committed
294

295
static bool
296
pull_var_clause_walker(Node *node, pull_var_clause_context *context)
297 298 299 300
{
	if (node == NULL)
		return false;
	if (IsA(node, Var))
301
	{
302 303
		if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars)
			context->varlist = lappend(context->varlist, node);
304
		return false;
305
	}
306
	return expression_tree_walker(node, pull_var_clause_walker,
307
								  (void *) context);
308
}
309 310 311 312


/*
 * flatten_join_alias_vars
313 314 315
 *	  Replace Vars that reference JOIN outputs with references to the original
 *	  relation variables instead.  This allows quals involving such vars to be
 *	  pushed down.
316
 *
317 318 319
 * 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
Bruce Momjian's avatar
Bruce Momjian committed
320
 * expression.	This is a hack to avoid confusing mergejoin planning, which
321 322 323 324 325
 * 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.
326 327 328 329 330
 *
 * Does not examine subqueries, therefore must only be used after reduction
 * of sublinks to subplans!
 */
Node *
331
flatten_join_alias_vars(Node *node, List *rtable, bool force)
332 333 334
{
	flatten_join_alias_vars_context context;

335
	context.rtable = rtable;
336
	context.force = force;
337 338 339 340 341 342 343 344 345 346 347 348

	return flatten_join_alias_vars_mutator(node, &context);
}

static Node *
flatten_join_alias_vars_mutator(Node *node,
								flatten_join_alias_vars_context *context)
{
	if (node == NULL)
		return NULL;
	if (IsA(node, Var))
	{
Bruce Momjian's avatar
Bruce Momjian committed
349
		Var		   *var = (Var *) node;
350
		RangeTblEntry *rte;
Bruce Momjian's avatar
Bruce Momjian committed
351
		Node	   *newvar;
352 353 354

		if (var->varlevelsup != 0)
			return node;		/* no need to copy, really */
355
		rte = rt_fetch(var->varno, context->rtable);
356
		if (rte->rtekind != RTE_JOIN)
357 358 359
			return node;
		Assert(var->varattno > 0);
		newvar = (Node *) nth(var->varattno - 1, rte->joinaliasvars);
Bruce Momjian's avatar
Bruce Momjian committed
360
		if (IsA(newvar, Var) ||context->force)
361
		{
362 363
			/* expand it; recurse in case join input is itself a join */
			return flatten_join_alias_vars_mutator(newvar, context);
364
		}
365 366
		/* we don't want to force expansion of this alias Var */
		return node;
367
	}
368 369
	return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
								   (void *) context);
370
}