aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r--src/backend/executor/nodeAgg.c76
1 files changed, 58 insertions, 18 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index b06e1c1562a..28c15bab99e 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -91,10 +91,13 @@
* transition value or a previous function result, and in either case its
* value need not be preserved. See int8inc() for an example. Notice that
* advance_transition_function() is coded to avoid a data copy step when
- * the previous transition value pointer is returned. Also, some
- * transition functions want to store working state in addition to the
- * nominal transition value; they can use the memory context returned by
- * AggCheckCallContext() to do that.
+ * the previous transition value pointer is returned. It is also possible
+ * to avoid repeated data copying when the transition value is an expanded
+ * object: to do that, the transition function must take care to return
+ * an expanded object that is in a child context of the memory context
+ * returned by AggCheckCallContext(). Also, some transition functions want
+ * to store working state in addition to the nominal transition value; they
+ * can use the memory context returned by AggCheckCallContext() to do that.
*
* Note: AggCheckCallContext() is available as of PostgreSQL 9.0. The
* AggState is available as context in earlier releases (back to 8.1),
@@ -791,8 +794,10 @@ advance_transition_function(AggState *aggstate,
/*
* If pass-by-ref datatype, must copy the new value into aggcontext and
- * pfree the prior transValue. But if transfn returned a pointer to its
- * first input, we don't need to do anything.
+ * 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.
*/
if (!pertrans->transtypeByVal &&
DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
@@ -800,12 +805,25 @@ advance_transition_function(AggState *aggstate,
if (!fcinfo->isnull)
{
MemoryContextSwitchTo(aggstate->aggcontexts[aggstate->current_set]->ecxt_per_tuple_memory);
- newVal = datumCopy(newVal,
- pertrans->transtypeByVal,
- pertrans->transtypeLen);
+ if (DatumIsReadWriteExpandedObject(newVal,
+ false,
+ pertrans->transtypeLen) &&
+ MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext)
+ /* do nothing */ ;
+ else
+ newVal = datumCopy(newVal,
+ pertrans->transtypeByVal,
+ pertrans->transtypeLen);
}
if (!pergroupstate->transValueIsNull)
- pfree(DatumGetPointer(pergroupstate->transValue));
+ {
+ if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
+ false,
+ pertrans->transtypeLen))
+ DeleteExpandedObject(pergroupstate->transValue);
+ else
+ pfree(DatumGetPointer(pergroupstate->transValue));
+ }
}
pergroupstate->transValue = newVal;
@@ -1053,8 +1071,11 @@ advance_combine_function(AggState *aggstate,
/*
* If pass-by-ref datatype, must copy the new value into aggcontext and
- * pfree the prior transValue. But if the combine function returned a
- * pointer to its first input, we don't need to do anything.
+ * free the prior transValue. But if the combine function returned a
+ * pointer to its first input, we don't need to do anything. Also, if the
+ * combine function 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.
*/
if (!pertrans->transtypeByVal &&
DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
@@ -1062,12 +1083,25 @@ advance_combine_function(AggState *aggstate,
if (!fcinfo->isnull)
{
MemoryContextSwitchTo(aggstate->aggcontexts[aggstate->current_set]->ecxt_per_tuple_memory);
- newVal = datumCopy(newVal,
- pertrans->transtypeByVal,
- pertrans->transtypeLen);
+ if (DatumIsReadWriteExpandedObject(newVal,
+ false,
+ pertrans->transtypeLen) &&
+ MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext)
+ /* do nothing */ ;
+ else
+ newVal = datumCopy(newVal,
+ pertrans->transtypeByVal,
+ pertrans->transtypeLen);
}
if (!pergroupstate->transValueIsNull)
- pfree(DatumGetPointer(pergroupstate->transValue));
+ {
+ if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
+ false,
+ pertrans->transtypeLen))
+ DeleteExpandedObject(pergroupstate->transValue);
+ else
+ pfree(DatumGetPointer(pergroupstate->transValue));
+ }
}
pergroupstate->transValue = newVal;
@@ -1333,7 +1367,9 @@ finalize_aggregate(AggState *aggstate,
(void *) aggstate, NULL);
/* Fill in the transition state value */
- fcinfo.arg[0] = pergroupstate->transValue;
+ fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
+ pergroupstate->transValueIsNull,
+ pertrans->transtypeLen);
fcinfo.argnull[0] = pergroupstate->transValueIsNull;
anynull |= pergroupstate->transValueIsNull;
@@ -1360,6 +1396,7 @@ finalize_aggregate(AggState *aggstate,
}
else
{
+ /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
*resultVal = pergroupstate->transValue;
*resultIsNull = pergroupstate->transValueIsNull;
}
@@ -1410,7 +1447,9 @@ finalize_partialaggregate(AggState *aggstate,
{
FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
- fcinfo->arg[0] = pergroupstate->transValue;
+ fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
+ pergroupstate->transValueIsNull,
+ pertrans->transtypeLen);
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
*resultVal = FunctionCallInvoke(fcinfo);
@@ -1419,6 +1458,7 @@ finalize_partialaggregate(AggState *aggstate,
}
else
{
+ /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
*resultVal = pergroupstate->transValue;
*resultIsNull = pergroupstate->transValueIsNull;
}