From c68763005ae539bb4b8c145c420ed119c62f5282 Mon Sep 17 00:00:00 2001
From: Mario Karuza <mkaruza@users.noreply.github.com>
Date: Thu, 10 Sep 2026 22:30:56 +0200
Subject: [PATCH v1] Fix memory accounting for datum sorts of pass-by-reference
 types

Memory allocated for copied pass-by-reference Datums was not accounted
against work_mem because tuplesort_putdatum() passed a hardcoded
tuplen of 0 to tuplesort_puttuple_common(). free_sort_tuple() correctly
adjusts the accounting by the amount actually allocated for the tuple,
so freeing one subtracts an amount that was never added.

Compute tuplen in tuplesort_putdatum() consistently with the other
tuplesort_put*() variants. This ensures that pass-by-reference datum
data is properly accounted.
---
 src/backend/utils/sort/tuplesortvariants.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c
index 95b9ff9d39a..c648c78455a 100644
--- a/src/backend/utils/sort/tuplesortvariants.c
+++ b/src/backend/utils/sort/tuplesortvariants.c
@@ -939,6 +939,7 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
 	MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
 	TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
 	SortTuple	stup;
+	Size		tuplen;
 
 	/*
 	 * Pass-by-value types or null values are just stored directly in
@@ -961,17 +962,26 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
 		stup.datum1 = !isNull ? val : (Datum) 0;
 		stup.isnull1 = isNull;
 		stup.tuple = NULL;		/* no separate storage */
+		tuplen = 0;
 	}
 	else
 	{
 		stup.isnull1 = false;
 		stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
 		stup.tuple = DatumGetPointer(stup.datum1);
+
+		/* GetMemoryChunkSpace is not supported for bump contexts */
+		if (TupleSortUseBumpTupleCxt(base->sortopt))
+			tuplen = MAXALIGN(datumGetSize(PointerGetDatum(stup.tuple),
+										   false,
+										   arg->datumTypeLen));
+		else
+			tuplen = GetMemoryChunkSpace(stup.tuple);
 	}
 
 	tuplesort_puttuple_common(state, &stup,
 							  base->tuples &&
-							  base->sortKeys->abbrev_converter && !isNull, 0);
+							  base->sortKeys->abbrev_converter && !isNull, tuplen);
 
 	MemoryContextSwitchTo(oldcontext);
 }
-- 
2.55.0

