@@ -178,26 +178,8 @@ MemoryContextDelete(MemoryContext context)
178
178
* there's an error we won't have deleted/busted contexts still attached
179
179
* to the context tree. Better a leak than a crash.
180
180
*/
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 );
190
182
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
- }
201
183
(* context -> methods -> delete_context ) (context );
202
184
pfree (context );
203
185
}
@@ -237,6 +219,67 @@ MemoryContextResetAndDeleteChildren(MemoryContext context)
237
219
MemoryContextReset (context );
238
220
}
239
221
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
+
240
283
/*
241
284
* GetMemoryChunkSpace
242
285
* Given a currently-allocated chunk, determine the total space
@@ -489,6 +532,7 @@ MemoryContextCreate(NodeTag tag, Size size,
489
532
(* node -> methods -> init ) (node );
490
533
491
534
/* OK to link node to parent (if any) */
535
+ /* Could use MemoryContextSetParent here, but doesn't seem worthwhile */
492
536
if (parent )
493
537
{
494
538
node -> parent = parent ;
0 commit comments