ExecAggTransReparent is underdocumented and badly named - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | ExecAggTransReparent is underdocumented and badly named |
Date | |
Msg-id | 3004282.1681930251@sss.pgh.pa.us Whole thread Raw |
List | pgsql-hackers |
I wondered at [1] why ExecAggTransReparent doesn't do what you'd guess from the name, that is reparent a supplied R/W expanded object under the aggcontext even if it's not there already. I tried to make it do that, and after I'd finished bandaging my wounds, I wrote some commentary explaining why that won't work. (Possibly we knew this at some point, but if so we sure failed to provide documentation about it.) I think we should at least apply the attached commentary-only patch. I wonder though if we should change the name of this function, and if so to what. Maybe ExecAggCopyTransValue? regards, tom lane [1] https://www.postgresql.org/message-id/2199319.1681662388%40sss.pgh.pa.us diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 4cd46f1717..386abf50b3 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4341,10 +4341,27 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup } /* - * Ensure that the current transition value is a child of the aggcontext, + * Ensure that the new transition value is stored in the aggcontext, * rather than the per-tuple context. * * NB: This can change the current memory context. + * + * This function is misnamed. It can either copy the datum returned by + * the transfn, or do nothing if the datum points to a R/W expanded object + * that is already a child of the aggcontext. What it will *not* do is what + * you might guess from the name, that is transfer a R/W expanded object from + * some other context to the aggcontext. We expect that a transfn that deals + * in expanded objects and is aware of the memory management conventions for + * aggregate transition values will have returned a R/W expanded object that + * is already in the right context. However, if we have a generic transfn + * that returns a R/W expanded object in the per-tuple context, we have a + * problem. If we pass that R/W object to the next invocation of the transfn, + * it will be at liberty to change or delete that object, and if it deletes it + * then our own attempt to delete the now-old transvalue afterwards will be a + * double free. We avoid this problem by forcing the transvalue to always + * be a flat non-expanded object unless the transfn is visibly doing + * aggregate-aware memory management. This is somewhat inefficient, but the + * best answer to that is to write a smarter transfn. */ Datum ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans, @@ -4559,9 +4576,7 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans, /* * For pass-by-ref datatype, must copy the new value into aggcontext and * free the prior transValue. But if transfn returned a pointer to its - * first input, we don't need to do anything. Also, if transfn returned a - * pointer to a R/W expanded object that is already a child of the - * aggcontext, assume we can adopt that value without copying it. + * first input, we don't need to do anything. * * It's safe to compare newVal with pergroup->transValue without regard * for either being NULL, because ExecAggTransReparent() takes care to set diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 3ac581a711..75a4f83ff1 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -368,7 +368,8 @@ advance_windowaggregate(WindowAggState *winstate, * free the prior transValue. But if transfn returned a pointer to its * first input, we don't need to do anything. Also, if transfn returned a * pointer to a R/W expanded object that is already a child of the - * aggcontext, assume we can adopt that value without copying it. + * aggcontext, assume we can adopt that value without copying it. (See + * comments for ExecAggTransReparent, which this code duplicates.) */ if (!peraggstate->transtypeByVal && DatumGetPointer(newVal) != DatumGetPointer(peraggstate->transValue)) @@ -533,7 +534,8 @@ advance_windowaggregate_base(WindowAggState *winstate, * free the prior transValue. But if invtransfn returned a pointer to its * first input, we don't need to do anything. Also, if invtransfn * returned a pointer to a R/W expanded object that is already a child of - * the aggcontext, assume we can adopt that value without copying it. + * the aggcontext, assume we can adopt that value without copying it. (See + * comments for ExecAggTransReparent, which this code duplicates.) * * Note: the checks for null values here will never fire, but it seems * best to have this stanza look just like advance_windowaggregate.
pgsql-hackers by date: