prepunion.c 9.07 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * prepunion.c--
Bruce Momjian's avatar
Bruce Momjian committed
4
 *	  Routines to plan inheritance, union, and version queries
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.9 1997/11/25 22:00:10 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14
#include <string.h>
Marc G. Fournier's avatar
Marc G. Fournier committed
15 16
#include <sys/types.h>

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include "postgres.h"

#include "nodes/nodes.h"
#include "nodes/pg_list.h"
#include "nodes/execnodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"

#include "parser/parsetree.h"

#include "utils/elog.h"
#include "utils/lsyscache.h"

#include "optimizer/internal.h"
#include "optimizer/prep.h"
#include "optimizer/plancat.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"

36
static List *
37 38 39
plan_union_query(List *relids, Index rt_index,
				 RangeTblEntry *rt_entry, Query *parse, UnionFlag flag,
				 List **union_rtentriesPtr);
40 41
static RangeTblEntry *
new_rangetable_entry(Oid new_relid,
42
					 RangeTblEntry *old_entry);
43
static Query *
44 45
subst_rangetable(Query *root, Index index,
				 RangeTblEntry *new_entry);
46 47
static void
fix_parsetree_attnums(Index rt_index, Oid old_relid,
48
					  Oid new_relid, Query *parsetree);
49
static Append *
50 51
make_append(List *unionplans, Index rt_index,
			List *union_rt_entries, List *tlist);
52 53


54
/*
55
 * find-all-inheritors -
56 57 58
 *		Returns a list of relids corresponding to relations that inherit
 *		attributes from any relations listed in either of the argument relid
 *		lists.
59
 */
60
List	   *
61 62
find_all_inheritors(List *unexamined_relids,
					List *examined_relids)
63
{
64 65 66
	List	   *new_inheritors = NIL;
	List	   *new_examined_relids = NIL;
	List	   *new_unexamined_relids = NIL;
67 68 69 70 71

	/*
	 * Find all relations which inherit from members of
	 * 'unexamined-relids' and store them in 'new-inheritors'.
	 */
72 73
	List	   *rels = NIL;
	List	   *newrels = NIL;
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

	foreach(rels, unexamined_relids)
	{
		newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)),
									  newrels);
	}
	new_inheritors = newrels;

	new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids);
	new_unexamined_relids = set_differencei(new_inheritors,
											new_examined_relids);

	if (new_unexamined_relids == NULL)
	{
		return (new_examined_relids);
	}
	else
	{
		return (find_all_inheritors(new_unexamined_relids,
									new_examined_relids));
	}
95 96
}

97
/*
98
 * first-matching-rt-entry -
99 100 101 102
 *		Given a rangetable, find the first rangetable entry that represents
 *		the appropriate special case.
 *
 *		Returns a rangetable index.,  Returns -1 if no matches
103 104
 */
int
105
first_matching_rt_entry(List *rangetable, UnionFlag flag)
106
{
107 108
	int			count = 0;
	List	   *temp = NIL;
109

110 111
	foreach(temp, rangetable)
	{
112
		RangeTblEntry *rt_entry = lfirst(temp);
113 114 115

		switch (flag)
		{
116 117 118 119 120 121
			case INHERITS_FLAG:
				if (rt_entry->inh)
					return count + 1;
				break;
			default:
				break;
122 123
		}
		count++;
124
	}
125 126

	return (-1);
127 128 129
}


130
/*
131
 * plan-union-queries--
132 133 134
 *
 *	  Plans the queries for a given parent relation.
 *
135 136 137 138
 * Returns a list containing a list of plans and a list of rangetable
 * entries to be inserted into an APPEND node.
 * XXX - what exactly does this mean, look for make_append
 */
139
Append	   *
140
plan_union_queries(Index rt_index,
141
				   Query *parse,
142
				   UnionFlag flag)
143
{
144 145 146 147 148
	List	   *rangetable = parse->rtable;
	RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
	List	   *union_relids = NIL;
	List	   *union_plans = NIL;
	List	   *union_rt_entries = NIL;
149 150

	switch (flag)
151
	{
152 153 154 155 156 157
		case INHERITS_FLAG:
			union_relids =
				find_all_inheritors(lconsi(rt_entry->relid,
										   NIL),
									NIL);
			break;
158 159

#if 0
160 161 162
		case UNION_FLAG:
			{
				Index		rt_index = 0;
163

164 165 166
				union_plans = handleunion(root, rangetable, tlist, qual);
				return (make_append(union_plans,
									rt_index, rangetable,
167
							((Plan *) lfirst(union_plans))->targetlist));
168 169
			}
			break;
170
#endif
171

172 173 174
		case VERSION_FLAG:
			union_relids = VersionGetParents(rt_entry->relid);
			break;
175

176 177 178
		default:
			/* do nothing */
			break;
179 180 181 182 183 184 185 186
	}

	/*
	 * Remove the flag for this relation, since we're about to handle it
	 * (do it before recursing!). XXX destructive parse tree change
	 */
	switch (flag)
	{
187 188 189 190 191
		case INHERITS_FLAG:
			rt_fetch(rt_index, rangetable)->inh = false;
			break;
		default:
			break;
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
	}

	/*
	 * XXX - can't find any reason to sort union-relids as paul did, so
	 * we're leaving it out for now (maybe forever) - jeff & lp
	 *
	 * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
	 * -- ay 10/94.]
	 */
	union_plans = plan_union_query(union_relids, rt_index, rt_entry,
								   parse, flag, &union_rt_entries);

	return (make_append(union_plans,
						rt_index,
						union_rt_entries,
						((Plan *) lfirst(union_plans))->targetlist));
208 209 210
}


211
/*
212
 * plan-union-query--
213 214
 *	  Returns a list of plans for 'relids' and a list of range table entries
 *	  in union_rtentries.
215
 */
216
static List *
217
plan_union_query(List *relids,
218
				 Index rt_index,
219 220
				 RangeTblEntry *rt_entry,
				 Query *root,
221
				 UnionFlag flag,
222
				 List **union_rtentriesPtr)
223
{
224 225 226
	List	   *i;
	List	   *union_plans = NIL;
	List	   *union_rtentries = NIL;
227

228 229
	foreach(i, relids)
	{
230 231 232 233 234 235
		int			relid = lfirsti(i);
		RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
														   rt_entry);
		Query	   *new_root = subst_rangetable(root,
												rt_index,
												new_rt_entry);
236 237 238 239 240 241 242 243

		/*
		 * reset the uniqueflag and sortclause in parse tree root, so that
		 * sorting will only be done once after append
		 */
/*		new_root->uniqueFlag = false; */
		new_root->uniqueFlag = NULL;
		new_root->sortClause = NULL;
Bruce Momjian's avatar
Bruce Momjian committed
244 245 246 247
		fix_parsetree_attnums(rt_index,
							  rt_entry->relid,
							  relid,
							  new_root);
248 249 250 251

		union_plans = lappend(union_plans, planner(new_root));
		union_rtentries = lappend(union_rtentries, new_rt_entry);
	}
252

253 254
	*union_rtentriesPtr = union_rtentries;
	return (union_plans);
255 256
}

257
/*
258
 * new-rangetable-entry -
259 260 261 262
 *		Replaces the name and relid of 'old-entry' with the values for
 *		'new-relid'.
 *
 *		Returns a copy of 'old-entry' with the parameters substituted.
263 264
 */
static RangeTblEntry *
265
new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
266
{
267
	RangeTblEntry *new_entry = copyObject(old_entry);
268

269 270 271 272 273 274
	/* ??? someone tell me what the following is doing! - ay 11/94 */
	if (!strcmp(new_entry->refname, "*CURRENT*") ||
		!strcmp(new_entry->refname, "*NEW*"))
		new_entry->refname = get_rel_name(new_relid);
	else
		new_entry->relname = get_rel_name(new_relid);
275

276 277
	new_entry->relid = new_relid;
	return (new_entry);
278 279
}

280
/*
281
 * subst-rangetable--
282 283
 *	  Replaces the 'index'th rangetable entry in 'root' with 'new-entry'.
 *
284 285
 * Returns a new copy of 'root'.
 */
286
static Query *
287
subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry)
288
{
289 290 291
	Query	   *new_root = copyObject(root);
	List	   *temp = NIL;
	int			i = 0;
292

293 294 295
	for (temp = new_root->rtable, i = 1; i < index; temp = lnext(temp), i++)
		;
	lfirst(temp) = new_entry;
296

297
	return (new_root);
298 299 300 301
}

static void
fix_parsetree_attnums_nodes(Index rt_index,
302 303
							Oid old_relid,
							Oid new_relid,
304
							Node *node)
305
{
306 307 308 309
	if (node == NULL)
		return;

	switch (nodeTag(node))
310
	{
311 312 313
		case T_TargetEntry:
			{
				TargetEntry *tle = (TargetEntry *) node;
314

315 316 317 318 319 320 321
				fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
											tle->expr);
			}
			break;
		case T_Expr:
			{
				Expr	   *expr = (Expr *) node;
322

323 324 325 326 327 328 329 330
				fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
											(Node *) expr->args);
			}
			break;
		case T_Var:
			{
				Var		   *var = (Var *) node;
				Oid			old_typeid,
331 332 333 334
							new_typeid;

/*			old_typeid = RelationIdGetTypeId(old_relid);*/
/*			new_typeid = RelationIdGetTypeId(new_relid);*/
335 336 337 338 339 340 341 342 343
				old_typeid = old_relid;
				new_typeid = new_relid;

				if (var->varno == rt_index && var->varattno != 0)
				{
					var->varattno =
						get_attnum(new_typeid,
								 get_attname(old_typeid, var->varattno));
				}
344
			}
345 346
			break;
		case T_List:
347
			{
348 349 350 351 352 353 354
				List	   *l;

				foreach(l, (List *) node)
				{
					fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
												(Node *) lfirst(l));
				}
355
			}
356 357 358
			break;
		default:
			break;
359 360
	}
}
361 362

/*
363
 * fix-parsetree-attnums--
364 365 366 367
 *	  Replaces attribute numbers from the relation represented by
 *	  'old-relid' in 'parsetree' with the attribute numbers from
 *	  'new-relid'.
 *
368
 * Returns the destructively-modified parsetree.
369
 *
370 371 372
 */
static void
fix_parsetree_attnums(Index rt_index,
373 374
					  Oid old_relid,
					  Oid new_relid,
375
					  Query *parsetree)
376
{
377 378
	if (old_relid == new_relid)
		return;
379

380 381 382 383
	fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
								(Node *) parsetree->targetList);
	fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
								parsetree->qual);
384 385
}

386
static Append *
387
make_append(List *unionplans,
388
			Index rt_index,
389 390
			List *union_rt_entries,
			List *tlist)
391
{
392
	Append	   *node = makeNode(Append);
393 394 395 396 397 398 399 400 401 402 403 404

	node->unionplans = unionplans;
	node->unionrelid = rt_index;
	node->unionrtentries = union_rt_entries;
	node->plan.cost = 0.0;
	node->plan.state = (EState *) NULL;
	node->plan.targetlist = tlist;
	node->plan.qual = NIL;
	node->plan.lefttree = (Plan *) NULL;
	node->plan.righttree = (Plan *) NULL;

	return (node);
405
}