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)
189189 Plan * initNode ;
190190 List * junkList ;
191191 RelationInfo * 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)
201204 nplans = length (appendplans );
202205 rtable = node -> inheritrtable ;
203206
204- CXT1_printf ("ExecInitAppend: context is %d\n" , CurrentMemoryContext );
205207 initialized = (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 */
237240 ExecInitResultTupleSlot (estate , & appendstate -> cstate );
@@ -247,34 +250,60 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
247250 (node -> inheritrelid == es_rri -> ri_RangeTableIndex ))
248251 {
249252 List * resultList = NIL ;
253+ Oid initial_reloid = RelationGetRelid (es_rri -> ri_RelationDesc );
250254 List * rtentryP ;
251255
256+ inherited_result_rel = true;
257+
252258 foreach (rtentryP , rtable )
253259 {
254260 RangeTblEntry * rtentry = lfirst (rtentryP );
255- Oid reloid ;
261+ Oid reloid = rtentry -> relid ;
256262 RelationInfo * 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_list must 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 {
310338 JunkFilter * j = ExecInitJunkFilter (initNode -> targetlist ,
311339 ExecGetTupType (initNode ));
@@ -361,7 +389,6 @@ ExecProcAppend(Append *node)
361389{
362390 EState * estate ;
363391 AppendState * appendstate ;
364-
365392 int whichplan ;
366393 List * appendplans ;
367394 Plan * subnode ;
@@ -376,7 +403,6 @@ ExecProcAppend(Append *node)
376403 appendstate = node -> appendstate ;
377404 estate = node -> plan .state ;
378405 direction = estate -> es_direction ;
379-
380406 appendplans = node -> appendplans ;
381407 whichplan = appendstate -> as_whichplan ;
382408 result_slot = appendstate -> cstate .cs_ResultTupleSlot ;
@@ -448,19 +474,20 @@ ExecProcAppend(Append *node)
448474void
449475ExecEndAppend (Append * node )
450476{
477+ EState * estate ;
451478 AppendState * appendstate ;
452479 int nplans ;
453480 List * appendplans ;
454481 bool * initialized ;
455482 int i ;
456483 List * resultRelationInfoList ;
457- RelationInfo * resultRelationInfo ;
458484
459485 /* ----------------
460486 * get information from the node
461487 * ----------------
462488 */
463489 appendstate = node -> appendstate ;
490+ estate = node -> plan .state ;
464491 appendplans = node -> appendplans ;
465492 nplans = appendstate -> as_nplans ;
466493 initialized = appendstate -> as_initialized ;
@@ -471,7 +498,7 @@ ExecEndAppend(Append *node)
471498 */
472499 for (i = 0 ; i < nplans ; i ++ )
473500 {
474- if (initialized [i ] == TRUE )
501+ if (initialized [i ])
475502 ExecEndNode ((Plan * ) nth (i , appendplans ), (Plan * ) node );
476503 }
477504
@@ -482,6 +509,7 @@ ExecEndAppend(Append *node)
482509 resultRelationInfoList = appendstate -> as_result_relation_info_list ;
483510 while (resultRelationInfoList != NIL )
484511 {
512+ RelationInfo * resultRelationInfo ;
485513 Relation resultRelationDesc ;
486514
487515 resultRelationInfo = (RelationInfo * ) lfirst (resultRelationInfoList );
@@ -490,8 +518,13 @@ ExecEndAppend(Append *node)
490518 pfree (resultRelationInfo );
491519 resultRelationInfoList = 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
0 commit comments