nodeAppend.c 14.8 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * nodeAppend.c
4
 *	  routines to handle append nodes.
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
B
Bruce Momjian 已提交
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.33 2000/06/15 04:09:52 momjian Exp $
12 13 14 15
 *
 *-------------------------------------------------------------------------
 */
/* INTERFACE ROUTINES
16 17 18
 *		ExecInitAppend	- initialize the append node
 *		ExecProcAppend	- retrieve the next tuple from the node
 *		ExecEndAppend	- shut down the append node
19
 *		ExecReScanAppend - rescan the append node
20
 *
21 22 23 24 25 26
 *	 NOTES
 *		Each append node contains a list of one or more subplans which
 *		must be iteratively processed (forwards or backwards).
 *		Tuples are retrieved by executing the 'whichplan'th subplan
 *		until the subplan stops returning tuples, at which point that
 *		plan is shut down and the next started up.
27
 *
28 29 30
 *		Append nodes don't make use of their left and right
 *		subtrees, rather they maintain a list of subplans so
 *		a typical append node looks like this in the plan tree:
31
 *
32 33 34 35 36 37
 *				   ...
 *				   /
 *				Append -------+------+------+--- nil
 *				/	\		  |		 |		|
 *			  nil	nil		 ...	...    ...
 *								 subplans
38
 *
39
 *		Append nodes are currently used for unions, and to support inheritance
40 41 42 43 44
 *		queries, where several relations need to be scanned.
 *		For example, in our standard person/student/employee/student-emp
 *		example, where student and employee inherit from person
 *		and student-emp inherits from student and employee, the
 *		query:
45
 *
46
 *				retrieve (e.name) from e in person*
47
 *
48
 *		generates the plan:
49
 *
50 51 52 53 54 55
 *				  |
 *				Append -------+-------+--------+--------+
 *				/	\		  |		  |		   |		|
 *			  nil	nil		 Scan	 Scan	  Scan	   Scan
 *							  |		  |		   |		|
 *							person employee student student-emp
56
 */
57 58
#include "postgres.h"

59

60 61
#include "access/heapam.h"
#include "executor/execdebug.h"
62
#include "executor/nodeAppend.h"
B
Bruce Momjian 已提交
63
#include "parser/parsetree.h"
64

B
Bruce Momjian 已提交
65
static bool exec_append_initialize_next(Append *node);
66

67
/* ----------------------------------------------------------------
68
 *		exec_append_initialize_next
69 70 71 72 73
 *
 *		Sets up the append node state (i.e. the append state node)
 *		for the "next" scan.
 *
 *		Returns t iff there is a "next" scan to process.
74 75
 * ----------------------------------------------------------------
 */
76
static bool
B
Bruce Momjian 已提交
77
exec_append_initialize_next(Append *node)
78
{
79
	EState	   *estate;
80
	AppendState *appendstate;
81
	TupleTableSlot *result_slot;
82
	List	   *rangeTable;
83

84 85
	int			whichplan;
	int			nplans;
86 87
	List	   *rtables;
	List	   *rtable;
88
	RangeTblEntry *rtentry;
89 90 91 92 93 94

	/* ----------------
	 *	get information from the append node
	 * ----------------
	 */
	estate = node->plan.state;
95 96
	appendstate = node->appendstate;
	result_slot = appendstate->cstate.cs_ResultTupleSlot;
97 98
	rangeTable = estate->es_range_table;

99 100 101 102
	whichplan = appendstate->as_whichplan;
	nplans = appendstate->as_nplans;
	rtables = node->unionrtables;
	rtable = node->inheritrtable;
103 104 105 106 107 108 109 110 111 112 113

	if (whichplan < 0)
	{
		/* ----------------
		 *		if scanning in reverse, we start at
		 *		the last scan in the list and then
		 *		proceed back to the first.. in any case
		 *		we inform ExecProcAppend that we are
		 *		at the end of the line by returning FALSE
		 * ----------------
		 */
114
		appendstate->as_whichplan = 0;
115 116 117 118 119 120 121 122 123 124
		return FALSE;

	}
	else if (whichplan >= nplans)
	{
		/* ----------------
		 *		as above, end the scan if we go beyond
		 *		the last scan in our list..
		 * ----------------
		 */
125
		appendstate->as_whichplan = nplans - 1;
126 127 128 129 130 131 132 133 134 135 136 137
		return FALSE;

	}
	else
	{
		/* ----------------
		 *		initialize the scan
		 *		(and update the range table appropriately)
		 *		  (doesn't this leave the range table hosed for anybody upstream
		 *		   of the Append node??? - jolly )
		 * ----------------
		 */
138
		if (node->inheritrelid > 0)
139
		{
140
			rtentry = nth(whichplan, rtable);
141
			Assert(rtentry != NULL);
142

143
			rt_store(node->inheritrelid, rangeTable, rtentry);
144
		}
145
		else
146
			estate->es_range_table = nth(whichplan, rtables);
147

148
		if (appendstate->as_junkFilter_list)
149
		{
150
			estate->es_junkFilter = (JunkFilter *) nth(whichplan,
B
Bruce Momjian 已提交
151
										appendstate->as_junkFilter_list);
152
		}
153
		if (appendstate->as_result_relation_info_list)
154
		{
155
			estate->es_result_relation_info = (RelationInfo *) nth(whichplan,
156
							  appendstate->as_result_relation_info_list);
157 158
		}
		result_slot->ttc_whichplan = whichplan;
159 160

		return TRUE;
161 162 163 164
	}
}

/* ----------------------------------------------------------------
165 166 167 168 169
 *		ExecInitAppend
 *
 *		Begins all of the subscans of the append node, storing the
 *		scan structures in the 'initialized' vector of the append-state
 *		structure.
170
 *
171 172 173 174 175 176
 *	   (This is potentially wasteful, since the entire result of the
 *		append node may not be scanned, but this way all of the
 *		structures get allocated in the executor's top level memory
 *		block instead of that of the call to ExecProcAppend.)
 *
 *		Returns the scan result of the first scan.
177 178 179
 * ----------------------------------------------------------------
 */
bool
180
ExecInitAppend(Append *node, EState *estate, Plan *parent)
181
{
182
	AppendState *appendstate;
183
	int			nplans;
184 185
	List	   *rtable;
	List	   *appendplans;
186 187 188 189 190
	bool	   *initialized;
	int			i;
	Plan	   *initNode;
	List	   *junkList;
	RelationInfo *es_rri = estate->es_result_relation_info;
191 192 193
	bool		inherited_result_rel = false;

	CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
194 195 196 197 198 199 200 201

	/* ----------------
	 *	assign execution state to node and get information
	 *	for append state
	 * ----------------
	 */
	node->plan.state = estate;

202 203 204
	appendplans = node->appendplans;
	nplans = length(appendplans);
	rtable = node->inheritrtable;
205 206

	initialized = (bool *) palloc(nplans * sizeof(bool));
207
	MemSet(initialized, 0, nplans * sizeof(bool));
208 209 210 211 212

	/* ----------------
	 *	create new AppendState for our append node
	 * ----------------
	 */
213 214 215 216 217
	appendstate = makeNode(AppendState);
	appendstate->as_whichplan = 0;
	appendstate->as_nplans = nplans;
	appendstate->as_initialized = initialized;
	appendstate->as_rtentries = rtable;
218

219
	node->appendstate = appendstate;
220 221 222 223 224 225 226 227 228 229 230

	/* ----------------
	 *	Miscellanious initialization
	 *
	 *		 +	assign node's base_id
	 *		 +	assign debugging hooks
	 *
	 *	Append plans don't have expression contexts because they
	 *	never call ExecQual or ExecTargetList.
	 * ----------------
	 */
231
	ExecAssignNodeBaseInfo(estate, &appendstate->cstate, parent);
232

233
#define APPEND_NSLOTS 1
234 235
	/* ----------------
	 *	append nodes still have Result slots, which hold pointers
236
	 *	to tuples, so we have to initialize them.
237 238
	 * ----------------
	 */
239
	ExecInitResultTupleSlot(estate, &appendstate->cstate);
240 241 242 243 244 245 246 247 248

	/*
	 * If the inherits rtentry is the result relation, we have to make a
	 * result relation info list for all inheritors so we can update their
	 * indices and put the result tuples in the right place etc.
	 *
	 * e.g. replace p (age = p.age + 1) from p in person*
	 */
	if ((es_rri != (RelationInfo *) NULL) &&
249
		(node->inheritrelid == es_rri->ri_RangeTableIndex))
250
	{
251
		List	   *resultList = NIL;
252
		Oid			initial_reloid = RelationGetRelid(es_rri->ri_RelationDesc);
253
		List	   *rtentryP;
254

255 256
		inherited_result_rel = true;

257
		foreach(rtentryP, rtable)
258
		{
259
			RangeTblEntry *rtentry = lfirst(rtentryP);
260
			Oid			reloid = rtentry->relid;
261
			RelationInfo *rri;
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
			/*
			 * We must recycle the RelationInfo already opened by InitPlan()
			 * for the parent rel, else we will leak the associated relcache
			 * refcount. 
			 */
			if (reloid == initial_reloid)
			{
				Assert(es_rri != NULL);	/* check we didn't use it already */
				rri = es_rri;
				es_rri = NULL;
			}
			else
			{
				rri = makeNode(RelationInfo);
				rri->ri_RangeTableIndex = node->inheritrelid;
				rri->ri_RelationDesc = heap_open(reloid, RowExclusiveLock);
				rri->ri_NumIndices = 0;
				rri->ri_IndexRelationDescs = NULL;	/* index descs */
				rri->ri_IndexRelationInfo = NULL;	/* index key info */

				/*
				 * XXX if the operation is a DELETE then we need not open
				 * indices, but how to tell that here?
				 */
				if (rri->ri_RelationDesc->rd_rel->relhasindex)
					ExecOpenIndices(reloid, rri);
			}

			/*
			 * NB: the as_result_relation_info_list must be in the same
			 * order as the rtentry list otherwise update or delete on
			 * inheritance hierarchies won't work.
			 */
			resultList = lappend(resultList, rri);
297
		}
298 299 300 301 302 303

		appendstate->as_result_relation_info_list = resultList;
		/* Check that we recycled InitPlan()'s RelationInfo */
		Assert(es_rri == NULL);
		/* Just for paranoia's sake, clear link until we set it properly */
		estate->es_result_relation_info = NULL;
304
	}
305

306 307 308 309
	/* ----------------
	 *	call ExecInitNode on each of the plans in our list
	 *	and save the results into the array "initialized"
	 * ----------------
310
	 */
311 312 313 314 315 316 317 318 319 320 321
	junkList = NIL;

	for (i = 0; i < nplans; i++)
	{
		/* ----------------
		 *	NOTE: we first modify range table in
		 *		  exec_append_initialize_next() and
		 *		  then initialize the subnode,
		 *		  since it may use the range table.
		 * ----------------
		 */
322
		appendstate->as_whichplan = i;
323 324
		exec_append_initialize_next(node);

325
		initNode = (Plan *) nth(i, appendplans);
326 327 328 329 330 331 332 333 334
		initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);

		/* ---------------
		 *	Each targetlist in the subplan may need its own junk filter
		 *
		 *	This is true only when the reln being replaced/deleted is
		 *	the one that we're looking at the subclasses of
		 * ---------------
		 */
335
		if (inherited_result_rel)
336
		{
337 338
			JunkFilter *j = ExecInitJunkFilter(initNode->targetlist,
											   ExecGetTupType(initNode));
339

340 341 342
			junkList = lappend(junkList, j);
		}

343
	}
344
	appendstate->as_junkFilter_list = junkList;
345 346 347 348 349 350 351
	if (junkList != NIL)
		estate->es_junkFilter = (JunkFilter *) lfirst(junkList);

	/* ----------------
	 *	initialize the return type from the appropriate subplan.
	 * ----------------
	 */
352
	initNode = (Plan *) nth(0, appendplans);
353
	ExecAssignResultType(&appendstate->cstate, ExecGetTupType(initNode));
354
	appendstate->cstate.cs_ProjInfo = NULL;
355 356 357 358 359

	/* ----------------
	 *	return the result from the first subplan's initialization
	 * ----------------
	 */
360
	appendstate->as_whichplan = 0;
361
	exec_append_initialize_next(node);
362

363
	return TRUE;
364 365 366
}

int
B
Bruce Momjian 已提交
367
ExecCountSlotsAppend(Append *node)
368
{
369
	List	   *plan;
370
	List	   *appendplans = node->appendplans;
371
	int			nSlots = 0;
372

373
	foreach(plan, appendplans)
374 375
		nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
	return nSlots + APPEND_NSLOTS;
376 377 378
}

/* ----------------------------------------------------------------
379 380 381 382 383
 *	   ExecProcAppend
 *
 *		Handles the iteration over the multiple scans.
 *
 *	   NOTE: Can't call this ExecAppend, that name is used in execMain.l
384 385 386
 * ----------------------------------------------------------------
 */
TupleTableSlot *
B
Bruce Momjian 已提交
387
ExecProcAppend(Append *node)
388
{
389
	EState	   *estate;
390
	AppendState *appendstate;
391
	int			whichplan;
392
	List	   *appendplans;
393
	Plan	   *subnode;
394 395
	TupleTableSlot *result;
	TupleTableSlot *result_slot;
396
	ScanDirection direction;
397

398
	/* ----------------
399
	 *	get information from the node
400 401
	 * ----------------
	 */
402
	appendstate = node->appendstate;
403 404
	estate = node->plan.state;
	direction = estate->es_direction;
405 406 407
	appendplans = node->appendplans;
	whichplan = appendstate->as_whichplan;
	result_slot = appendstate->cstate.cs_ResultTupleSlot;
408 409 410 411 412

	/* ----------------
	 *	figure out which subplan we are currently processing
	 * ----------------
	 */
413
	subnode = (Plan *) nth(whichplan, appendplans);
414 415 416 417 418 419 420 421 422 423 424 425 426 427

	if (subnode == NULL)
		elog(DEBUG, "ExecProcAppend: subnode is NULL");

	/* ----------------
	 *	get a tuple from the subplan
	 * ----------------
	 */
	result = ExecProcNode(subnode, (Plan *) node);

	if (!TupIsNull(result))
	{
		/* ----------------
		 *	if the subplan gave us something then place a copy of
428 429 430 431
		 *	whatever we get into our result slot and return it.
		 *
		 *	Note we rely on the subplan to retain ownership of the
		 *	tuple for as long as we need it --- we don't copy it.
432 433
		 * ----------------
		 */
434
		return ExecStoreTuple(result->val, result_slot, InvalidBuffer, false);
435 436 437 438 439 440 441 442
	}
	else
	{
		/* ----------------
		 *	.. go on to the "next" subplan in the appropriate
		 *	direction and try processing again (recursively)
		 * ----------------
		 */
443
		whichplan = appendstate->as_whichplan;
444 445

		if (ScanDirectionIsForward(direction))
446
			appendstate->as_whichplan = whichplan + 1;
447
		else
448
			appendstate->as_whichplan = whichplan - 1;
449 450 451 452 453 454 455 456 457

		/* ----------------
		 *	return something from next node or an empty slot
		 *	all of our subplans have been exhausted.
		 * ----------------
		 */
		if (exec_append_initialize_next(node))
		{
			ExecSetSlotDescriptorIsNew(result_slot, true);
458
			return ExecProcAppend(node);
459 460 461 462
		}
		else
			return ExecClearTuple(result_slot);
	}
463 464 465
}

/* ----------------------------------------------------------------
466 467 468 469 470
 *		ExecEndAppend
 *
 *		Shuts down the subscans of the append node.
 *
 *		Returns nothing of interest.
471 472 473
 * ----------------------------------------------------------------
 */
void
B
Bruce Momjian 已提交
474
ExecEndAppend(Append *node)
475
{
476
	EState	   *estate;
477
	AppendState *appendstate;
478
	int			nplans;
479
	List	   *appendplans;
480 481 482
	bool	   *initialized;
	int			i;
	List	   *resultRelationInfoList;
483 484 485 486 487

	/* ----------------
	 *	get information from the node
	 * ----------------
	 */
488
	appendstate = node->appendstate;
489
	estate = node->plan.state;
490 491 492
	appendplans = node->appendplans;
	nplans = appendstate->as_nplans;
	initialized = appendstate->as_initialized;
493 494 495 496 497 498 499

	/* ----------------
	 *	shut down each of the subscans
	 * ----------------
	 */
	for (i = 0; i < nplans; i++)
	{
500
		if (initialized[i])
501
			ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
502 503 504 505 506 507
	}

	/* ----------------
	 *	close out the different result relations
	 * ----------------
	 */
508
	resultRelationInfoList = appendstate->as_result_relation_info_list;
509 510
	while (resultRelationInfoList != NIL)
	{
511
		RelationInfo *resultRelationInfo;
512
		Relation	resultRelationDesc;
513

514 515
		resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
		resultRelationDesc = resultRelationInfo->ri_RelationDesc;
516
		heap_close(resultRelationDesc, NoLock);
517 518 519
		pfree(resultRelationInfo);
		resultRelationInfoList = lnext(resultRelationInfoList);
	}
520 521 522 523 524 525 526
	appendstate->as_result_relation_info_list = NIL;
	/*
	 * This next step is critical to prevent EndPlan() from trying to close
	 * an already-closed-and-deleted RelationInfo --- es_result_relation_info
	 * is pointing at one of the nodes we just zapped above.
	 */
	estate->es_result_relation_info = NULL;
527 528

	/*
529 530
	 * XXX should free appendstate->as_rtentries  and
	 * appendstate->as_junkfilter_list here
531 532
	 */
}
533 534 535 536
void
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
{
	AppendState *appendstate = node->appendstate;
537 538
	int			nplans = length(node->appendplans);
	int			i;
539 540 541 542 543 544 545 546 547 548

	for (i = 0; i < nplans; i++)
	{
		Plan	   *rescanNode;

		appendstate->as_whichplan = i;
		rescanNode = (Plan *) nth(i, node->appendplans);
		if (rescanNode->chgParam == NULL)
		{
			exec_append_initialize_next(node);
549
			ExecReScan((Plan *) rescanNode, exprCtxt, (Plan *) node);
550 551 552 553 554
		}
	}
	appendstate->as_whichplan = 0;
	exec_append_initialize_next(node);
}