88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.31 2000/06/09 01:44:09 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.32 2000/06/10 05:16:38 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -189,6 +189,9 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
189189Plan * initNode ;
190190List * junkList ;
191191RelationInfo * es_rri = estate -> es_result_relation_info ;
192+ bool inherited_result_rel = false;
193+
194+ CXT1_printf ("ExecInitAppend: context is %d\n" ,CurrentMemoryContext );
192195
193196/* ----------------
194197 *assign execution state to node and get information
@@ -201,8 +204,8 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
201204nplans = length (appendplans );
202205rtable = node -> inheritrtable ;
203206
204- CXT1_printf ("ExecInitAppend: context is %d\n" ,CurrentMemoryContext );
205207initialized = (bool * )palloc (nplans * sizeof (bool ));
208+ MemSet (initialized ,0 ,nplans * sizeof (bool ));
206209
207210/* ----------------
208211 *create new AppendState for our append node
@@ -231,7 +234,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
231234#define APPEND_NSLOTS 1
232235/* ----------------
233236 *append nodes still have Result slots, which hold pointers
234- *to tuples, so we have to initialize them..
237+ *to tuples, so we have to initialize them.
235238 * ----------------
236239 */
237240ExecInitResultTupleSlot (estate ,& appendstate -> cstate );
@@ -247,34 +250,60 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
247250(node -> inheritrelid == es_rri -> ri_RangeTableIndex ))
248251{
249252List * resultList = NIL ;
253+ Oid initial_reloid = RelationGetRelid (es_rri -> ri_RelationDesc );
250254List * rtentryP ;
251255
256+ inherited_result_rel = true;
257+
252258foreach (rtentryP ,rtable )
253259{
254260RangeTblEntry * rtentry = lfirst (rtentryP );
255- Oid reloid ;
261+ Oid reloid = rtentry -> relid ;
256262RelationInfo * rri ;
257263
258- reloid = rtentry -> relid ;
259- rri = makeNode (RelationInfo );
260- rri -> ri_RangeTableIndex = es_rri -> ri_RangeTableIndex ;
261- rri -> ri_RelationDesc = heap_open (reloid ,RowExclusiveLock );
262- rri -> ri_NumIndices = 0 ;
263- rri -> ri_IndexRelationDescs = NULL ;/* index descs */
264- rri -> ri_IndexRelationInfo = NULL ;/* index key info */
265-
266- if (rri -> ri_RelationDesc -> rd_rel -> relhasindex )
267- ExecOpenIndices (reloid ,rri );
268-
269- resultList = lcons (rri ,resultList );
264+ /*
265+ * We must recycle the RelationInfo already opened by InitPlan()
266+ * for the parent rel, else we will leak the associated relcache
267+ * refcount.
268+ */
269+ if (reloid == initial_reloid )
270+ {
271+ Assert (es_rri != NULL );/* check we didn't use it already */
272+ rri = es_rri ;
273+ es_rri = NULL ;
274+ }
275+ else
276+ {
277+ rri = makeNode (RelationInfo );
278+ rri -> ri_RangeTableIndex = node -> inheritrelid ;
279+ rri -> ri_RelationDesc = heap_open (reloid ,RowExclusiveLock );
280+ rri -> ri_NumIndices = 0 ;
281+ rri -> ri_IndexRelationDescs = NULL ;/* index descs */
282+ rri -> ri_IndexRelationInfo = NULL ;/* index key info */
283+
284+ /*
285+ * XXX if the operation is a DELETE then we need not open
286+ * indices, but how to tell that here?
287+ */
288+ if (rri -> ri_RelationDesc -> rd_rel -> relhasindex )
289+ ExecOpenIndices (reloid ,rri );
290+ }
291+
292+ /*
293+ * NB: the as_result_relation_info_list must be in the same
294+ * order as the rtentry list otherwise update or delete on
295+ * inheritance hierarchies won't work.
296+ */
297+ resultList = lappend (resultList ,rri );
270298}
271- /*
272- The as_result_relation_info_listmust be in the same
273- order as the rtentry list otherwise update or delete on
274- inheritance hierarchies won't work.
275- */
276- appendstate -> as_result_relation_info_list = lreverse ( resultList ) ;
299+
300+ appendstate -> as_result_relation_info_list = resultList ;
301+ /* Check that we recycled InitPlan()'s RelationInfo */
302+ Assert ( es_rri == NULL );
303+ /* Just for paranoia's sake, clear link until we set it properly */
304+ estate -> es_result_relation_info = NULL ;
277305}
306+
278307/* ----------------
279308 *call ExecInitNode on each of the plans in our list
280309 *and save the results into the array "initialized"
@@ -304,8 +333,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
304333 *the one that we're looking at the subclasses of
305334 * ---------------
306335 */
307- if ((es_rri != (RelationInfo * )NULL )&&
308- (node -> inheritrelid == es_rri -> ri_RangeTableIndex ))
336+ if (inherited_result_rel )
309337{
310338JunkFilter * j = ExecInitJunkFilter (initNode -> targetlist ,
311339ExecGetTupType (initNode ));
@@ -361,7 +389,6 @@ ExecProcAppend(Append *node)
361389{
362390EState * estate ;
363391AppendState * appendstate ;
364-
365392int whichplan ;
366393List * appendplans ;
367394Plan * subnode ;
@@ -376,7 +403,6 @@ ExecProcAppend(Append *node)
376403appendstate = node -> appendstate ;
377404estate = node -> plan .state ;
378405direction = estate -> es_direction ;
379-
380406appendplans = node -> appendplans ;
381407whichplan = appendstate -> as_whichplan ;
382408result_slot = appendstate -> cstate .cs_ResultTupleSlot ;
@@ -448,19 +474,20 @@ ExecProcAppend(Append *node)
448474void
449475ExecEndAppend (Append * node )
450476{
477+ EState * estate ;
451478AppendState * appendstate ;
452479int nplans ;
453480List * appendplans ;
454481bool * initialized ;
455482int i ;
456483List * resultRelationInfoList ;
457- RelationInfo * resultRelationInfo ;
458484
459485/* ----------------
460486 *get information from the node
461487 * ----------------
462488 */
463489appendstate = node -> appendstate ;
490+ estate = node -> plan .state ;
464491appendplans = node -> appendplans ;
465492nplans = appendstate -> as_nplans ;
466493initialized = appendstate -> as_initialized ;
@@ -471,7 +498,7 @@ ExecEndAppend(Append *node)
471498 */
472499for (i = 0 ;i < nplans ;i ++ )
473500{
474- if (initialized [i ]== TRUE )
501+ if (initialized [i ])
475502ExecEndNode ((Plan * )nth (i ,appendplans ), (Plan * )node );
476503}
477504
@@ -482,6 +509,7 @@ ExecEndAppend(Append *node)
482509resultRelationInfoList = appendstate -> as_result_relation_info_list ;
483510while (resultRelationInfoList != NIL )
484511{
512+ RelationInfo * resultRelationInfo ;
485513Relation resultRelationDesc ;
486514
487515resultRelationInfo = (RelationInfo * )lfirst (resultRelationInfoList );
@@ -490,8 +518,13 @@ ExecEndAppend(Append *node)
490518pfree (resultRelationInfo );
491519resultRelationInfoList = lnext (resultRelationInfoList );
492520}
493- if (appendstate -> as_result_relation_info_list )
494- pfree (appendstate -> as_result_relation_info_list );
521+ appendstate -> as_result_relation_info_list = NIL ;
522+ /*
523+ * This next step is critical to prevent EndPlan() from trying to close
524+ * an already-closed-and-deleted RelationInfo --- es_result_relation_info
525+ * is pointing at one of the nodes we just zapped above.
526+ */
527+ estate -> es_result_relation_info = NULL ;
495528
496529/*
497530 * XXX should free appendstate->as_rtentries and