From 3894e6e02c4b7364bc57498ed165f37dda4dba63 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Mon, 30 Apr 2018 12:28:54 -0700
Subject: [PATCH] Don't truncate away non-key attributes for leftmost
 downlinks.

nbtsort.c does not need to truncate away non-key attributes for the
minimum key of the leftmost page on a level, since this is only used to
build a minus infinity downlink for the level's leftmost page.
Truncating away non-key attributes in advance of truncating away all
attributes in _bt_sortaddtup() does not affect the correctness of CREATE
INDEX, but it is misleading.

Author: Peter Geoghegan
---
 src/backend/access/nbtree/nbtsort.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 0587e42573..e012df596e 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -934,7 +934,10 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
 			state->btps_next = _bt_pagestate(wstate, state->btps_level + 1);
 
 		Assert(BTreeTupleGetNAtts(state->btps_minkey, wstate->index) ==
-			   IndexRelationGetNumberOfKeyAttributes(wstate->index));
+			   IndexRelationGetNumberOfKeyAttributes(wstate->index) ||
+			   P_LEFTMOST(opageop));
+		Assert(BTreeTupleGetNAtts(state->btps_minkey, wstate->index) == 0 ||
+			   !P_LEFTMOST(opageop));
 		BTreeInnerTupleSetDownLink(state->btps_minkey, oblkno);
 		_bt_buildadd(wstate, state->btps_next, state->btps_minkey);
 		pfree(state->btps_minkey);
@@ -974,24 +977,16 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
 	 * If the new item is the first for its page, stash a copy for later. Note
 	 * this will only happen for the first item on a level; on later pages,
 	 * the first item for a page is copied from the prior page in the code
-	 * above.
+	 * above.  Since the minimum key for an entire level is only used as a
+	 * minus infinity downlink, and never as a high key, there is no need to
+	 * truncate away non-key attributes at this point.
 	 */
 	if (last_off == P_HIKEY)
 	{
-		BTPageOpaque npageop;
-
 		Assert(state->btps_minkey == NULL);
-
-		npageop = (BTPageOpaque) PageGetSpecialPointer(npage);
-
-		/*
-		 * Truncate included attributes of the tuple that we're going to
-		 * insert into the parent page as a downlink
-		 */
-		if (indnkeyatts != indnatts && P_ISLEAF(npageop))
-			state->btps_minkey = _bt_nonkey_truncate(wstate->index, itup);
-		else
-			state->btps_minkey = CopyIndexTuple(itup);
+		state->btps_minkey = CopyIndexTuple(itup);
+		/* _bt_sortaddtup() will perform full truncation later */
+		BTreeTupleSetNAtts(state->btps_minkey, 0);
 	}
 
 	/*
@@ -1044,7 +1039,10 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
 		else
 		{
 			Assert(BTreeTupleGetNAtts(s->btps_minkey, wstate->index) ==
-				   IndexRelationGetNumberOfKeyAttributes(wstate->index));
+				   IndexRelationGetNumberOfKeyAttributes(wstate->index) ||
+				   P_LEFTMOST(opaque));
+			Assert(BTreeTupleGetNAtts(s->btps_minkey, wstate->index) == 0 ||
+				   !P_LEFTMOST(opaque));
 			BTreeInnerTupleSetDownLink(s->btps_minkey, blkno);
 			_bt_buildadd(wstate, s->btps_next, s->btps_minkey);
 			pfree(s->btps_minkey);
-- 
2.14.1

