prepunion.c 17.0 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * prepunion.c
B
Bruce Momjian 已提交
4
 *	  Routines to plan inheritance, union, and version queries
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.48 2000/04/12 17:15:23 momjian Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
M
Marc G. Fournier 已提交
15 16
#include <sys/types.h>

17 18
#include "postgres.h"

19
#include "optimizer/clauses.h"
20
#include "optimizer/plancat.h"
V
Vadim B. Mikheev 已提交
21
#include "optimizer/planmain.h"
B
Bruce Momjian 已提交
22 23
#include "optimizer/planner.h"
#include "optimizer/prep.h"
24
#include "optimizer/tlist.h"
B
Bruce Momjian 已提交
25 26 27
#include "parser/parse_clause.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
28

29 30
typedef struct
{
31 32 33 34 35 36
	Index		rt_index;
	int			sublevels_up;
	Oid			old_relid;
	Oid			new_relid;
} fix_parsetree_attnums_context;

B
Bruce Momjian 已提交
37
static List *plan_inherit_query(Relids relids, Index rt_index,
38
				   RangeTblEntry *rt_entry, Query *parse, List *tlist,
39
				   List **union_rtentriesPtr);
40
static RangeTblEntry *new_rangetable_entry(Oid new_relid,
41
					 RangeTblEntry *old_entry);
42
static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
43
					  Oid new_relid, Query *parsetree);
44 45
static bool fix_parsetree_attnums_walker(Node *node,
							 fix_parsetree_attnums_context *context);
46
static Append *make_append(List *appendplans, List *unionrtables,
47 48
			Index rt_index,
			List *inheritrtable, List *tlist);
49 50


51
/*
52
 * plan_union_queries
53 54 55 56
 *
 *	  Plans the queries for a given UNION.
 *
 * Returns a list containing a list of plans and a list of rangetables
57
 */
58
Append *
59
plan_union_queries(Query *parse)
60
{
61 62
	List	   *union_plans = NIL,
			   *ulist,
63
			   *union_all_queries,
64
			   *union_rts,
65 66
			   *last_union = NIL,
			   *hold_sortClause = parse->sortClause;
67 68
	bool		union_all_found = false,
				union_found = false,
69
				last_union_all_flag = false;
70

71 72
	/*------------------------------------------------------------------
	 *
73 74 75 76 77
	 * Do we need to split up our unions because we have UNION and UNION
	 * ALL?
	 *
	 * We are checking for the case of: SELECT 1 UNION SELECT 2 UNION SELECT
	 * 3 UNION ALL SELECT 4 UNION ALL SELECT 5
78
	 *
79 80 81 82 83 84
	 * where we have to do a DISTINCT on the output of the first three
	 * queries, then add the rest.	If they have used UNION and UNION ALL,
	 * we grab all queries up to the last UNION query, make them their own
	 * UNION with the owner as the first query in the list.  Then, we take
	 * the remaining queries, which is UNION ALL, and add them to the list
	 * of union queries.
85
	 *
86
	 * So the above query becomes:
87
	 *
88
	 *	Append Node
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
	 *	{
	 *		Sort and Unique
	 *		{
	 *			Append Node
	 *			{
	 *				SELECT 1		This is really a sub-UNION.
	 *				unionClause		We run a DISTINCT on these.
	 *				{
	 *					SELECT 2
	 *					SELECT 3
	 *				}
	 *			}
	 *		}
	 *		SELECT 4
	 *		SELECT 5
	 *	}
105
	 *
106
	 *---------------------------------------------------------------------
107 108
	 */

109
	foreach(ulist, parse->unionClause)
110
	{
111
		Query	   *union_query = lfirst(ulist);
112

113 114 115 116 117 118 119
		if (union_query->unionall)
			union_all_found = true;
		else
		{
			union_found = true;
			last_union = ulist;
		}
120
		last_union_all_flag = union_query->unionall;
121
	}
122

123 124 125
	/* Is this a simple one */
	if (!union_all_found ||
		!union_found ||
126
	/* A trailing UNION negates the effect of earlier UNION ALLs */
127
		!last_union_all_flag)
128
	{
129
		List	   *hold_unionClause = parse->unionClause;
130
		double		tuple_fraction = -1.0;		/* default processing */
131

132
		/* we will do sorting later, so don't do it now */
133 134 135 136
		if (!union_all_found ||
			!last_union_all_flag)
		{
			parse->sortClause = NIL;
137
			parse->distinctClause = NIL;
138

139 140 141 142 143
			/*
			 * force lower-level planning to assume that all tuples will
			 * be retrieved, even if it sees a LIMIT in the query node.
			 */
			tuple_fraction = 0.0;
144 145
		}

146
		parse->unionClause = NIL;		/* prevent recursion */
147
		union_plans = lcons(union_planner(parse, tuple_fraction), NIL);
148 149 150 151
		union_rts = lcons(parse->rtable, NIL);

		foreach(ulist, hold_unionClause)
		{
152
			Query	   *union_query = lfirst(ulist);
153

154 155 156
			/*
			 * use subquery_planner here because the union'd queries have
			 * not been preprocessed yet.  My goodness this is messy...
157
			 */
158
			union_plans = lappend(union_plans,
159 160
								  subquery_planner(union_query,
												   tuple_fraction));
161 162
			union_rts = lappend(union_rts, union_query->rtable);
		}
163 164 165
	}
	else
	{
166

167
		/*
168
		 * We have mixed unions and non-unions
169
		 *
170 171
		 * We need to restructure this to put the UNIONs on their own so we
		 * can do a DISTINCT.
172
		 */
173

174
		/* save off everthing past the last UNION */
175
		union_all_queries = lnext(last_union);
176

177 178 179 180
		/* clip off the list to remove the trailing UNION ALLs */
		lnext(last_union) = NIL;

		/*
181
		 * Recursion, but UNION only. The last one is a UNION, so it will
182 183
		 * not come here in recursion.
		 *
184 185
		 * XXX is it OK to pass default -1 to union_planner in this path, or
		 * should we force a tuple_fraction value?
186
		 */
187
		union_plans = lcons(union_planner(parse, -1.0), NIL);
188
		union_rts = lcons(parse->rtable, NIL);
189

190
		/* Append the remaining UNION ALLs */
191
		foreach(ulist, union_all_queries)
192
		{
193
			Query	   *union_all_query = lfirst(ulist);
194

195 196 197
			/*
			 * use subquery_planner here because the union'd queries have
			 * not been preprocessed yet.  My goodness this is messy...
198
			 */
199
			union_plans = lappend(union_plans,
200
								subquery_planner(union_all_query, -1.0));
201
			union_rts = lappend(union_rts, union_all_query->rtable);
202
		}
203
	}
204

205
	/* We have already split UNION and UNION ALL and we made it consistent */
206
	if (!last_union_all_flag)
207
	{
208 209 210 211 212

		/*
		 * Need SELECT DISTINCT behavior to implement UNION. Put back the
		 * held sortClause, add any missing columns to the sort clause,
		 * and set distinctClause properly.
213
		 */
214 215
		List	   *slitem;

216 217
		parse->sortClause = addAllTargetsToSortList(hold_sortClause,
													parse->targetList);
218 219 220 221 222 223
		parse->distinctClause = NIL;
		foreach(slitem, parse->sortClause)
		{
			SortClause *scl = (SortClause *) lfirst(slitem);
			TargetEntry *tle = get_sortgroupclause_tle(scl, parse->targetList);

224
			if (!tle->resdom->resjunk)
225 226 227
				parse->distinctClause = lappend(parse->distinctClause,
												copyObject(scl));
		}
228 229
	}
	else
230
	{
231 232
		/* needed so we don't take SELECT DISTINCT from the first query */
		parse->distinctClause = NIL;
233
	}
234

235 236 237 238
	/*
	 * Make sure we don't try to apply the first query's grouping stuff to
	 * the Append node, either.  Basically we don't want union_planner to
	 * do anything when we return control, except add the top sort/unique
239 240 241 242
	 * nodes for DISTINCT processing if this wasn't UNION ALL, or the top
	 * sort node if it was UNION ALL with a user-provided sort clause.
	 */
	parse->groupClause = NULL;
243
	parse->havingQual = NULL;
244
	parse->hasAggs = false;
245

246 247 248 249 250
	return make_append(union_plans,
					   union_rts,
					   0,
					   NULL,
					   parse->targetList);
251 252 253
}


254
/*
255
 * plan_inherit_queries
256
 *
257
 *	  Plans the queries for an inheritance tree rooted at a parent relation.
258
 *
259 260 261 262 263 264 265 266 267 268
 * Inputs:
 *	parse = parent parse tree
 *	tlist = target list for inheritance subqueries (not same as parent's!)
 *	rt_index = rangetable index for current inheritance item
 *
 * Returns an APPEND node that forms the result of performing the given
 * query for each member relation of the inheritance group.
 *
 * If grouping, aggregation, or sorting is specified in the parent plan,
 * the subplans should not do any of those steps --- we must do those
269
 * operations just once above the APPEND node.	The given tlist has been
270 271 272 273 274
 * modified appropriately to remove group/aggregate expressions, but the
 * Query node still has the relevant fields set.  We remove them in the
 * copies used for subplans (see plan_inherit_query).
 *
 * NOTE: this can be invoked recursively if more than one inheritance wildcard
275
 * is present.	At each level of recursion, the first wildcard remaining in
276
 * the rangetable is expanded.
277
 */
278
Append *
279
plan_inherit_queries(Query *parse, List *tlist, Index rt_index)
280
{
281 282
	List	   *rangetable = parse->rtable;
	RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
283
	List	   *inheritrtable = NIL;
284 285
	List	   *union_relids;
	List	   *union_plans;
B
Bruce Momjian 已提交
286

287 288
	/* Make a list of the target relid plus all its descendants */
	union_relids = find_all_inheritors(rt_entry->relid);
289

290
	/*
291
	 * Remove the flag for this relation, since we're about to handle it.
292 293
	 * XXX destructive change to parent parse tree, but necessary to
	 * prevent infinite recursion.
294
	 */
295
	rt_entry->inh = false;
296

297
	union_plans = plan_inherit_query(union_relids, rt_index, rt_entry,
298
									 parse, tlist, &inheritrtable);
299

300 301 302 303 304
	return make_append(union_plans,
					   NULL,
					   rt_index,
					   inheritrtable,
					   ((Plan *) lfirst(union_plans))->targetlist);
305 306
}

307
/*
308
 * plan_inherit_query
309 310
 *	  Returns a list of plans for 'relids', plus a list of range table entries
 *	  in *union_rtentriesPtr.
311
 */
312
static List *
B
Bruce Momjian 已提交
313
plan_inherit_query(Relids relids,
314 315 316
				   Index rt_index,
				   RangeTblEntry *rt_entry,
				   Query *root,
317
				   List *tlist,
318
				   List **union_rtentriesPtr)
319
{
320 321
	List	   *union_plans = NIL;
	List	   *union_rtentries = NIL;
322
	List	   *save_tlist = root->targetList;
323
	double		tuple_fraction;
324
	List	   *i;
325

326 327
	/*
	 * Avoid making copies of the root's tlist, which we aren't going to
328 329
	 * use anyway (we are going to make copies of the passed tlist,
	 * instead).
330 331 332
	 */
	root->targetList = NIL;

333
	/*
334 335
	 * If we are going to need sorting or grouping at the top level, force
	 * lower-level planners to assume that all tuples will be retrieved.
336 337 338
	 */
	if (root->distinctClause || root->sortClause ||
		root->groupClause || root->hasAggs)
339
		tuple_fraction = 0.0;	/* will need all tuples from each subplan */
340
	else
341
		tuple_fraction = -1.0;	/* default behavior is OK (I think) */
342

343 344
	foreach(i, relids)
	{
345
		int			relid = lfirsti(i);
346

347
		/*
348 349 350
		 * Make a modifiable copy of the original query, and replace the
		 * target rangetable entry with a new one identifying this child
		 * table.
351 352
		 */
		Query	   *new_root = copyObject(root);
353 354
		RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
														   rt_entry);
355

356
		rt_store(rt_index, new_root->rtable, new_rt_entry);
357

358
		/*
359 360
		 * Insert (a modifiable copy of) the desired simplified tlist into
		 * the subquery
361 362 363 364 365 366
		 */
		new_root->targetList = copyObject(tlist);

		/*
		 * Clear the sorting and grouping qualifications in the subquery,
		 * so that sorting will only be done once after append
367
		 */
368 369 370
		new_root->distinctClause = NIL;
		new_root->sortClause = NIL;
		new_root->groupClause = NIL;
B
Bruce Momjian 已提交
371
		new_root->havingQual = NULL;
372
		new_root->hasAggs = false;		/* shouldn't be any left ... */
373

374 375 376 377 378
		/*
		 * Update attribute numbers in case child has different ordering
		 * of columns than parent (as can happen after ALTER TABLE).
		 *
		 * XXX This is a crock, and it doesn't really work.  It'd be better
379 380
		 * to fix ALTER TABLE to preserve consistency of attribute
		 * numbering.
381
		 */
B
Bruce Momjian 已提交
382 383 384 385
		fix_parsetree_attnums(rt_index,
							  rt_entry->relid,
							  relid,
							  new_root);
386

387 388
		union_plans = lappend(union_plans,
							  union_planner(new_root, tuple_fraction));
389 390
		union_rtentries = lappend(union_rtentries, new_rt_entry);
	}
391

392 393
	root->targetList = save_tlist;

394
	*union_rtentriesPtr = union_rtentries;
395
	return union_plans;
396 397
}

398
/*
399
 * find_all_inheritors -
400 401
 *		Returns an integer list of relids including the given rel plus
 *		all relations that inherit from it, directly or indirectly.
402
 */
403
List *
404
find_all_inheritors(Oid parentrel)
405
{
406 407
	List	   *examined_relids = NIL;
	List	   *unexamined_relids = lconsi(parentrel, NIL);
408 409

	/*
410 411 412
	 * While the queue of unexamined relids is nonempty, remove the first
	 * element, mark it examined, and find its direct descendants. NB:
	 * cannot use foreach(), since we modify the queue inside loop.
413
	 */
414
	while (unexamined_relids != NIL)
415
	{
416 417
		Oid			currentrel = lfirsti(unexamined_relids);
		List	   *currentchildren;
418

419 420 421
		unexamined_relids = lnext(unexamined_relids);
		examined_relids = lappendi(examined_relids, currentrel);
		currentchildren = find_inheritance_children(currentrel);
422

423
		/*
424 425 426 427
		 * Add to the queue only those children not already seen. This
		 * could probably be simplified to a plain nconc, because our
		 * inheritance relationships should always be a strict tree, no?
		 * Should never find any matches, ISTM...
428 429 430 431
		 */
		currentchildren = set_differencei(currentchildren, examined_relids);
		unexamined_relids = LispUnioni(unexamined_relids, currentchildren);
	}
432

433
	return examined_relids;
434 435 436
}

/*
437
 * first_inherit_rt_entry -
438
 *		Given a rangetable, find the first rangetable entry that represents
439
 *		an inheritance set.
440
 *
441 442
 *		Returns a rangetable index (1..n).
 *		Returns -1 if no matches
443 444 445 446 447
 */
int
first_inherit_rt_entry(List *rangetable)
{
	int			count = 0;
448
	List	   *temp;
449 450 451 452 453 454

	foreach(temp, rangetable)
	{
		RangeTblEntry *rt_entry = lfirst(temp);

		count++;
455 456
		if (rt_entry->inh)
			return count;
457 458 459 460 461
	}

	return -1;
}

462
/*
463 464 465
 * new_rangetable_entry -
 *		Replaces the name and relid of 'old_entry' with the values for
 *		'new_relid'.
466
 *
467
 *		Returns a copy of 'old_entry' with the parameters substituted.
468 469
 */
static RangeTblEntry *
470
new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
471
{
472
	RangeTblEntry *new_entry = copyObject(old_entry);
473

474
	/* ??? someone tell me what the following is doing! - ay 11/94 */
475 476
	if (!strcmp(new_entry->eref->relname, "*CURRENT*") ||
		!strcmp(new_entry->eref->relname, "*NEW*"))
477
		new_entry->ref->relname = get_rel_name(new_relid);
478 479
	else
		new_entry->relname = get_rel_name(new_relid);
480

481
	new_entry->relid = new_relid;
482
	return new_entry;
483 484
}

485
/*
486 487 488 489
 * fix_parsetree_attnums
 *	  Replaces attribute numbers from the relation represented by
 *	  'old_relid' in 'parsetree' with the attribute numbers from
 *	  'new_relid'.
490
 *
491
 * The parsetree is MODIFIED IN PLACE.	This is OK only because
492
 * plan_inherit_query made a copy of the tree for us to hack upon.
493
 */
494 495 496 497 498
static void
fix_parsetree_attnums(Index rt_index,
					  Oid old_relid,
					  Oid new_relid,
					  Query *parsetree)
499
{
500
	fix_parsetree_attnums_context context;
501

502 503
	if (old_relid == new_relid)
		return;					/* no work needed for parent rel itself */
504

505 506 507 508
	context.rt_index = rt_index;
	context.old_relid = old_relid;
	context.new_relid = new_relid;
	context.sublevels_up = 0;
509

510 511 512 513 514 515
	/*
	 * We must scan both the targetlist and qual, but we know the
	 * havingQual is empty, so we can ignore it.
	 */
	fix_parsetree_attnums_walker((Node *) parsetree->targetList, &context);
	fix_parsetree_attnums_walker((Node *) parsetree->qual, &context);
516 517
}

518
/*
519
 * Adjust varnos for child tables.	This routine makes it possible for
520 521 522 523 524 525 526
 * child tables to have different column positions for the "same" attribute
 * as a parent, which helps ALTER TABLE ADD COLUMN.  Unfortunately this isn't
 * nearly enough to make it work transparently; there are other places where
 * things fall down if children and parents don't have the same column numbers
 * for inherited attributes.  It'd be better to rip this code out and fix
 * ALTER TABLE...
 */
527
static bool
528 529
fix_parsetree_attnums_walker(Node *node,
							 fix_parsetree_attnums_context *context)
530
{
531
	if (node == NULL)
532 533
		return false;
	if (IsA(node, Var))
534
	{
535
		Var		   *var = (Var *) node;
536

537 538 539 540 541 542 543 544 545 546 547 548
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index &&
			var->varattno > 0)
		{
			var->varattno = get_attnum(context->new_relid,
									   get_attname(context->old_relid,
												   var->varattno));
		}
		return false;
	}
	if (IsA(node, SubLink))
	{
549

550
		/*
551 552
		 * Standard expression_tree_walker will not recurse into
		 * subselect, but here we must do so.
553 554
		 */
		SubLink    *sub = (SubLink *) node;
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
		if (fix_parsetree_attnums_walker((Node *) (sub->lefthand), context))
			return true;
		context->sublevels_up++;
		if (fix_parsetree_attnums_walker((Node *) (sub->subselect), context))
		{
			context->sublevels_up--;
			return true;
		}
		context->sublevels_up--;
		return false;
	}
	if (IsA(node, Query))
	{
		/* Reach here after recursing down into subselect above... */
		Query	   *qry = (Query *) node;

		if (fix_parsetree_attnums_walker((Node *) (qry->targetList), context))
			return true;
		if (fix_parsetree_attnums_walker((Node *) (qry->qual), context))
			return true;
		if (fix_parsetree_attnums_walker((Node *) (qry->havingQual), context))
			return true;
		return false;
	}
	return expression_tree_walker(node, fix_parsetree_attnums_walker,
								  (void *) context);
582 583
}

584
static Append *
585 586
make_append(List *appendplans,
			List *unionrtables,
587
			Index rt_index,
588
			List *inheritrtable,
589
			List *tlist)
590
{
591
	Append	   *node = makeNode(Append);
592
	List	   *subnode;
593

594 595 596 597
	node->appendplans = appendplans;
	node->unionrtables = unionrtables;
	node->inheritrelid = rt_index;
	node->inheritrtable = inheritrtable;
598 599
	node->plan.startup_cost = 0;
	node->plan.total_cost = 0;
600 601
	node->plan.plan_rows = 0;
	node->plan.plan_width = 0;
602
	foreach(subnode, appendplans)
603
	{
604
		Plan	   *subplan = (Plan *) lfirst(subnode);
605

606
		if (subnode == appendplans)		/* first node? */
607 608
			node->plan.startup_cost = subplan->startup_cost;
		node->plan.total_cost += subplan->total_cost;
609 610 611 612
		node->plan.plan_rows += subplan->plan_rows;
		if (node->plan.plan_width < subplan->plan_width)
			node->plan.plan_width = subplan->plan_width;
	}
613 614 615 616 617 618
	node->plan.state = (EState *) NULL;
	node->plan.targetlist = tlist;
	node->plan.qual = NIL;
	node->plan.lefttree = (Plan *) NULL;
	node->plan.righttree = (Plan *) NULL;

619
	return node;
620
}