diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 779d8ac1e69..ea4cfde33f1 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -922,6 +922,15 @@ advance_transition_function(AggState *aggstate,
 	 * 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.
+	 *
+	 * It's safe to compare newVal with pergroupstate->transValue without
+	 * regard for either being NULL, because we below take care to set
+	 * transValue to 0 when NULL. Otherwise we could end up accidentally not
+	 * reparenting, when the transValue has the same numerical value as
+	 * newVal, despite being NULL.  This is a somewhat hot path, making it
+	 * undesirable to instead solve this with another branch for the common
+	 * case of the transition function returning its (modified) input
+	 * argument.
 	 */
 	if (!pertrans->transtypeByVal &&
 		DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
@@ -939,6 +948,16 @@ advance_transition_function(AggState *aggstate,
 								   pertrans->transtypeByVal,
 								   pertrans->transtypeLen);
 		}
+		else
+		{
+			/*
+			 * Ensure that pergroupstate->transValue ends up being 0, so we
+			 * can safely compare newVal/transValue without having to check
+			 * their respective nullness.
+			 */
+			newVal = (Datum) 0;
+		}
+
 		if (!pergroupstate->transValueIsNull)
 		{
 			if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,