From a8a7c9ec4f0b96ed9d889d008731864f3d4e87d1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 3 Apr 2022 09:41:04 +1200
Subject: [PATCH] WIP: Fix tuplesort optimizations for expression-based
 CLUSTER.

---
 src/backend/utils/sort/tuplesort.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 361527098f..34714d9baf 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -268,6 +268,8 @@ struct Tuplesortstate
 	MemoryContext tuplecontext; /* sub-context of sortcontext for tuple data */
 	LogicalTapeSet *tapeset;	/* logtape.c object for tapes in a temp file */
 
+	bool		disable_datum1;	/* disable leading value-based optimizations */
+
 	/*
 	 * These function pointers decouple the routines that must know what kind
 	 * of tuple we are sorting from the routines that don't need to know it.
@@ -1095,6 +1097,13 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
 
 	state->indexInfo = BuildIndexInfo(indexRel);
 
+	/*
+	 * If we don't have a simple attribute, disable the use of datum1/isnull1.
+	 * copytup_cluster() doesn't know how to compute expressions.
+	 */
+	if (state->indexInfo->ii_IndexAttrNumbers[0] == 0)
+		state->disable_datum1 = true;
+
 	state->tupDesc = tupDesc;	/* assume we need not copy tupDesc */
 
 	indexScanKey = _bt_mkscankey(indexRel, NULL);
@@ -3593,20 +3602,27 @@ tuplesort_sort_memtuples(Tuplesortstate *state)
 
 	if (state->memtupcount > 1)
 	{
-		/* Do we have a specialization for the leading column's comparator? */
+		/*
+		 * Do we have a specialization for the leading column's comparator,
+		 * and has the leading column's value or abbreviation been stored in
+		 * datum1/isnull1?
+		 */
 		if (state->sortKeys &&
+			!state->disable_datum1 &&
 			state->sortKeys[0].comparator == ssup_datum_unsigned_cmp)
 		{
 			elog(DEBUG1, "qsort_tuple_unsigned");
 			qsort_tuple_unsigned(state->memtuples, state->memtupcount, state);
 		}
 		else if (state->sortKeys &&
+				 !state->disable_datum1 &&
 				 state->sortKeys[0].comparator == ssup_datum_signed_cmp)
 		{
 			elog(DEBUG1, "qsort_tuple_signed");
 			qsort_tuple_signed(state->memtuples, state->memtupcount, state);
 		}
 		else if (state->sortKeys &&
+				 !state->disable_datum1 &&
 				 state->sortKeys[0].comparator == ssup_datum_int32_cmp)
 		{
 			elog(DEBUG1, "qsort_tuple_int32");
@@ -4134,7 +4150,7 @@ copytup_cluster(Tuplesortstate *state, SortTuple *stup, void *tup)
 	 * set up first-column key value, and potentially abbreviate, if it's a
 	 * simple column
 	 */
-	if (state->indexInfo->ii_IndexAttrNumbers[0] == 0)
+	if (state->disable_datum1)
 		return;
 
 	original = heap_getattr(tuple,
-- 
2.35.1

