@@ -4341,15 +4341,40 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup
4341
4341
}
4342
4342
4343
4343
/*
4344
- * Ensure that the current transition value is a child of the aggcontext,
4345
- * rather than the per-tuple context.
4344
+ * Ensure that the new transition value is stored in the aggcontext,
4345
+ * rather than the per-tuple context. This should be invoked only when
4346
+ * we know (a) the transition data type is pass-by-reference, and (b)
4347
+ * the newValue is distinct from the oldValue.
4346
4348
*
4347
4349
* NB: This can change the current memory context.
4350
+ *
4351
+ * We copy the presented newValue into the aggcontext, except when the datum
4352
+ * points to a R/W expanded object that is already a child of the aggcontext,
4353
+ * in which case we need not copy. We then delete the oldValue, if not null.
4354
+ *
4355
+ * If the presented datum points to a R/W expanded object that is a child of
4356
+ * some other context, ideally we would just reparent it under the aggcontext.
4357
+ * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
4358
+ * aggregate-aware transfns. We expect that a transfn that deals in expanded
4359
+ * objects and is aware of the memory management conventions for aggregate
4360
+ * transition values will (1) on first call, return a R/W expanded object that
4361
+ * is already in the right context, allowing us to do nothing here, and (2) on
4362
+ * subsequent calls, modify and return that same object, so that control
4363
+ * doesn't even reach here. However, if we have a generic transfn that
4364
+ * returns a new R/W expanded object (probably in the per-tuple context),
4365
+ * reparenting that result would cause problems. We'd pass that R/W object to
4366
+ * the next invocation of the transfn, and then it would be at liberty to
4367
+ * change or delete that object, and if it deletes it then our own attempt to
4368
+ * delete the now-old transvalue afterwards would be a double free. We avoid
4369
+ * this problem by forcing the stored transvalue to always be a flat
4370
+ * non-expanded object unless the transfn is visibly doing aggregate-aware
4371
+ * memory management. This is somewhat inefficient, but the best answer to
4372
+ * that is to write a smarter transfn.
4348
4373
*/
4349
4374
Datum
4350
- ExecAggTransReparent (AggState * aggstate , AggStatePerTrans pertrans ,
4351
- Datum newValue , bool newValueIsNull ,
4352
- Datum oldValue , bool oldValueIsNull )
4375
+ ExecAggCopyTransValue (AggState * aggstate , AggStatePerTrans pertrans ,
4376
+ Datum newValue , bool newValueIsNull ,
4377
+ Datum oldValue , bool oldValueIsNull )
4353
4378
{
4354
4379
Assert (newValue != oldValue );
4355
4380
@@ -4559,12 +4584,10 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
4559
4584
/*
4560
4585
* For pass-by-ref datatype, must copy the new value into aggcontext and
4561
4586
* free the prior transValue. But if transfn returned a pointer to its
4562
- * first input, we don't need to do anything. Also, if transfn returned a
4563
- * pointer to a R/W expanded object that is already a child of the
4564
- * aggcontext, assume we can adopt that value without copying it.
4587
+ * first input, we don't need to do anything.
4565
4588
*
4566
4589
* It's safe to compare newVal with pergroup->transValue without regard
4567
- * for either being NULL, because ExecAggTransReparent() takes care to set
4590
+ * for either being NULL, because ExecAggCopyTransValue takes care to set
4568
4591
* transValue to 0 when NULL. Otherwise we could end up accidentally not
4569
4592
* reparenting, when the transValue has the same numerical value as
4570
4593
* newValue, despite being NULL. This is a somewhat hot path, making it
@@ -4573,10 +4596,10 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
4573
4596
* argument.
4574
4597
*/
4575
4598
if (DatumGetPointer (newVal ) != DatumGetPointer (pergroup -> transValue ))
4576
- newVal = ExecAggTransReparent (aggstate , pertrans ,
4577
- newVal , fcinfo -> isnull ,
4578
- pergroup -> transValue ,
4579
- pergroup -> transValueIsNull );
4599
+ newVal = ExecAggCopyTransValue (aggstate , pertrans ,
4600
+ newVal , fcinfo -> isnull ,
4601
+ pergroup -> transValue ,
4602
+ pergroup -> transValueIsNull );
4580
4603
4581
4604
pergroup -> transValue = newVal ;
4582
4605
pergroup -> transValueIsNull = fcinfo -> isnull ;
0 commit comments