From ba69019340ad853f7d0ab4cb696ec32d5f361733 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Tue, 21 Jun 2022 14:13:56 +0300
Subject: [PATCH 3/6] Put abbreviation logic into puttuple_common()

Abbreviation code is very similar along tuplesort_put*() functions.  This
commit unifies that code and puts it into puttuple_common().  tuplesort_put*()
functions differs in the abbreviation condition, so it has been added as an
argument to the puttuple_common() function.
---
 src/backend/utils/sort/tuplesort.c | 222 ++++++++---------------------
 1 file changed, 56 insertions(+), 166 deletions(-)

diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 8b6b2bc1d38..828efe701e5 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -616,7 +616,8 @@ static Tuplesortstate *tuplesort_begin_common(int workMem,
 											  SortCoordinate coordinate,
 											  int sortopt);
 static void tuplesort_begin_batch(Tuplesortstate *state);
-static void puttuple_common(Tuplesortstate *state, SortTuple *tuple);
+static void puttuple_common(Tuplesortstate *state, SortTuple *tuple,
+							bool useAbbrev);
 static bool consider_abort_common(Tuplesortstate *state);
 static void inittapes(Tuplesortstate *state, bool mergeruns);
 static void inittapestate(Tuplesortstate *state, int maxTapes);
@@ -1841,7 +1842,6 @@ tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
 {
 	MemoryContext oldcontext = MemoryContextSwitchTo(state->tuplecontext);
 	SortTuple	stup;
-	Datum		original;
 	MinimalTuple tuple;
 	HeapTupleData htup;
 
@@ -1852,51 +1852,15 @@ tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
 	/* set up first-column key value */
 	htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
 	htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
-	original = heap_getattr(&htup,
-							state->sortKeys[0].ssup_attno,
-							state->tupDesc,
-							&stup.isnull1);
+	stup.datum1 = heap_getattr(&htup,
+							   state->sortKeys[0].ssup_attno,
+							   state->tupDesc,
+							   &stup.isnull1);
 
 	MemoryContextSwitchTo(state->sortcontext);
 
-	if (!state->sortKeys->abbrev_converter || stup.isnull1)
-	{
-		/*
-		 * Store ordinary Datum representation, or NULL value.  If there is a
-		 * converter it won't expect NULL values, and cost model is not
-		 * required to account for NULL, so in that case we avoid calling
-		 * converter and just set datum1 to zeroed representation (to be
-		 * consistent, and to support cheap inequality tests for NULL
-		 * abbreviated keys).
-		 */
-		stup.datum1 = original;
-	}
-	else if (!consider_abort_common(state))
-	{
-		/* Store abbreviated key representation */
-		stup.datum1 = state->sortKeys->abbrev_converter(original,
-														state->sortKeys);
-	}
-	else
-	{
-		/* Abort abbreviation */
-		int			i;
-
-		stup.datum1 = original;
-
-		/*
-		 * Set state to be consistent with never trying abbreviation.
-		 *
-		 * Alter datum1 representation in already-copied tuples, so as to
-		 * ensure a consistent representation (current tuple was just
-		 * handled).  It does not matter if some dumped tuples are already
-		 * sorted on tape, since serialized tuples lack abbreviated keys
-		 * (TSS_BUILDRUNS state prevents control reaching here in any case).
-		 */
-		REMOVEABBREV(state, state->memtuples, state->memtupcount);
-	}
-
-	puttuple_common(state, &stup);
+	puttuple_common(state, &stup,
+					state->sortKeys->abbrev_converter && !stup.isnull1);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -1910,7 +1874,6 @@ void
 tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
 {
 	SortTuple	stup;
-	Datum		original;
 	MemoryContext oldcontext = MemoryContextSwitchTo(state->tuplecontext);
 
 	/* copy the tuple into sort storage */
@@ -1926,51 +1889,14 @@ tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
 	 */
 	if (state->haveDatum1)
 	{
-		original = heap_getattr(tup,
-								state->indexInfo->ii_IndexAttrNumbers[0],
-								state->tupDesc,
-								&stup.isnull1);
-
-		if (!state->sortKeys->abbrev_converter || stup.isnull1)
-		{
-			/*
-			 * Store ordinary Datum representation, or NULL value.  If there
-			 * is a converter it won't expect NULL values, and cost model is
-			 * not required to account for NULL, so in that case we avoid
-			 * calling converter and just set datum1 to zeroed representation
-			 * (to be consistent, and to support cheap inequality tests for
-			 * NULL abbreviated keys).
-			 */
-			stup.datum1 = original;
-		}
-		else if (!consider_abort_common(state))
-		{
-			/* Store abbreviated key representation */
-			stup.datum1 = state->sortKeys->abbrev_converter(original,
-															state->sortKeys);
-		}
-		else
-		{
-			/* Abort abbreviation */
-			int			i;
-
-			stup.datum1 = original;
-
-			/*
-			 * Set state to be consistent with never trying abbreviation.
-			 *
-			 * Alter datum1 representation in already-copied tuples, so as to
-			 * ensure a consistent representation (current tuple was just
-			 * handled).  It does not matter if some dumped tuples are already
-			 * sorted on tape, since serialized tuples lack abbreviated keys
-			 * (TSS_BUILDRUNS state prevents control reaching here in any
-			 * case).
-			 */
-			REMOVEABBREV(state, state->memtuples, state->memtupcount);
-		}
+		stup.datum1 = heap_getattr(tup,
+								   state->indexInfo->ii_IndexAttrNumbers[0],
+								   state->tupDesc,
+								   &stup.isnull1);
 	}
 
-	puttuple_common(state, &stup);
+	puttuple_common(state, &stup,
+					state->haveDatum1 && state->sortKeys->abbrev_converter && !stup.isnull1);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -1986,7 +1912,6 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
 {
 	MemoryContext oldcontext;
 	SortTuple	stup;
-	Datum		original;
 	IndexTuple	tuple;
 
 	stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
@@ -1995,51 +1920,15 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
 	tuple->t_tid = *self;
 	USEMEM(state, GetMemoryChunkSpace(stup.tuple));
 	/* set up first-column key value */
-	original = index_getattr(tuple,
-							 1,
-							 RelationGetDescr(state->indexRel),
-							 &stup.isnull1);
+	stup.datum1 = index_getattr(tuple,
+								1,
+								RelationGetDescr(state->indexRel),
+								&stup.isnull1);
 
 	oldcontext = MemoryContextSwitchTo(state->sortcontext);
 
-	if (!state->sortKeys || !state->sortKeys->abbrev_converter || stup.isnull1)
-	{
-		/*
-		 * Store ordinary Datum representation, or NULL value.  If there is a
-		 * converter it won't expect NULL values, and cost model is not
-		 * required to account for NULL, so in that case we avoid calling
-		 * converter and just set datum1 to zeroed representation (to be
-		 * consistent, and to support cheap inequality tests for NULL
-		 * abbreviated keys).
-		 */
-		stup.datum1 = original;
-	}
-	else if (!consider_abort_common(state))
-	{
-		/* Store abbreviated key representation */
-		stup.datum1 = state->sortKeys->abbrev_converter(original,
-														state->sortKeys);
-	}
-	else
-	{
-		/* Abort abbreviation */
-		int			i;
-
-		stup.datum1 = original;
-
-		/*
-		 * Set state to be consistent with never trying abbreviation.
-		 *
-		 * Alter datum1 representation in already-copied tuples, so as to
-		 * ensure a consistent representation (current tuple was just
-		 * handled).  It does not matter if some dumped tuples are already
-		 * sorted on tape, since serialized tuples lack abbreviated keys
-		 * (TSS_BUILDRUNS state prevents control reaching here in any case).
-		 */
-		REMOVEABBREV(state, state->memtuples, state->memtupcount);
-	}
-
-	puttuple_common(state, &stup);
+	puttuple_common(state, &stup,
+					state->sortKeys && state->sortKeys->abbrev_converter && !stup.isnull1);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -2080,45 +1969,15 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
 	}
 	else
 	{
-		Datum		original = datumCopy(val, false, state->datumTypeLen);
-
 		stup.isnull1 = false;
-		stup.tuple = DatumGetPointer(original);
+		stup.datum1 = datumCopy(val, false, state->datumTypeLen);
+		stup.tuple = DatumGetPointer(stup.datum1);
 		USEMEM(state, GetMemoryChunkSpace(stup.tuple));
 		MemoryContextSwitchTo(state->sortcontext);
-
-		if (!state->sortKeys->abbrev_converter)
-		{
-			stup.datum1 = original;
-		}
-		else if (!consider_abort_common(state))
-		{
-			/* Store abbreviated key representation */
-			stup.datum1 = state->sortKeys->abbrev_converter(original,
-															state->sortKeys);
-		}
-		else
-		{
-			/* Abort abbreviation */
-			int			i;
-
-			stup.datum1 = original;
-
-			/*
-			 * Set state to be consistent with never trying abbreviation.
-			 *
-			 * Alter datum1 representation in already-copied tuples, so as to
-			 * ensure a consistent representation (current tuple was just
-			 * handled).  It does not matter if some dumped tuples are already
-			 * sorted on tape, since serialized tuples lack abbreviated keys
-			 * (TSS_BUILDRUNS state prevents control reaching here in any
-			 * case).
-			 */
-			REMOVEABBREV(state, state->memtuples, state->memtupcount);
-		}
 	}
 
-	puttuple_common(state, &stup);
+	puttuple_common(state, &stup,
+					state->tuples && !isNull && state->sortKeys->abbrev_converter);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -2127,10 +1986,41 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
  * Shared code for tuple and datum cases.
  */
 static void
-puttuple_common(Tuplesortstate *state, SortTuple *tuple)
+puttuple_common(Tuplesortstate *state, SortTuple *tuple, bool useAbbrev)
 {
 	Assert(!LEADER(state));
 
+	if (!useAbbrev)
+	{
+		/*
+		 * Leave ordinary Datum representation, or NULL value.  If there is a
+		 * converter it won't expect NULL values, and cost model is not
+		 * required to account for NULL, so in that case we avoid calling
+		 * converter and just set datum1 to zeroed representation (to be
+		 * consistent, and to support cheap inequality tests for NULL
+		 * abbreviated keys).
+		 */
+	}
+	else if (!consider_abort_common(state))
+	{
+		/* Store abbreviated key representation */
+		tuple->datum1 = state->sortKeys->abbrev_converter(tuple->datum1,
+														  state->sortKeys);
+	}
+	else
+	{
+		/*
+		 * Set state to be consistent with never trying abbreviation.
+		 *
+		 * Alter datum1 representation in already-copied tuples, so as to
+		 * ensure a consistent representation (current tuple was just
+		 * handled).  It does not matter if some dumped tuples are already
+		 * sorted on tape, since serialized tuples lack abbreviated keys
+		 * (TSS_BUILDRUNS state prevents control reaching here in any case).
+		 */
+		REMOVEABBREV(state, state->memtuples, state->memtupcount);
+	}
+
 	switch (state->status)
 	{
 		case TSS_INITIAL:
-- 
2.24.3 (Apple Git-128)

