From 7f13603d7a37dae59ca5d08346d79e67e5d3fe4e Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Thu, 7 Apr 2022 12:30:00 +0200
Subject: [PATCH v5 2/8] Use specialized attribute iterators in
 backend/*/nbt*_spec.h

Split out for making it clear what substantial changes were made to the
pre-existing functions.

Even though not all nbt*_spec functions have been updated; most call sites
now can directly call the specialized functions instead of having to determine
the right specialization based on the (potentially locally unavailable) index
relation, making the specialization of those functions worth the effort.
---
 src/backend/access/nbtree/nbtsearch_spec.h | 16 +++---
 src/backend/access/nbtree/nbtsort_spec.h   | 24 +++++----
 src/backend/access/nbtree/nbtutils_spec.h  | 63 +++++++++++++---------
 3 files changed, 62 insertions(+), 41 deletions(-)

diff --git a/src/backend/access/nbtree/nbtsearch_spec.h b/src/backend/access/nbtree/nbtsearch_spec.h
index 73d5370496..a5c5f2b94f 100644
--- a/src/backend/access/nbtree/nbtsearch_spec.h
+++ b/src/backend/access/nbtree/nbtsearch_spec.h
@@ -823,6 +823,7 @@ NBTS_FUNCTION(_bt_compare)(Relation rel,
 	int			ncmpkey;
 	int			ntupatts;
 	int32		result;
+	nbts_attiterdeclare(itup);
 
 	Assert(_bt_check_natts(rel, key->heapkeyspace, page, offnum));
 	Assert(key->keysz <= IndexRelationGetNumberOfKeyAttributes(rel));
@@ -854,23 +855,26 @@ NBTS_FUNCTION(_bt_compare)(Relation rel,
 	Assert(key->heapkeyspace || ncmpkey == key->keysz);
 	Assert(!BTreeTupleIsPosting(itup) || key->allequalimage);
 	scankey = key->scankeys;
-	for (int i = 1; i <= ncmpkey; i++)
+	nbts_attiterinit(itup, 1, itupdesc);
+
+	nbts_foreachattr(1, ncmpkey)
 	{
 		Datum		datum;
-		bool		isNull;
 
-		datum = index_getattr(itup, scankey->sk_attno, itupdesc, &isNull);
+		datum = nbts_attiter_nextattdatum(itup, itupdesc);
 
-		if (scankey->sk_flags & SK_ISNULL)	/* key is NULL */
+		/* key is NULL */
+		if (scankey->sk_flags & SK_ISNULL)
 		{
-			if (isNull)
+			if (nbts_attiter_curattisnull(itup))
 				result = 0;		/* NULL "=" NULL */
 			else if (scankey->sk_flags & SK_BT_NULLS_FIRST)
 				result = -1;	/* NULL "<" NOT_NULL */
 			else
 				result = 1;		/* NULL ">" NOT_NULL */
 		}
-		else if (isNull)		/* key is NOT_NULL and item is NULL */
+		/* key is NOT_NULL and item is NULL */
+		else if (nbts_attiter_curattisnull(itup))
 		{
 			if (scankey->sk_flags & SK_BT_NULLS_FIRST)
 				result = 1;		/* NOT_NULL ">" NULL */
diff --git a/src/backend/access/nbtree/nbtsort_spec.h b/src/backend/access/nbtree/nbtsort_spec.h
index 8f4a3602ca..d3f2db2dc4 100644
--- a/src/backend/access/nbtree/nbtsort_spec.h
+++ b/src/backend/access/nbtree/nbtsort_spec.h
@@ -27,8 +27,7 @@ NBTS_FUNCTION(_bt_load)(BTWriteState *wstate, BTSpool *btspool,
 				itup2 = NULL;
 	bool		load1;
 	TupleDesc	tupdes = RelationGetDescr(wstate->index);
-	int			i,
-				keysz = IndexRelationGetNumberOfKeyAttributes(wstate->index);
+	int			keysz = IndexRelationGetNumberOfKeyAttributes(wstate->index);
 	SortSupport sortKeys;
 	int64		tuples_done = 0;
 	bool		deduplicate;
@@ -50,7 +49,7 @@ NBTS_FUNCTION(_bt_load)(BTWriteState *wstate, BTSpool *btspool,
 		/* Prepare SortSupport data for each column */
 		sortKeys = (SortSupport) palloc0(keysz * sizeof(SortSupportData));
 
-		for (i = 0; i < keysz; i++)
+		for (int i = 0; i < keysz; i++)
 		{
 			SortSupport sortKey = sortKeys + i;
 			ScanKey		scanKey = wstate->inskey->scankeys + i;
@@ -82,22 +81,25 @@ NBTS_FUNCTION(_bt_load)(BTWriteState *wstate, BTSpool *btspool,
 			}
 			else if (itup != NULL)
 			{
+				nbts_attiterdeclare(itup);
+				nbts_attiterdeclare(itup2);
 				int32		compare = 0;
 
-				for (i = 1; i <= keysz; i++)
+				nbts_attiterinit(itup, 1, tupdes);
+				nbts_attiterinit(itup2, 1, tupdes);
+
+				nbts_foreachattr(1, keysz)
 				{
 					SortSupport entry;
 					Datum		attrDatum1,
 								attrDatum2;
-					bool		isNull1,
-								isNull2;
 
-					entry = sortKeys + i - 1;
-					attrDatum1 = index_getattr(itup, i, tupdes, &isNull1);
-					attrDatum2 = index_getattr(itup2, i, tupdes, &isNull2);
+					entry = sortKeys + nbts_attiter_attnum - 1;
+					attrDatum1 = nbts_attiter_nextattdatum(itup, tupdes);
+					attrDatum2 = nbts_attiter_nextattdatum(itup2, tupdes);
 
-					compare = ApplySortComparator(attrDatum1, isNull1,
-												  attrDatum2, isNull2,
+					compare = ApplySortComparator(attrDatum1, nbts_attiter_curattisnull(itup),
+												  attrDatum2, nbts_attiter_curattisnull(itup2),
 												  entry);
 					if (compare > 0)
 					{
diff --git a/src/backend/access/nbtree/nbtutils_spec.h b/src/backend/access/nbtree/nbtutils_spec.h
index a4b934ae7a..638eff18f6 100644
--- a/src/backend/access/nbtree/nbtutils_spec.h
+++ b/src/backend/access/nbtree/nbtutils_spec.h
@@ -211,6 +211,8 @@ NBTS_FUNCTION(_bt_keep_natts)(Relation rel, IndexTuple lastleft,
 	TupleDesc	itupdesc = RelationGetDescr(rel);
 	int			keepnatts;
 	ScanKey		scankey;
+	nbts_attiterdeclare(lastleft);
+	nbts_attiterdeclare(firstright);
 
 	/*
 	 * _bt_compare() treats truncated key attributes as having the value minus
@@ -222,20 +224,22 @@ NBTS_FUNCTION(_bt_keep_natts)(Relation rel, IndexTuple lastleft,
 
 	scankey = itup_key->scankeys;
 	keepnatts = 1;
-	for (int attnum = 1; attnum <= nkeyatts; attnum++, scankey++)
+
+	nbts_attiterinit(lastleft, 1, itupdesc);
+	nbts_attiterinit(firstright, 1, itupdesc);
+
+	nbts_foreachattr(1, nkeyatts)
 	{
 		Datum		datum1,
 					datum2;
-		bool		isNull1,
-					isNull2;
 
-		datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1);
-		datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2);
+		datum1 = nbts_attiter_nextattdatum(lastleft, itupdesc);
+		datum2 = nbts_attiter_nextattdatum(firstright, itupdesc);
 
-		if (isNull1 != isNull2)
+		if (nbts_attiter_curattisnull(lastleft) != nbts_attiter_curattisnull(firstright))
 			break;
 
-		if (!isNull1 &&
+		if (!nbts_attiter_curattisnull(lastleft) &&
 			DatumGetInt32(FunctionCall2Coll(&scankey->sk_func,
 											scankey->sk_collation,
 											datum1,
@@ -243,6 +247,7 @@ NBTS_FUNCTION(_bt_keep_natts)(Relation rel, IndexTuple lastleft,
 			break;
 
 		keepnatts++;
+		scankey++;
 	}
 
 	/*
@@ -295,7 +300,7 @@ NBTS_FUNCTION(_bt_mkscankey)(Relation rel, IndexTuple itup)
 	int			indnkeyatts;
 	int16	   *indoption;
 	int			tupnatts;
-	int			i;
+	nbts_attiterdeclare(itup);
 
 	itupdesc = RelationGetDescr(rel);
 	indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
@@ -326,7 +331,10 @@ NBTS_FUNCTION(_bt_mkscankey)(Relation rel, IndexTuple itup)
 	key->scantid = key->heapkeyspace && itup ?
 				   BTreeTupleGetHeapTID(itup) : NULL;
 	skey = key->scankeys;
-	for (i = 0; i < indnkeyatts; i++)
+
+	nbts_attiterinit(itup, 1, itupdesc);
+
+	nbts_foreachattr(1, indnkeyatts)
 	{
 		FmgrInfo   *procinfo;
 		Datum		arg;
@@ -337,27 +345,30 @@ NBTS_FUNCTION(_bt_mkscankey)(Relation rel, IndexTuple itup)
 		 * We can use the cached (default) support procs since no cross-type
 		 * comparison can be needed.
 		 */
-		procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
+		procinfo = index_getprocinfo(rel, nbts_attiter_attnum, BTORDER_PROC);
 
 		/*
 		 * Key arguments built from truncated attributes (or when caller
 		 * provides no tuple) are defensively represented as NULL values. They
 		 * should never be used.
 		 */
-		if (i < tupnatts)
-			arg = index_getattr(itup, i + 1, itupdesc, &null);
+		if (nbts_attiter_attnum <= tupnatts)
+		{
+			arg = nbts_attiter_nextattdatum(itup, itupdesc);
+			null = nbts_attiter_curattisnull(itup);
+		}
 		else
 		{
 			arg = (Datum) 0;
 			null = true;
 		}
-		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
-		ScanKeyEntryInitializeWithInfo(&skey[i],
+		flags = (null ? SK_ISNULL : 0) | (indoption[nbts_attiter_attnum - 1] << SK_BT_INDOPTION_SHIFT);
+		ScanKeyEntryInitializeWithInfo(&skey[nbts_attiter_attnum - 1],
 									   flags,
-									   (AttrNumber) (i + 1),
+									   (AttrNumber) nbts_attiter_attnum,
 									   InvalidStrategy,
 									   InvalidOid,
-									   rel->rd_indcollation[i],
+									   rel->rd_indcollation[nbts_attiter_attnum - 1],
 									   procinfo,
 									   arg);
 		/* Record if any key attribute is NULL (or truncated) */
@@ -744,24 +755,28 @@ NBTS_FUNCTION(_bt_keep_natts_fast)(Relation rel,
 	TupleDesc	itupdesc = RelationGetDescr(rel);
 	int			keysz = IndexRelationGetNumberOfKeyAttributes(rel);
 	int			keepnatts;
+	nbts_attiterdeclare(lastleft);
+	nbts_attiterdeclare(firstright);
 
 	keepnatts = 1;
-	for (int attnum = 1; attnum <= keysz; attnum++)
+	nbts_attiterinit(lastleft, 1, itupdesc);
+	nbts_attiterinit(firstright, 1, itupdesc);
+
+	nbts_foreachattr(1, keysz)
 	{
 		Datum		datum1,
 					datum2;
-		bool		isNull1,
-					isNull2;
 		Form_pg_attribute att;
 
-		datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1);
-		datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2);
-		att = TupleDescAttr(itupdesc, attnum - 1);
+		datum1 = nbts_attiter_nextattdatum(lastleft,itupdesc);
+		datum2 = nbts_attiter_nextattdatum(firstright, itupdesc);
+		att = TupleDescAttr(itupdesc, nbts_attiter_attnum - 1);
 
-		if (isNull1 != isNull2)
+		if (nbts_attiter_curattisnull(lastleft) !=
+			nbts_attiter_curattisnull(firstright))
 			break;
 
-		if (!isNull1 &&
+		if (!nbts_attiter_curattisnull(lastleft) &&
 			!datum_image_eq(datum1, datum2, att->attbyval, att->attlen))
 			break;
 
-- 
2.30.2

