subselect.c 14.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*-------------------------------------------------------------------------
 *
 * subselect.c--
 *
 *-------------------------------------------------------------------------
 */
#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"

29 30 31 32 33
int			PlannerQueryLevel;	/* level of current query */
List	   *PlannerVarParam;	/* correlation Vars to Param mapper */
List	   *PlannerParamVar;	/* to get Var from Param->paramid */
List	   *PlannerInitPlan;	/* init subplans for current query */
int			PlannerPlanId;
34 35 36


static int
37
_new_param(Var *var, int varlevel)
38
{
39 40 41 42
	List	   *last;
	int			i = 0;

	if (PlannerParamVar == NULL)
43 44 45
		last = PlannerParamVar = makeNode(List);
	else
	{
46
		for (last = PlannerParamVar;;)
47 48
		{
			i++;
49
			if (lnext(last) == NULL)
50 51 52 53 54 55
				break;
			last = lnext(last);
		}
		lnext(last) = makeNode(List);
		last = lnext(last);
	}
56

57
	lnext(last) = NULL;
58 59 60
	lfirst(last) = makeVar(var->varno, var->varattno, var->vartype,
				var->vartypmod, varlevel, var->varnoold, var->varoattno);

61
	return i;
62 63
}

64 65
static Param *
_replace_var(Var *var)
66
{
67 68 69 70 71 72
	List	  **rt = (List **) nth(var->varlevelsup, PlannerVarParam);
	List	   *vpe = rt[var->varno - 1];
	Param	   *retval;
	int			i;

	if (vpe == NULL)
73 74 75 76 77
	{
		vpe = rt[var->varno - 1] = makeNode(List);
		lfirsti(vpe) = -1;
		lnext(vpe) = NULL;
	}
78

79
	for (i = ObjectIdAttributeNumber;; i++)
80
	{
81
		if (i == var->varattno)
82
			break;
83
		if (lnext(vpe) == NULL)
84 85 86 87 88 89 90 91 92
		{
			lnext(vpe) = makeNode(List);
			vpe = lnext(vpe);
			lfirsti(vpe) = -1;
			lnext(vpe) = NULL;
		}
		else
			vpe = lnext(vpe);
	}
93 94 95 96

	if ((i = lfirsti(vpe)) < 0) /* parameter is not assigned */
		i = _new_param(var, PlannerQueryLevel - var->varlevelsup);

97 98 99 100
	retval = makeNode(Param);
	retval->paramkind = PARAM_EXEC;
	retval->paramid = (AttrNumber) i;
	retval->paramtype = var->vartype;
101

102
	return retval;
103 104
}

105 106
static Node *
_make_subplan(SubLink *slink)
107
{
108
	SubPlan    *node = makeNode(SubPlan);
109 110 111 112
	Plan	   *plan;
	List	   *lst;
	Node	   *result;
	List	   *saved_ip = PlannerInitPlan;
113

114
	PlannerInitPlan = NULL;
115

116
	PlannerQueryLevel++;		/* we becomes child */
117 118 119 120 121 122 123

	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.
124
	 */
125
	(void) SS_finalize_plan(plan);
126
	plan->initPlan = PlannerInitPlan;
127

128
	/* Get extParam from InitPlan-s */
129
	foreach(lst, PlannerInitPlan)
130
	{
131 132 133
		List	   *lp;

		foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)
134
		{
135 136
			if (!intMember(lfirsti(lp), plan->extParam))
				plan->extParam = lappendi(plan->extParam, lfirsti(lp));
137 138
		}
	}
139

140 141 142
	/* and now we are parent again */
	PlannerInitPlan = saved_ip;
	PlannerQueryLevel--;
143

144
	node->plan_id = PlannerPlanId++;
145
	node->rtable = ((Query *) slink->subselect)->rtable;
146 147
	node->sublink = slink;
	slink->subselect = NULL;	/* cool ?! */
148

149
	/* make parParam list */
150
	foreach(lst, plan->extParam)
151
	{
152 153 154 155
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

		if (var->varlevelsup == PlannerQueryLevel)
			node->parParam = lappendi(node->parParam, lfirsti(lst));
156
	}
157 158 159 160

	/*
	 * Un-correlated or undirect correlated plans of EXISTS or EXPR types
	 * can be used as initPlans...
161
	 */
162
	if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
163
	{
164 165
		int			i = 0;

166
		/* transform right side of all sublink Oper-s into Param */
167
		foreach(lst, slink->oper)
168
		{
169 170 171 172 173 174 175
			List	   *rside = lnext(((Expr *) lfirst(lst))->args);
			TargetEntry *te = nth(i, plan->targetlist);
			Var		   *var = makeVar(0, 0, te->resdom->restype,
									  te->resdom->restypmod,
									  PlannerQueryLevel, 0, 0);
			Param	   *prm = makeNode(Param);

176
			prm->paramkind = PARAM_EXEC;
177
			prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
178 179
			prm->paramtype = var->vartype;
			lfirst(rside) = prm;
180 181
			node->setParam = lappendi(node->setParam, prm->paramid);
			pfree(var);
182 183
			i++;
		}
184 185 186 187
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		if (i > 1)
			result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
							   make_andclause(slink->oper));
188
		else
189
			result = (Node *) lfirst(slink->oper);
190
	}
191
	else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
192
	{
193
		Var		   *var = makeVar(0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0);
194
		Param	   *prm = makeNode(Param);
195

196
		prm->paramkind = PARAM_EXEC;
197
		prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
198
		prm->paramtype = var->vartype;
199 200 201 202
		node->setParam = lappendi(node->setParam, prm->paramid);
		pfree(var);
		PlannerInitPlan = lappend(PlannerInitPlan, node);
		result = (Node *) prm;
203
	}
204 205
	else
/* make expression of SUBPLAN type */
206
	{
207 208 209 210
		Expr	   *expr = makeNode(Expr);
		List	   *args = NULL;
		int			i = 0;

211 212
		expr->typeOid = BOOLOID;
		expr->opType = SUBPLAN_EXPR;
213 214 215 216 217 218
		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.
219
		 */
220
		foreach(lst, node->parParam)
221
		{
222 223 224
			Var		   *var = nth(lfirsti(lst), PlannerParamVar);

			var = (Var *) copyObject(var);
225
			var->varlevelsup = 0;
226
			args = lappend(args, var);
227
		}
228
		foreach(lst, slink->oper)
229
		{
230 231 232 233 234
			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);

235 236 237 238
			lfirst(rside) = con;
			i++;
		}
		expr->args = args;
239
		result = (Node *) expr;
240
	}
241

242
	return result;
243

244 245 246
}

static List *
247
set_unioni(List *l1, List *l2)
248 249
{
	if (l1 == NULL)
250
		return l2;
251
	if (l2 == NULL)
252
		return l1;
253

254
	return nconc(l1, set_differencei(l2, l1));
255 256 257
}

static List *
258
_finalize_primnode(void *expr, List **subplan)
259
{
260 261 262
	List	   *result = NULL;

	if (expr == NULL)
263
		return NULL;
264 265

	if (IsA(expr, Param))
266
	{
267
		if (((Param *) expr)->paramkind == PARAM_EXEC)
268
			return lconsi(((Param *) expr)->paramid, (List *) NULL);
269 270
	}
	else if (single_node(expr))
271
		return NULL;
272
	else if (IsA(expr, List))
273
	{
274 275 276 277 278
		List	   *le;

		foreach(le, (List *) expr)
			result = set_unioni(result,
								_finalize_primnode(lfirst(le), subplan));
279
	}
280
	else if (IsA(expr, Iter))
281
		return _finalize_primnode(((Iter *) expr)->iterexpr, subplan);
282 283
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
284
		return _finalize_primnode(((Expr *) expr)->args, subplan);
285
	else if (IsA(expr, Aggreg))
286
		return _finalize_primnode(((Aggreg *) expr)->target, subplan);
287
	else if (IsA(expr, ArrayRef))
288
	{
289 290 291 292 293 294 295
		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));
296
	}
297
	else if (IsA(expr, TargetEntry))
298
		return _finalize_primnode(((TargetEntry *) expr)->expr, subplan);
299
	else if (is_subplan(expr))
300
	{
301 302 303 304
		List	   *lst;

		*subplan = lappend(*subplan, ((Expr *) expr)->oper);
		foreach(lst, ((SubPlan *) ((Expr *) expr)->oper)->plan->extParam)
305
		{
306 307 308 309 310
			Var		   *var = nth(lfirsti(lst), PlannerParamVar);

			if (var->varlevelsup < PlannerQueryLevel &&
				!intMember(lfirsti(lst), result))
				result = lappendi(result, lfirsti(lst));
311 312 313
		}
	}
	else
314 315 316
		elog(ERROR, "_finalize_primnode: can't handle node %d",
			 nodeTag(expr));

317
	return result;
318 319 320
}

Node *
321
SS_replace_correlation_vars(Node *expr)
322 323
{

324
	if (expr == NULL)
325
		return NULL;
326
	if (IsA(expr, List))
327
	{
328 329 330 331
		List	   *le;

		foreach(le, (List *) expr)
			lfirst(le) = SS_replace_correlation_vars((Node *) lfirst(le));
332
	}
333
	else if (IsA(expr, Var))
334
	{
335
		if (((Var *) expr)->varlevelsup > 0)
336
		{
337 338
			Assert(((Var *) expr)->varlevelsup < PlannerQueryLevel);
			expr = (Node *) _replace_var((Var *) expr);
339 340
		}
	}
341
	else if (IsA(expr, Iter))
342
	{
343 344
		((Iter *) expr)->iterexpr =
			SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
345 346
	}
	else if (single_node(expr))
347
		return expr;
348 349 350 351 352 353 354 355
	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);
	else if (IsA(expr, Aggreg))
		((Aggreg *) expr)->target =
			SS_replace_correlation_vars((Node *) ((Aggreg *) expr)->target);
	else if (IsA(expr, ArrayRef))
356
	{
357 358 359 360 361 362 363 364
		((ArrayRef *) expr)->refupperindexpr = (List *)
			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refupperindexpr);
		((ArrayRef *) expr)->reflowerindexpr = (List *)
			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->reflowerindexpr);
		((ArrayRef *) expr)->refexpr =
			SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refexpr);
		((ArrayRef *) expr)->refassgnexpr =
			SS_replace_correlation_vars(((ArrayRef *) expr)->refassgnexpr);
365
	}
366 367 368 369
	else if (IsA(expr, TargetEntry))
		((TargetEntry *) expr)->expr =
			SS_replace_correlation_vars((Node *) ((TargetEntry *) expr)->expr);
	else if (IsA(expr, SubLink))
370
	{
371 372 373
		List	   *le;

		foreach(le, ((SubLink *) expr)->oper)	/* left sides only */
374
		{
375 376 377 378
			List	   *oparg = ((Expr *) lfirst(le))->args;

			lfirst(oparg) = (List *)
				SS_replace_correlation_vars((Node *) lfirst(oparg));
379
		}
380 381
		((SubLink *) expr)->lefthand = (List *)
			SS_replace_correlation_vars((Node *) ((SubLink *) expr)->lefthand);
382 383
	}
	else
384 385 386
		elog(NOTICE, "SS_replace_correlation_vars: can't handle node %d",
			 nodeTag(expr));

387
	return expr;
388 389
}

390 391
Node *
SS_process_sublinks(Node *expr)
392
{
393
	if (expr == NULL)
394
		return NULL;
395
	if (IsA(expr, List))
396
	{
397 398 399 400
		List	   *le;

		foreach(le, (List *) expr)
			lfirst(le) = SS_process_sublinks((Node *) lfirst(le));
401
	}
402 403 404 405 406
	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! */
407 408 409 410 411 412 413
	{
          /* Hack to make sure expr->oper->args points to the same VAR node
           * as expr->lefthand does. Needed for subselects in the havingQual
           * when used on views.
           * Otherwise aggregate functions will fail later on (at execution 
           * time!) Reason: The rewite System makes several copies of the
           * VAR nodes and in this case it should not do so :-( */
B
Bruce Momjian 已提交
414
	    if(((SubLink *) expr)->lefthand != NULL)
415 416 417 418
		{
			lfirst(((Expr *) lfirst(((SubLink *)expr)->oper))->args) = 
			lfirst(((SubLink *)expr)->lefthand);
		}
419
	    expr = _make_subplan((SubLink *) expr);
420
	}
421
	
422
	return expr;
423 424
}

425 426
List *
SS_finalize_plan(Plan *plan)
427
{
428 429 430 431 432 433 434
	List	   *extParam = NULL;
	List	   *locParam = NULL;
	List	   *subPlan = NULL;
	List	   *param_list;
	List	   *lst;

	if (plan == NULL)
435
		return NULL;
436 437 438 439

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

440 441 442
	switch (nodeTag(plan))
	{
		case T_Result:
443 444
			param_list = set_unioni(param_list,
									_finalize_primnode(((Result *) plan)->resconstantqual, &subPlan));
445 446 447
			break;

		case T_Append:
448
			foreach(lst, ((Append *) plan)->appendplans)
449 450
				param_list = set_unioni(param_list,
								 SS_finalize_plan((Plan *) lfirst(lst)));
451
			break;
452

453
		case T_IndexScan:
454 455 456
			param_list = set_unioni(param_list,
			_finalize_primnode(((IndexScan *) plan)->indxqual, &subPlan));
			Assert(subPlan == NULL);
457 458 459
			break;

		case T_MergeJoin:
460 461 462
			param_list = set_unioni(param_list,
									_finalize_primnode(((MergeJoin *) plan)->mergeclauses, &subPlan));
			Assert(subPlan == NULL);
463 464 465
			break;

		case T_HashJoin:
466 467 468
			param_list = set_unioni(param_list,
									_finalize_primnode(((HashJoin *) plan)->hashclauses, &subPlan));
			Assert(subPlan == NULL);
469
			break;
470

471
		case T_Hash:
472 473 474
			param_list = set_unioni(param_list,
				 _finalize_primnode(((Hash *) plan)->hashkey, &subPlan));
			Assert(subPlan == NULL);
475 476 477
			break;

		case T_Agg:
478 479 480
			param_list = set_unioni(param_list,
					 _finalize_primnode(((Agg *) plan)->aggs, &subPlan));
			Assert(subPlan == NULL);
481
			break;
482

483 484 485 486 487 488 489 490 491
		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));
492
			return NULL;
493
	}
494 495 496 497 498 499

	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)
500
	{
501 502 503 504 505 506
		Var		   *var = nth(lfirsti(lst), PlannerParamVar);

		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");
507 508
		else
		{
509 510
			Assert(var->varno == 0 && var->varattno == 0);
			locParam = lappendi(locParam, lfirsti(lst));
511 512
		}
	}
513

514 515 516
	plan->extParam = extParam;
	plan->locParam = locParam;
	plan->subPlan = subPlan;
517

518
	return param_list;
519 520 521

}

522
List	   *SS_pull_subplan(void *expr);
523 524

List *
525
SS_pull_subplan(void *expr)
526
{
527 528 529
	List	   *result = NULL;

	if (expr == NULL || single_node(expr))
530
		return NULL;
531 532

	if (IsA(expr, List))
533
	{
534 535 536 537
		List	   *le;

		foreach(le, (List *) expr)
			result = nconc(result, SS_pull_subplan(lfirst(le)));
538
	}
539
	else if (IsA(expr, Iter))
540
		return SS_pull_subplan(((Iter *) expr)->iterexpr);
541 542
	else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
			 not_clause(expr) || is_funcclause(expr))
543
		return SS_pull_subplan(((Expr *) expr)->args);
544
	else if (IsA(expr, Aggreg))
545
		return SS_pull_subplan(((Aggreg *) expr)->target);
546
	else if (IsA(expr, ArrayRef))
547
	{
548 549 550 551 552 553 554
		result = SS_pull_subplan(((ArrayRef *) expr)->refupperindexpr);
		result = nconc(result,
				  SS_pull_subplan(((ArrayRef *) expr)->reflowerindexpr));
		result = nconc(result,
					   SS_pull_subplan(((ArrayRef *) expr)->refexpr));
		result = nconc(result,
					 SS_pull_subplan(((ArrayRef *) expr)->refassgnexpr));
555
	}
556
	else if (IsA(expr, TargetEntry))
557
		return SS_pull_subplan(((TargetEntry *) expr)->expr);
558
	else if (is_subplan(expr))
559
		return lcons(((Expr *) expr)->oper, NULL);
560
	else
561 562 563
		elog(ERROR, "SS_pull_subplan: can't handle node %d",
			 nodeTag(expr));

564
	return result;
565
}