@@ -178,26 +178,8 @@ MemoryContextDelete(MemoryContext context)
178178 * there's an error we won't have deleted/busted contexts still attached
179179 * to the context tree. Better a leak than a crash.
180180 */
181- if (context -> parent )
182- {
183- MemoryContext parent = context -> parent ;
184-
185- if (context == parent -> firstchild )
186- parent -> firstchild = context -> nextchild ;
187- else
188- {
189- MemoryContext child ;
181+ MemoryContextSetParent (context ,NULL );
190182
191- for (child = parent -> firstchild ;child ;child = child -> nextchild )
192- {
193- if (context == child -> nextchild )
194- {
195- child -> nextchild = context -> nextchild ;
196- break ;
197- }
198- }
199- }
200- }
201183(* context -> methods -> delete_context ) (context );
202184pfree (context );
203185}
@@ -237,6 +219,67 @@ MemoryContextResetAndDeleteChildren(MemoryContext context)
237219MemoryContextReset (context );
238220}
239221
222+ /*
223+ * MemoryContextSetParent
224+ *Change a context to belong to a new parent (or no parent).
225+ *
226+ * We provide this as an API function because it is sometimes useful to
227+ * change a context's lifespan after creation. For example, a context
228+ * might be created underneath a transient context, filled with data,
229+ * and then reparented underneath CacheMemoryContext to make it long-lived.
230+ * In this way no special effort is needed to get rid of the context in case
231+ * a failure occurs before its contents are completely set up.
232+ *
233+ * Callers often assume that this function cannot fail, so don't put any
234+ * elog(ERROR) calls in it.
235+ *
236+ * A possible caller error is to reparent a context under itself, creating
237+ * a loop in the context graph. We assert here that context != new_parent,
238+ * but checking for multi-level loops seems more trouble than it's worth.
239+ */
240+ void
241+ MemoryContextSetParent (MemoryContext context ,MemoryContext new_parent )
242+ {
243+ AssertArg (MemoryContextIsValid (context ));
244+ AssertArg (context != new_parent );
245+
246+ /* Delink from existing parent, if any */
247+ if (context -> parent )
248+ {
249+ MemoryContext parent = context -> parent ;
250+
251+ if (context == parent -> firstchild )
252+ parent -> firstchild = context -> nextchild ;
253+ else
254+ {
255+ MemoryContext child ;
256+
257+ for (child = parent -> firstchild ;child ;child = child -> nextchild )
258+ {
259+ if (context == child -> nextchild )
260+ {
261+ child -> nextchild = context -> nextchild ;
262+ break ;
263+ }
264+ }
265+ }
266+ }
267+
268+ /* And relink */
269+ if (new_parent )
270+ {
271+ AssertArg (MemoryContextIsValid (new_parent ));
272+ context -> parent = new_parent ;
273+ context -> nextchild = new_parent -> firstchild ;
274+ new_parent -> firstchild = context ;
275+ }
276+ else
277+ {
278+ context -> parent = NULL ;
279+ context -> nextchild = NULL ;
280+ }
281+ }
282+
240283/*
241284 * GetMemoryChunkSpace
242285 *Given a currently-allocated chunk, determine the total space
@@ -489,6 +532,7 @@ MemoryContextCreate(NodeTag tag, Size size,
489532(* node -> methods -> init ) (node );
490533
491534/* OK to link node to parent (if any) */
535+ /* Could use MemoryContextSetParent here, but doesn't seem worthwhile */
492536if (parent )
493537{
494538node -> parent = parent ;