subselect.c 15.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * subselect.c
4 5 6 7 8 9
 *	  Planning routines for subselects and parameters.
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.18 1999/06/21 01:20:57 tgl Exp $
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "catalog/pg_type.h"
#include "nodes/pg_list.h"
#include "nodes/plannodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/subselect.h"
#include "optimizer/planner.h"
#include "optimizer/planmain.h"
#include "optimizer/internal.h"
#include "optimizer/paths.h"
#include "optimizer/clauses.h"
#include "optimizer/keys.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "optimizer/cost.h"

33 34
int			PlannerQueryLevel;	/* level of current query */
List	   *PlannerInitPlan;	/* init subplans for current query */
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
List	   *PlannerParamVar;	/* to get Var from Param->paramid */
int			PlannerPlanId;		/* to assign unique ID to subquery plans */

/*--------------------
 * PlannerParamVar is a list of Var nodes, wherein the n'th entry
 * (n counts from 0) corresponds to Param->paramid = n.  The Var nodes
 * are ordinary except for one thing: their varlevelsup field does NOT
 * have the usual interpretation of "subplan levels out from current".
 * Instead, it contains the absolute plan level, with the outermost
 * plan being level 1 and nested plans having higher level numbers.
 * This nonstandardness is useful because we don't have to run around
 * and update the list elements when we enter or exit a subplan
 * recursion level.  But we must pay attention not to confuse this
 * meaning with the normal meaning of varlevelsup.
 *--------------------
 */
51 52


53 54 55 56 57 58
/*
 * Create a new entry in the PlannerParamVar list, and return its index.
 *
 * var contains the data to be copied, except for varlevelsup which
 * is set from the absolute level value given by varlevel.
 */
59
static int
60
_new_param(Var *var, int varlevel)
61
{
62 63 64 65
	List	   *last;
	int			i = 0;

	if (PlannerParamVar == NULL)
66 67 68
		last = PlannerParamVar = makeNode(List);
	else
	{
69
		for (last = PlannerParamVar;;)
70 71
		{
			i++;
72
			if (lnext(last) == NULL)
73 74 75 76 77 78
				break;
			last = lnext(last);
		}
		lnext(last) = makeNode(List);
		last = lnext(last);
	}
79

80
	lnext(last) = NULL;
81 82 83
	lfirst(last) = makeVar(var->varno, var->varattno, var->vartype,
				var->vartypmod, varlevel, var->varnoold, var->varoattno);

84
	return i;
85 86
}

87 88 89 90
/*
 * Generate a Param node to replace the given Var,
 * which is expected to have varlevelsup > 0 (ie, it is not local).
 */
91 92
static Param *
_replace_var(Var *var)
93
{
94
	List	   *ppv;
95
	Param	   *retval;
96
	int			varlevel;
97 98
	int			i;

99 100
	Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);
	varlevel = PlannerQueryLevel - var->varlevelsup;
101

102 103 104 105 106 107 108 109 110 111 112 113
	/*
	 * If there's already a PlannerParamVar entry for this same Var,
	 * just use it.  NOTE: in situations involving UNION or inheritance,
	 * it is possible for the same varno/varlevel to refer to different RTEs
	 * in different parts of the parsetree, so that different fields might
	 * end up sharing the same Param number.  As long as we check the vartype
	 * as well, I believe that this sort of aliasing will cause no trouble.
	 * The correct field should get stored into the Param slot at execution
	 * in each part of the tree.
	 */
	i = 0;
	foreach(ppv, PlannerParamVar)
114
	{
115 116 117 118 119 120
		Var	   *pvar = lfirst(ppv);

		if (pvar->varno == var->varno &&
			pvar->varattno == var->varattno &&
			pvar->varlevelsup == varlevel &&
			pvar->vartype == var->vartype)
121
			break;
122
		i++;
123
	}
124

125 126 127 128 129
	if (! ppv)
	{
		/* Nope, so make a new one */
		i = _new_param(var, varlevel);
	}
130

131 132 133 134
	retval = makeNode(Param);
	retval->paramkind = PARAM_EXEC;
	retval->paramid = (AttrNumber) i;
	retval->paramtype = var->vartype;
135

136
	return retval;
137 138
}

139 140
static Node *
_make_subplan(SubLink *slink)
141
{
142
	SubPlan    *node = makeNode(SubPlan);
143 144 145 146
	Plan	   *plan;
	List	   *lst;
	Node	   *result;
	List	   *saved_ip = PlannerInitPlan;
147

148
	PlannerInitPlan = NULL;
149

150
	PlannerQueryLevel++;		/* we becomes child */
151 152 153 154 155 156 157

	node->plan = plan = union_planner((Query *) slink->subselect);

	/*
	 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
	 * SS_finalize_plan doesn't handle initPlan-s and so we assigne them
	 * to the topmost plan node and take care about its extParam too.
158
	 */
159
	(void) SS_finalize_plan(plan);
160
	plan->initPlan = PlannerInitPlan;
161

162
	/* Create extParam list as union of InitPlan-s' lists */
163
	foreach(lst, PlannerInitPlan)
164
	{
165 166 167
		List	   *lp;

		foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)
168
		{
169 170
			if (!intMember(lfirsti(lp), plan->extParam))
				plan->extParam = lappendi(plan->extParam, lfirsti(lp));
171 172
		}
	}
173

174 175 176
	/* and now we are parent again */
	PlannerInitPlan = saved_ip;
	PlannerQueryLevel--;
177

178
	node->plan_id = PlannerPlanId++;
179
	node->rtable = ((Query *) slink->subselect)->rtable;
180 181
	node->sublink = slink;
	slink->subselect = NULL;	/* cool ?! */
182

183
	/* make parParam list of params coming from current query level */
184
	foreach(lst, plan->extParam)
185
	{
186 187
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

188
		/* note varlevelsup is absolute level number */
189 190
		if (var->varlevelsup == PlannerQueryLevel)
			node->parParam = lappendi(node->parParam, lfirsti(lst));
191
	}
192 193 194 195

	/*
	 * Un-correlated or undirect correlated plans of EXISTS or EXPR types
	 * can be used as initPlans...
196
	 */
197
	if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
198
	{
199 200
		int			i = 0;

201
		/* transform right side of all sublink Oper-s into Param */
202
		foreach(lst, slink->oper)
203
		{
204 205 206 207
			List	   *rside = lnext(((Expr *) lfirst(lst))->args);
			TargetEntry *te = nth(i, plan->targetlist);
			Var		   *var = makeVar(0, 0, te->resdom->restype,
									  te->resdom->restypmod,
208
									  0, 0, 0);
209 210
			Param	   *prm = makeNode(Param);

211
			prm->paramkind = PARAM_EXEC;
212
			prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
213 214
			prm->paramtype = var->vartype;
			lfirst(rside) = prm;
215 216
			node->setParam = lappendi(node->setParam, prm->paramid);
			pfree(var);
217 218
			i++;
		}
219 220 221 222
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		if (i > 1)
			result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
							   make_andclause(slink->oper));
223
		else
224
			result = (Node *) lfirst(slink->oper);
225
	}
226
	else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
227
	{
228
		Var		   *var = makeVar(0, 0, BOOLOID, -1, 0, 0, 0);
229
		Param	   *prm = makeNode(Param);
230

231
		prm->paramkind = PARAM_EXEC;
232
		prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
233
		prm->paramtype = var->vartype;
234 235 236 237
		node->setParam = lappendi(node->setParam, prm->paramid);
		pfree(var);
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		result = (Node *) prm;
238
	}
239
	else
240
	{
241
		/* make expression of SUBPLAN type */
242
		Expr	   *expr = makeNode(Expr);
243
		List	   *args = NIL;
244 245
		int			i = 0;

246 247
		expr->typeOid = BOOLOID;
		expr->opType = SUBPLAN_EXPR;
248 249 250 251 252 253
		expr->oper = (Node *) node;

		/*
		 * Make expr->args from parParam. Left sides of sublink Oper-s are
		 * handled by optimizer directly... Also, transform right side of
		 * sublink Oper-s into Const.
254
		 */
255
		foreach(lst, node->parParam)
256
		{
257 258 259
			Var		   *var = nth(lfirsti(lst), PlannerParamVar);

			var = (Var *) copyObject(var);
260 261 262 263
			/* Must fix absolute-level varlevelsup from the
			 * PlannerParamVar entry.  But since var is at current
			 * subplan level, this is easy:
			 */
264
			var->varlevelsup = 0;
265
			args = lappend(args, var);
266
		}
267
		foreach(lst, slink->oper)
268
		{
269 270 271 272 273
			List	   *rside = lnext(((Expr *) lfirst(lst))->args);
			TargetEntry *te = nth(i, plan->targetlist);
			Const	   *con = makeConst(te->resdom->restype,
										0, 0, true, 0, 0, 0);

274 275 276 277
			lfirst(rside) = con;
			i++;
		}
		expr->args = args;
278
		result = (Node *) expr;
279
	}
280

281
	return result;
282 283 284
}

static List *
285
set_unioni(List *l1, List *l2)
286 287
{
	if (l1 == NULL)
288
		return l2;
289
	if (l2 == NULL)
290
		return l1;
291

292
	return nconc(l1, set_differencei(l2, l1));
293 294 295
}

static List *
296
_finalize_primnode(void *expr, List **subplan)
297
{
298 299 300
	List	   *result = NULL;

	if (expr == NULL)
301
		return NULL;
302 303

	if (IsA(expr, Param))
304
	{
305
		if (((Param *) expr)->paramkind == PARAM_EXEC)
306
			return lconsi(((Param *) expr)->paramid, (List *) NULL);
307 308
	}
	else if (single_node(expr))
309
		return NULL;
310
	else if (IsA(expr, List))
311
	{
312 313 314 315 316
		List	   *le;

		foreach(le, (List *) expr)
			result = set_unioni(result,
								_finalize_primnode(lfirst(le), subplan));
317
	}
318
	else if (IsA(expr, Iter))
319
		return _finalize_primnode(((Iter *) expr)->iterexpr, subplan);
320 321
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
322
		return _finalize_primnode(((Expr *) expr)->args, subplan);
B
Bruce Momjian 已提交
323 324
	else if (IsA(expr, Aggref))
		return _finalize_primnode(((Aggref *) expr)->target, subplan);
325
	else if (IsA(expr, ArrayRef))
326
	{
327 328 329 330 331 332 333
		result = _finalize_primnode(((ArrayRef *) expr)->refupperindexpr, subplan);
		result = set_unioni(result,
							_finalize_primnode(((ArrayRef *) expr)->reflowerindexpr, subplan));
		result = set_unioni(result,
			  _finalize_primnode(((ArrayRef *) expr)->refexpr, subplan));
		result = set_unioni(result,
		 _finalize_primnode(((ArrayRef *) expr)->refassgnexpr, subplan));
334
	}
335
	else if (IsA(expr, TargetEntry))
336
		return _finalize_primnode(((TargetEntry *) expr)->expr, subplan);
337
	else if (is_subplan(expr))
338
	{
339 340 341 342
		List	   *lst;

		*subplan = lappend(*subplan, ((Expr *) expr)->oper);
		foreach(lst, ((SubPlan *) ((Expr *) expr)->oper)->plan->extParam)
343
		{
344 345
			Var		   *var = nth(lfirsti(lst), PlannerParamVar);

346
			/* note varlevelsup is absolute level number */
347 348 349
			if (var->varlevelsup < PlannerQueryLevel &&
				!intMember(lfirsti(lst), result))
				result = lappendi(result, lfirsti(lst));
350 351 352
		}
	}
	else
353
		elog(ERROR, "_finalize_primnode: can't handle node %d", nodeTag(expr));
354

355
	return result;
356 357 358
}

Node *
359
SS_replace_correlation_vars(Node *expr)
360 361
{

362
	if (expr == NULL)
363
		return NULL;
364
	if (IsA(expr, List))
365
	{
366 367 368 369
		List	   *le;

		foreach(le, (List *) expr)
			lfirst(le) = SS_replace_correlation_vars((Node *) lfirst(le));
370
	}
371
	else if (IsA(expr, Var))
372
	{
373 374
		if (((Var *) expr)->varlevelsup > 0)
			expr = (Node *) _replace_var((Var *) expr);
375
	}
376
	else if (IsA(expr, Iter))
377
		((Iter *) expr)->iterexpr = SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
378
	else if (single_node(expr))
379
		return expr;
380 381 382 383
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
		((Expr *) expr)->args = (List *)
			SS_replace_correlation_vars((Node *) ((Expr *) expr)->args);
B
Bruce Momjian 已提交
384
	else if (IsA(expr, Aggref))
385
		((Aggref *) expr)->target = SS_replace_correlation_vars((Node *) ((Aggref *) expr)->target);
386
	else if (IsA(expr, ArrayRef))
387
	{
388 389 390 391
		((ArrayRef *) expr)->refupperindexpr = (List *)
			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refupperindexpr);
		((ArrayRef *) expr)->reflowerindexpr = (List *)
			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->reflowerindexpr);
392 393
		((ArrayRef *) expr)->refexpr = SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refexpr);
		((ArrayRef *) expr)->refassgnexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refassgnexpr);
394
	}
395
	else if (IsA(expr, TargetEntry))
396
		((TargetEntry *) expr)->expr = SS_replace_correlation_vars((Node *) ((TargetEntry *) expr)->expr);
397
	else if (IsA(expr, SubLink))
398
	{
399 400 401
		List	   *le;

		foreach(le, ((SubLink *) expr)->oper)	/* left sides only */
402
		{
403 404 405 406
			List	   *oparg = ((Expr *) lfirst(le))->args;

			lfirst(oparg) = (List *)
				SS_replace_correlation_vars((Node *) lfirst(oparg));
407
		}
408 409
		((SubLink *) expr)->lefthand = (List *)
			SS_replace_correlation_vars((Node *) ((SubLink *) expr)->lefthand);
410 411
	}
	else
412 413 414
		elog(NOTICE, "SS_replace_correlation_vars: can't handle node %d",
			 nodeTag(expr));

415
	return expr;
416 417
}

418 419
Node *
SS_process_sublinks(Node *expr)
420
{
421
	if (expr == NULL)
422
		return NULL;
423
	if (IsA(expr, List))
424
	{
425 426 427 428
		List	   *le;

		foreach(le, (List *) expr)
			lfirst(le) = SS_process_sublinks((Node *) lfirst(le));
429
	}
430 431 432 433 434
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
		((Expr *) expr)->args = (List *)
			SS_process_sublinks((Node *) ((Expr *) expr)->args);
	else if (IsA(expr, SubLink))/* got it! */
435 436
		expr = _make_subplan((SubLink *) expr);

437
	return expr;
438 439
}

440 441
List *
SS_finalize_plan(Plan *plan)
442
{
443 444 445 446 447 448 449
	List	   *extParam = NULL;
	List	   *locParam = NULL;
	List	   *subPlan = NULL;
	List	   *param_list;
	List	   *lst;

	if (plan == NULL)
450
		return NULL;
451 452 453 454

	param_list = _finalize_primnode(plan->targetlist, &subPlan);
	Assert(subPlan == NULL);

455 456 457
	switch (nodeTag(plan))
	{
		case T_Result:
458 459
			param_list = set_unioni(param_list,
									_finalize_primnode(((Result *) plan)->resconstantqual, &subPlan));
460
			/* subPlan is NOT necessarily NULL here ... */
461 462 463
			break;

		case T_Append:
464
			foreach(lst, ((Append *) plan)->appendplans)
465 466
				param_list = set_unioni(param_list,
								 SS_finalize_plan((Plan *) lfirst(lst)));
467
			break;
468

469
		case T_IndexScan:
470 471 472
			param_list = set_unioni(param_list,
			_finalize_primnode(((IndexScan *) plan)->indxqual, &subPlan));
			Assert(subPlan == NULL);
473 474 475
			break;

		case T_MergeJoin:
476 477 478
			param_list = set_unioni(param_list,
									_finalize_primnode(((MergeJoin *) plan)->mergeclauses, &subPlan));
			Assert(subPlan == NULL);
479 480 481
			break;

		case T_HashJoin:
482 483 484
			param_list = set_unioni(param_list,
									_finalize_primnode(((HashJoin *) plan)->hashclauses, &subPlan));
			Assert(subPlan == NULL);
485
			break;
486

487
		case T_Hash:
488 489 490
			param_list = set_unioni(param_list,
				 _finalize_primnode(((Hash *) plan)->hashkey, &subPlan));
			Assert(subPlan == NULL);
491 492 493
			break;

		case T_Agg:
494 495 496
			param_list = set_unioni(param_list,
					 _finalize_primnode(((Agg *) plan)->aggs, &subPlan));
			Assert(subPlan == NULL);
497
			break;
498

499 500 501 502 503 504 505 506 507
		case T_SeqScan:
		case T_NestLoop:
		case T_Material:
		case T_Sort:
		case T_Unique:
		case T_Group:
			break;
		default:
			elog(ERROR, "SS_finalize_plan: node %d unsupported", nodeTag(plan));
508
			return NULL;
509
	}
510 511 512 513 514 515

	param_list = set_unioni(param_list, _finalize_primnode(plan->qual, &subPlan));
	param_list = set_unioni(param_list, SS_finalize_plan(plan->lefttree));
	param_list = set_unioni(param_list, SS_finalize_plan(plan->righttree));

	foreach(lst, param_list)
516
	{
517 518
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

519
		/* note varlevelsup is absolute level number */
520 521 522 523
		if (var->varlevelsup < PlannerQueryLevel)
			extParam = lappendi(extParam, lfirsti(lst));
		else if (var->varlevelsup > PlannerQueryLevel)
			elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan' variable");
524 525
		else
		{
526 527
			Assert(var->varno == 0 && var->varattno == 0);
			locParam = lappendi(locParam, lfirsti(lst));
528 529
		}
	}
530

531 532 533
	plan->extParam = extParam;
	plan->locParam = locParam;
	plan->subPlan = subPlan;
534

535
	return param_list;
536 537 538

}

539
/* Construct a list of all subplans found within the given node tree */
540 541

List *
542
SS_pull_subplan(Node *expr)
543
{
544 545 546
	List	   *result = NULL;

	if (expr == NULL || single_node(expr))
547
		return NULL;
548 549

	if (IsA(expr, List))
550
	{
551 552 553 554
		List	   *le;

		foreach(le, (List *) expr)
			result = nconc(result, SS_pull_subplan(lfirst(le)));
555
	}
556
	else if (IsA(expr, Iter))
557
		return SS_pull_subplan(((Iter *) expr)->iterexpr);
558 559
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
560
		return SS_pull_subplan((Node *) ((Expr *) expr)->args);
B
Bruce Momjian 已提交
561 562
	else if (IsA(expr, Aggref))
		return SS_pull_subplan(((Aggref *) expr)->target);
563
	else if (IsA(expr, ArrayRef))
564
	{
B
Bruce Momjian 已提交
565
		result = SS_pull_subplan((Node *) ((ArrayRef *) expr)->refupperindexpr);
566
		result = nconc(result,
B
Bruce Momjian 已提交
567
		 SS_pull_subplan((Node *) ((ArrayRef *) expr)->reflowerindexpr));
568 569 570
		result = nconc(result,
					   SS_pull_subplan(((ArrayRef *) expr)->refexpr));
		result = nconc(result,
B
Bruce Momjian 已提交
571
					 SS_pull_subplan(((ArrayRef *) expr)->refassgnexpr));
572
	}
573
	else if (IsA(expr, TargetEntry))
574
		return SS_pull_subplan(((TargetEntry *) expr)->expr);
575
	else if (is_subplan(expr))
576
		return lcons(((Expr *) expr)->oper, NULL);
577
	else
578
		elog(ERROR, "SS_pull_subplan: can't handle node %d", nodeTag(expr));
579

580
	return result;
581
}