subselect.c 16.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * subselect.c
4 5 6 7 8
 *	  Planning routines for subselects and parameters.
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
9
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.24 1999/08/25 23:21:39 tgl Exp $
10 11 12 13 14
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

15
#include "catalog/pg_operator.h"
16 17 18 19
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
B
Bruce Momjian 已提交
20 21
#include "optimizer/planner.h"
#include "optimizer/subselect.h"
22 23 24 25 26
#include "parser/parse_expr.h"
#include "parser/parse_node.h"
#include "parser/parse_oper.h"
#include "utils/lsyscache.h"

27

28 29
int			PlannerQueryLevel;	/* level of current query */
List	   *PlannerInitPlan;	/* init subplans for current query */
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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.
 *--------------------
 */
46 47


48 49 50 51 52 53
/*
 * 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.
 */
54
static int
55
new_param(Var *var, int varlevel)
56
{
57
	Var		   *paramVar = (Var *) copyObject(var);
58

59
	paramVar->varlevelsup = varlevel;
60

61
	PlannerParamVar = lappend(PlannerParamVar, paramVar);
62

63
	return length(PlannerParamVar) - 1;
64 65
}

66 67 68 69
/*
 * Generate a Param node to replace the given Var,
 * which is expected to have varlevelsup > 0 (ie, it is not local).
 */
70
static Param *
71
replace_var(Var *var)
72
{
73
	List	   *ppv;
74
	Param	   *retval;
75
	int			varlevel;
76 77
	int			i;

78 79
	Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);
	varlevel = PlannerQueryLevel - var->varlevelsup;
80

81 82 83 84 85 86 87 88 89 90 91 92
	/*
	 * 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)
93
	{
94 95 96 97 98 99
		Var	   *pvar = lfirst(ppv);

		if (pvar->varno == var->varno &&
			pvar->varattno == var->varattno &&
			pvar->varlevelsup == varlevel &&
			pvar->vartype == var->vartype)
100
			break;
101
		i++;
102
	}
103

104 105 106
	if (! ppv)
	{
		/* Nope, so make a new one */
107
		i = new_param(var, varlevel);
108
	}
109

110 111 112 113
	retval = makeNode(Param);
	retval->paramkind = PARAM_EXEC;
	retval->paramid = (AttrNumber) i;
	retval->paramtype = var->vartype;
114

115
	return retval;
116 117
}

118 119 120
/*
 * Convert a bare SubLink (as created by the parser) into a SubPlan.
 */
121
static Node *
122
make_subplan(SubLink *slink)
123
{
124
	SubPlan    *node = makeNode(SubPlan);
125 126 127 128
	Plan	   *plan;
	List	   *lst;
	Node	   *result;
	List	   *saved_ip = PlannerInitPlan;
129

130
	PlannerInitPlan = NULL;
131

132
	PlannerQueryLevel++;		/* we becomes child */
133 134 135 136 137

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

	/*
	 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
138
	 * SS_finalize_plan doesn't handle initPlan-s and so we assign them
139
	 * to the topmost plan node and take care about its extParam too.
140
	 */
141
	(void) SS_finalize_plan(plan);
142
	plan->initPlan = PlannerInitPlan;
143

144
	/* Create extParam list as union of InitPlan-s' lists */
145
	foreach(lst, PlannerInitPlan)
146
	{
147 148 149
		List	   *lp;

		foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)
150
		{
151 152
			if (!intMember(lfirsti(lp), plan->extParam))
				plan->extParam = lappendi(plan->extParam, lfirsti(lp));
153 154
		}
	}
155

156 157 158
	/* and now we are parent again */
	PlannerInitPlan = saved_ip;
	PlannerQueryLevel--;
159

160
	node->plan_id = PlannerPlanId++;
161
	node->rtable = ((Query *) slink->subselect)->rtable;
162 163
	node->sublink = slink;
	slink->subselect = NULL;	/* cool ?! */
164

165
	/* make parParam list of params coming from current query level */
166
	foreach(lst, plan->extParam)
167
	{
168 169
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

170
		/* note varlevelsup is absolute level number */
171 172
		if (var->varlevelsup == PlannerQueryLevel)
			node->parParam = lappendi(node->parParam, lfirsti(lst));
173
	}
174 175 176 177

	/*
	 * Un-correlated or undirect correlated plans of EXISTS or EXPR types
	 * can be used as initPlans...
178
	 */
179
	if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
180
	{
181
		List	   *newoper = NIL;
182 183
		int			i = 0;

184 185 186 187
		/*
		 * Convert oper list of Opers into a list of Exprs, using
		 * lefthand arguments and Params representing inside results.
		 */
188
		foreach(lst, slink->oper)
189
		{
190 191
			Oper	   *oper = (Oper *) lfirst(lst);
			Node	   *lefthand = nth(i, slink->lefthand);
192
			TargetEntry *te = nth(i, plan->targetlist);
193
			/* need a var node just to pass to new_param()... */
194
			Var		   *var = makeVar(0, 0, te->resdom->restype,
195
									  te->resdom->restypmod, 0);
196
			Param	   *prm = makeNode(Param);
197 198 199 200
			Operator	tup;
			Form_pg_operator opform;
			Node	   *left,
					   *right;
201

202
			prm->paramkind = PARAM_EXEC;
203
			prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
204
			prm->paramtype = var->vartype;
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

			Assert(IsA(oper, Oper));
			tup = get_operator_tuple(oper->opno);
			Assert(HeapTupleIsValid(tup));
			opform = (Form_pg_operator) GETSTRUCT(tup);
			/* Note: we use make_operand in case runtime type conversion
			 * function calls must be inserted for this operator!
			 */
			left = make_operand("", lefthand,
								exprType(lefthand), opform->oprleft);
			right = make_operand("", (Node *) prm,
								 prm->paramtype, opform->oprright);
			newoper = lappend(newoper,
							  make_opclause(oper,
											(Var *) left,
											(Var *) right));
221 222
			node->setParam = lappendi(node->setParam, prm->paramid);
			pfree(var);
223 224
			i++;
		}
225 226
		slink->oper = newoper;
		slink->lefthand = NIL;
227 228
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		if (i > 1)
229 230
			result = (Node *) ((slink->useor) ? make_orclause(newoper) :
							   make_andclause(newoper));
231
		else
232
			result = (Node *) lfirst(newoper);
233
	}
234
	else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
235
	{
236
		Var		   *var = makeVar(0, 0, BOOLOID, -1, 0);
237
		Param	   *prm = makeNode(Param);
238

239
		prm->paramkind = PARAM_EXEC;
240
		prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
241
		prm->paramtype = var->vartype;
242 243 244 245
		node->setParam = lappendi(node->setParam, prm->paramid);
		pfree(var);
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		result = (Node *) prm;
246
	}
247
	else
248
	{
249
		/* make expression of SUBPLAN type */
250
		Expr	   *expr = makeNode(Expr);
251
		List	   *args = NIL;
252
		List	   *newoper = NIL;
253 254
		int			i = 0;

255
		expr->typeOid = BOOLOID; /* bogus, but we don't really care */
256
		expr->opType = SUBPLAN_EXPR;
257 258 259
		expr->oper = (Node *) node;

		/*
260
		 * Make expr->args from parParam.
261
		 */
262
		foreach(lst, node->parParam)
263
		{
264 265 266
			Var		   *var = nth(lfirsti(lst), PlannerParamVar);

			var = (Var *) copyObject(var);
267 268 269 270
			/* Must fix absolute-level varlevelsup from the
			 * PlannerParamVar entry.  But since var is at current
			 * subplan level, this is easy:
			 */
271
			var->varlevelsup = 0;
272
			args = lappend(args, var);
273
		}
274 275 276 277 278
		expr->args = args;
		/*
		 * Convert oper list of Opers into a list of Exprs, using
		 * lefthand arguments and Consts representing inside results.
		 */
279
		foreach(lst, slink->oper)
280
		{
281 282
			Oper	   *oper = (Oper *) lfirst(lst);
			Node	   *lefthand = nth(i, slink->lefthand);
283
			TargetEntry *te = nth(i, plan->targetlist);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
			Const	   *con;
			Operator	tup;
			Form_pg_operator opform;
			Node	   *left,
					   *right;

			/*
			 * XXX really ought to fill in constlen and constbyval correctly,
			 * but right now ExecEvalExpr won't look at them...
			 */
			con = makeConst(te->resdom->restype, 0, 0, true, 0, 0, 0);

			Assert(IsA(oper, Oper));
			tup = get_operator_tuple(oper->opno);
			Assert(HeapTupleIsValid(tup));
			opform = (Form_pg_operator) GETSTRUCT(tup);
			/* Note: we use make_operand in case runtime type conversion
			 * function calls must be inserted for this operator!
			 */
			left = make_operand("", lefthand,
								exprType(lefthand), opform->oprleft);
			right = make_operand("", (Node *) con,
								 con->consttype, opform->oprright);
			newoper = lappend(newoper,
							  make_opclause(oper,
											(Var *) left,
											(Var *) right));
311 312
			i++;
		}
313 314
		slink->oper = newoper;
		slink->lefthand = NIL;
315
		result = (Node *) expr;
316
	}
317

318
	return result;
319 320
}

321 322
/* this oughta be merged with LispUnioni */

323
static List *
324
set_unioni(List *l1, List *l2)
325 326
{
	if (l1 == NULL)
327
		return l2;
328
	if (l2 == NULL)
329
		return l1;
330

331
	return nconc(l1, set_differencei(l2, l1));
332 333
}

334 335 336 337 338
/*
 * finalize_primnode: build lists of subplans and params appearing
 * in the given expression tree.
 */

339 340 341 342
typedef struct finalize_primnode_results {
	List	*subplans;			/* List of subplans found in expr */
	List	*paramids;			/* List of PARAM_EXEC paramids found */
} finalize_primnode_results;
343

344 345
static bool finalize_primnode_walker(Node *node,
									 finalize_primnode_results *results);
346

347 348 349 350 351 352 353
static void
finalize_primnode(Node *expr, finalize_primnode_results *results)
{
	results->subplans = NIL;	/* initialize */
	results->paramids = NIL;
	(void) finalize_primnode_walker(expr, results);
}
354

355 356 357 358 359 360 361
static bool
finalize_primnode_walker(Node *node,
						 finalize_primnode_results *results)
{
	if (node == NULL)
		return false;
	if (IsA(node, Param))
362
	{
363 364 365 366 367 368 369 370
		if (((Param *) node)->paramkind == PARAM_EXEC)
		{
			int		paramid = (int) ((Param *) node)->paramid;

			if (! intMember(paramid, results->paramids))
				results->paramids = lconsi(paramid, results->paramids);
		}
		return false;			/* no more to do here */
371
	}
372
	if (is_subplan(node))
373
	{
374
		SubPlan	   *subplan = (SubPlan *) ((Expr *) node)->oper;
375 376
		List	   *lst;

377 378 379 380
		/* Add subplan to subplans list */
		results->subplans = lappend(results->subplans, subplan);
		/* Check extParam list for params to add to paramids */
		foreach(lst, subplan->plan->extParam)
381
		{
382 383
			int			paramid = lfirsti(lst);
			Var		   *var = nth(paramid, PlannerParamVar);
384

385
			/* note varlevelsup is absolute level number */
386
			if (var->varlevelsup < PlannerQueryLevel &&
387 388
				! intMember(paramid, results->paramids))
				results->paramids = lconsi(paramid, results->paramids);
389
		}
390
		/* fall through to recurse into subplan args */
391
	}
392 393
	return expression_tree_walker(node, finalize_primnode_walker,
								  (void *) results);
394 395
}

396 397
/*
 * Replace correlation vars (uplevel vars) with Params.
398
 */
399 400 401

static Node *replace_correlation_vars_mutator(Node *node, void *context);

402
Node *
403
SS_replace_correlation_vars(Node *expr)
404
{
405 406 407
	/* No setup needed for tree walk, so away we go */
	return replace_correlation_vars_mutator(expr, NULL);
}
408

409 410 411 412 413 414
static Node *
replace_correlation_vars_mutator(Node *node, void *context)
{
	if (node == NULL)
		return NULL;
	if (IsA(node, Var))
415
	{
416 417
		if (((Var *) node)->varlevelsup > 0)
			return (Node *) replace_var((Var *) node);
418
	}
419 420 421
	return expression_tree_mutator(node,
								   replace_correlation_vars_mutator,
								   context);
422 423
}

424 425
/*
 * Expand SubLinks to SubPlans in the given expression.
426
 */
427 428 429

static Node *process_sublinks_mutator(Node *node, void *context);

430 431
Node *
SS_process_sublinks(Node *expr)
432
{
433 434 435 436 437 438 439 440
	/* No setup needed for tree walk, so away we go */
    return process_sublinks_mutator(expr, NULL);
}

static Node *
process_sublinks_mutator(Node *node, void *context)
{
	if (node == NULL)
441
		return NULL;
442
	if (IsA(node, SubLink))
443
	{
444
		SubLink	   *sublink = (SubLink *) node;
445

446 447 448
		/* First, scan the lefthand-side expressions.
		 * This is a tad klugy since we modify the input SubLink node,
		 * but that should be OK (make_subplan does it too!)
449
		 */
450 451 452 453
		sublink->lefthand = (List *)
			process_sublinks_mutator((Node *) sublink->lefthand, context);
		/* Now build the SubPlan node and make the expr to return */
		return make_subplan(sublink);
454
	}
455 456 457 458 459 460 461 462
	/*
	 * Note that we will never see a SubPlan expression in the input
	 * (since this is the very routine that creates 'em to begin with).
	 * So the code in expression_tree_mutator() that might do
	 * inappropriate things with SubPlans or SubLinks will not be
	 * exercised.
	 */
	Assert(! is_subplan(node));
463

464 465 466
	return expression_tree_mutator(node,
								   process_sublinks_mutator,
								   context);
467 468
}

469 470
List *
SS_finalize_plan(Plan *plan)
471
{
472 473 474
	List	   *extParam = NIL;
	List	   *locParam = NIL;
	finalize_primnode_results results;
475 476 477
	List	   *lst;

	if (plan == NULL)
478
		return NULL;
479

480 481 482
	/* Find params in targetlist, make sure there are no subplans there */
	finalize_primnode((Node *) plan->targetlist, &results);
	Assert(results.subplans == NIL);
483

484 485 486 487 488
	/* From here on, we invoke finalize_primnode_walker not finalize_primnode,
	 * so that results.paramids lists are automatically merged together and
	 * we don't have to do it the hard way.  But when recursing to self,
	 * we do have to merge the lists.  Oh well.
	 */
489 490 491
	switch (nodeTag(plan))
	{
		case T_Result:
492 493 494
			finalize_primnode_walker(((Result *) plan)->resconstantqual,
									 &results);
			/* results.subplans is NOT necessarily empty here ... */
495 496 497
			break;

		case T_Append:
498
			foreach(lst, ((Append *) plan)->appendplans)
499 500
				results.paramids = set_unioni(results.paramids,
								SS_finalize_plan((Plan *) lfirst(lst)));
501
			break;
502

503
		case T_IndexScan:
504 505 506
			finalize_primnode_walker((Node *) ((IndexScan *) plan)->indxqual,
									 &results);
			Assert(results.subplans == NIL);
507 508 509
			break;

		case T_MergeJoin:
510 511 512
			finalize_primnode_walker((Node *) ((MergeJoin *) plan)->mergeclauses,
									 &results);
			Assert(results.subplans == NIL);
513 514 515
			break;

		case T_HashJoin:
516 517 518
			finalize_primnode_walker((Node *) ((HashJoin *) plan)->hashclauses,
									 &results);
			Assert(results.subplans == NIL);
519
			break;
520

521
		case T_Hash:
522 523 524
			finalize_primnode_walker((Node *) ((Hash *) plan)->hashkey,
									 &results);
			Assert(results.subplans == NIL);
525 526 527
			break;

		case T_Agg:
528
			/* XXX Code used to reject subplans in Aggref args; needed?? */
529
			break;
530

531 532 533 534 535 536 537
		case T_SeqScan:
		case T_NestLoop:
		case T_Material:
		case T_Sort:
		case T_Unique:
		case T_Group:
			break;
538

539
		default:
540 541
			elog(ERROR, "SS_finalize_plan: node %d unsupported",
				 nodeTag(plan));
542
			return NULL;
543
	}
544

545 546 547 548 549 550 551 552 553
	finalize_primnode_walker((Node *) plan->qual, &results);
	/* subplans are OK in the qual... */

	results.paramids = set_unioni(results.paramids,
								  SS_finalize_plan(plan->lefttree));
	results.paramids = set_unioni(results.paramids,
								  SS_finalize_plan(plan->righttree));

	/* Now we have all the paramids and subplans */
554

555
	foreach(lst, results.paramids)
556
	{
557 558
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

559
		/* note varlevelsup is absolute level number */
560 561 562
		if (var->varlevelsup < PlannerQueryLevel)
			extParam = lappendi(extParam, lfirsti(lst));
		else if (var->varlevelsup > PlannerQueryLevel)
563
			elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan's variable");
564 565
		else
		{
566 567
			Assert(var->varno == 0 && var->varattno == 0);
			locParam = lappendi(locParam, lfirsti(lst));
568 569
		}
	}
570

571 572
	plan->extParam = extParam;
	plan->locParam = locParam;
573
	plan->subPlan = results.subplans;
574

575
	return results.paramids;
576 577
}

578 579 580
/*
 * Construct a list of all subplans found within the given node tree.
 */
581

582 583
static bool SS_pull_subplan_walker(Node *node, List **listptr);

584
List *
585
SS_pull_subplan(Node *expr)
586
{
587
	List	   *result = NIL;
588

589 590 591
	SS_pull_subplan_walker(expr, &result);
	return result;
}
592

593 594 595 596 597 598
static bool
SS_pull_subplan_walker(Node *node, List **listptr)
{
	if (node == NULL)
		return false;
	if (is_subplan(node))
599
	{
600
		*listptr = lappend(*listptr, ((Expr *) node)->oper);
601
		/* fall through to check args to subplan */
602
	}
603 604
	return expression_tree_walker(node, SS_pull_subplan_walker,
								  (void *) listptr);
605
}