From 2c90e8c6cf96c11caafd33c9dc5d9f20d6159ab4 Mon Sep 17 00:00:00 2001
From: Amit Khandekar <amit.khandekar@enterprisedb.com>
Date: Tue, 9 Oct 2018 20:26:48 +0530
Subject: [PATCH v14 3/7] Use separate tuple table slot to return tuples from
 reorder queue.

Index scan uses reorder queue in some cases. Tuples are stored reorder
queue as heap tuples without any associated buffer. While returning a
tuple from reorder queue, IndexNextWithReorder() should use
TupleTableSlot of type HeapTupleTableSlot. A tuple returned directly
from an index scan has a buffer associated with it, so should use
TupleTableSlot of type BufferHeapTupleTableSlot. So, use different
kinds of slots for an index scan.

Author: Ashutosh Bapat
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de
---
 src/backend/executor/nodeIndexscan.c | 18 ++++++++++++------
 src/include/nodes/execnodes.h        |  1 +
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 83038e31f66..bad2ce7ec56 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -208,8 +208,6 @@ IndexNextWithReorder(IndexScanState *node)
 
 	scandesc = node->iss_ScanDesc;
 	econtext = node->ss.ps.ps_ExprContext;
-	slot = node->ss.ss_ScanTupleSlot;
-
 	if (scandesc == NULL)
 	{
 		/*
@@ -245,6 +243,7 @@ IndexNextWithReorder(IndexScanState *node)
 		 */
 		if (!pairingheap_is_empty(node->iss_ReorderQueue))
 		{
+			slot = node->iss_ReorderQueueSlot;
 			topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
 
 			if (node->iss_ReachedEnd ||
@@ -264,13 +263,15 @@ IndexNextWithReorder(IndexScanState *node)
 		else if (node->iss_ReachedEnd)
 		{
 			/* Queue is empty, and no more tuples from index.  We're done. */
-			return ExecClearTuple(slot);
+			ExecClearTuple(node->iss_ReorderQueueSlot);
+			return ExecClearTuple(node->ss.ss_ScanTupleSlot);
 		}
 
 		/*
 		 * Fetch next tuple from the index.
 		 */
 next_indextuple:
+		slot = node->ss.ss_ScanTupleSlot;
 		tuple = index_getnext(scandesc, ForwardScanDirection);
 		if (!tuple)
 		{
@@ -372,7 +373,8 @@ next_indextuple:
 	 * if we get here it means the index scan failed so we are at the end of
 	 * the scan..
 	 */
-	return ExecClearTuple(slot);
+	ExecClearTuple(node->iss_ReorderQueueSlot);
+	return ExecClearTuple(node->ss.ss_ScanTupleSlot);
 }
 
 /*
@@ -946,7 +948,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 	 */
 	ExecInitScanTupleSlot(estate, &indexstate->ss,
 						  RelationGetDescr(currentRelation),
-						  &TTSOpsBufferTuple); /* FIXME: wrong for reorder case */
+						  &TTSOpsBufferTuple);
 
 	/*
 	 * Initialize result type and projection.
@@ -1077,9 +1079,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 		indexstate->iss_OrderByNulls = (bool *)
 			palloc(numOrderByKeys * sizeof(bool));
 
-		/* and initialize the reorder queue */
+		/* and initialize the reorder queue and the corresponding slot */
 		indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
 															indexstate);
+		indexstate->iss_ReorderQueueSlot =
+			ExecAllocTableSlot(&estate->es_tupleTable,
+							   RelationGetDescr(currentRelation),
+							   &TTSOpsHeapTuple);
 	}
 
 	/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index d0e8cbddac4..59fb3c15833 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1365,6 +1365,7 @@ typedef struct IndexScanState
 	bool	   *iss_OrderByTypByVals;
 	int16	   *iss_OrderByTypLens;
 	Size		iss_PscanLen;
+	TupleTableSlot *iss_ReorderQueueSlot;
 } IndexScanState;
 
 /* ----------------
-- 
2.18.0.rc2.dirty

