From b6d92d8a8d0fc0826de0c1618540e04b4255989d Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Wed, 27 Dec 2017 13:03:24 +1100
Subject: [PATCH 08/11] Remove HeapScanDesc usage outside heap

HeapScanDesc is divided into two scan descriptors.
StorageScanDesc and HeapPageScanDesc.

StorageScanDesc has common members that are should
be available across all the storage routines and
HeapPageScanDesc is avaiable only for the storage
routine that supports Heap storage with page format.
The HeapPageScanDesc is used internally by the heapam
storage routine and also this is exposed to Bitmap Heap
and Sample scan's as they depend on the Heap page format.

while generating the Bitmap Heap and Sample scan's,
the planner now checks whether the storage routine
supports returning HeapPageScanDesc or not? Based on
this decision, the planner plans above two plans.
---
 contrib/pgrowlocks/pgrowlocks.c            |   4 +-
 contrib/pgstattuple/pgstattuple.c          |  10 +-
 contrib/tsm_system_rows/tsm_system_rows.c  |  18 +-
 contrib/tsm_system_time/tsm_system_time.c  |   8 +-
 src/backend/access/heap/heapam.c           | 424 +++++++++++++++--------------
 src/backend/access/heap/heapam_storage.c   |  53 ++++
 src/backend/access/index/genam.c           |   4 +-
 src/backend/access/storage/storageam.c     |  51 +++-
 src/backend/access/tablesample/system.c    |   2 +-
 src/backend/bootstrap/bootstrap.c          |   4 +-
 src/backend/catalog/aclchk.c               |   4 +-
 src/backend/catalog/index.c                |   8 +-
 src/backend/catalog/partition.c            |   2 +-
 src/backend/catalog/pg_conversion.c        |   2 +-
 src/backend/catalog/pg_db_role_setting.c   |   2 +-
 src/backend/catalog/pg_publication.c       |   2 +-
 src/backend/catalog/pg_subscription.c      |   2 +-
 src/backend/commands/cluster.c             |   4 +-
 src/backend/commands/copy.c                |   2 +-
 src/backend/commands/dbcommands.c          |   6 +-
 src/backend/commands/indexcmds.c           |   2 +-
 src/backend/commands/tablecmds.c           |  10 +-
 src/backend/commands/tablespace.c          |  10 +-
 src/backend/commands/typecmds.c            |   4 +-
 src/backend/commands/vacuum.c              |   4 +-
 src/backend/executor/nodeBitmapHeapscan.c  |  69 +++--
 src/backend/executor/nodeSamplescan.c      |  50 ++--
 src/backend/executor/nodeSeqscan.c         |   5 +-
 src/backend/optimizer/util/plancat.c       |   4 +-
 src/backend/postmaster/autovacuum.c        |   4 +-
 src/backend/postmaster/pgstat.c            |   2 +-
 src/backend/replication/logical/launcher.c |   2 +-
 src/backend/rewrite/rewriteDefine.c        |   2 +-
 src/backend/utils/init/postinit.c          |   2 +-
 src/include/access/heapam.h                |  36 +--
 src/include/access/relscan.h               |  47 ++--
 src/include/access/storage_common.h        |   1 -
 src/include/access/storageam.h             |  44 +--
 src/include/access/storageamapi.h          |  42 +--
 src/include/nodes/execnodes.h              |   4 +-
 40 files changed, 535 insertions(+), 421 deletions(-)

diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index bc8b423975..762d969ecd 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -56,7 +56,7 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
 typedef struct
 {
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	int			ncolumns;
 } MyData;
 
@@ -71,7 +71,7 @@ Datum
 pgrowlocks(PG_FUNCTION_ARGS)
 {
 	FuncCallContext *funcctx;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	TupleDesc	tupdesc;
 	AttInMetadata *attinmeta;
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index c4b10d6efc..32ac121e92 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -314,7 +314,8 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 static Datum
 pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
+	HeapPageScanDesc pagescan;
 	HeapTuple	tuple;
 	BlockNumber nblocks;
 	BlockNumber block = 0;		/* next block to count free space in */
@@ -328,7 +329,8 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 	scan = storage_beginscan_strat(rel, SnapshotAny, 0, NULL, true, false);
 	InitDirtySnapshot(SnapshotDirty);
 
-	nblocks = scan->rs_nblocks; /* # blocks to be scanned */
+	pagescan = storageam_get_heappagescandesc(scan);
+	nblocks = pagescan->rs_nblocks; /* # blocks to be scanned */
 
 	/* scan the relation */
 	while ((tuple = storage_getnext(scan, ForwardScanDirection)) != NULL)
@@ -364,7 +366,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 			CHECK_FOR_INTERRUPTS();
 
 			buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block,
-										RBM_NORMAL, scan->rs_strategy);
+										RBM_NORMAL, pagescan->rs_strategy);
 			LockBuffer(buffer, BUFFER_LOCK_SHARE);
 			stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer));
 			UnlockReleaseBuffer(buffer);
@@ -377,7 +379,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 		CHECK_FOR_INTERRUPTS();
 
 		buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block,
-									RBM_NORMAL, scan->rs_strategy);
+									RBM_NORMAL, pagescan->rs_strategy);
 		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 		stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer));
 		UnlockReleaseBuffer(buffer);
diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c
index 544458ec91..14120291d0 100644
--- a/contrib/tsm_system_rows/tsm_system_rows.c
+++ b/contrib/tsm_system_rows/tsm_system_rows.c
@@ -71,7 +71,7 @@ static BlockNumber system_rows_nextsampleblock(SampleScanState *node);
 static OffsetNumber system_rows_nextsampletuple(SampleScanState *node,
 							BlockNumber blockno,
 							OffsetNumber maxoffset);
-static bool SampleOffsetVisible(OffsetNumber tupoffset, HeapScanDesc scan);
+static bool SampleOffsetVisible(OffsetNumber tupoffset, HeapPageScanDesc scan);
 static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
 
 
@@ -209,7 +209,7 @@ static BlockNumber
 system_rows_nextsampleblock(SampleScanState *node)
 {
 	SystemRowsSamplerData *sampler = (SystemRowsSamplerData *) node->tsm_state;
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = node->pagescan;
 
 	/* First call within scan? */
 	if (sampler->doneblocks == 0)
@@ -221,14 +221,14 @@ system_rows_nextsampleblock(SampleScanState *node)
 			SamplerRandomState randstate;
 
 			/* If relation is empty, there's nothing to scan */
-			if (scan->rs_nblocks == 0)
+			if (pagescan->rs_nblocks == 0)
 				return InvalidBlockNumber;
 
 			/* We only need an RNG during this setup step */
 			sampler_random_init_state(sampler->seed, randstate);
 
 			/* Compute nblocks/firstblock/step only once per query */
-			sampler->nblocks = scan->rs_nblocks;
+			sampler->nblocks = pagescan->rs_nblocks;
 
 			/* Choose random starting block within the relation */
 			/* (Actually this is the predecessor of the first block visited) */
@@ -258,7 +258,7 @@ system_rows_nextsampleblock(SampleScanState *node)
 	{
 		/* Advance lb, using uint64 arithmetic to forestall overflow */
 		sampler->lb = ((uint64) sampler->lb + sampler->step) % sampler->nblocks;
-	} while (sampler->lb >= scan->rs_nblocks);
+	} while (sampler->lb >= pagescan->rs_nblocks);
 
 	return sampler->lb;
 }
@@ -278,7 +278,7 @@ system_rows_nextsampletuple(SampleScanState *node,
 							OffsetNumber maxoffset)
 {
 	SystemRowsSamplerData *sampler = (SystemRowsSamplerData *) node->tsm_state;
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = node->pagescan;
 	OffsetNumber tupoffset = sampler->lt;
 
 	/* Quit if we've returned all needed tuples */
@@ -291,7 +291,7 @@ system_rows_nextsampletuple(SampleScanState *node,
 	 */
 
 	/* We rely on the data accumulated in pagemode access */
-	Assert(scan->rs_pageatatime);
+	Assert(pagescan->rs_pageatatime);
 	for (;;)
 	{
 		/* Advance to next possible offset on page */
@@ -308,7 +308,7 @@ system_rows_nextsampletuple(SampleScanState *node,
 		}
 
 		/* Found a candidate? */
-		if (SampleOffsetVisible(tupoffset, scan))
+		if (SampleOffsetVisible(tupoffset, pagescan))
 		{
 			sampler->donetuples++;
 			break;
@@ -327,7 +327,7 @@ system_rows_nextsampletuple(SampleScanState *node,
  * so just look at the info it left in rs_vistuples[].
  */
 static bool
-SampleOffsetVisible(OffsetNumber tupoffset, HeapScanDesc scan)
+SampleOffsetVisible(OffsetNumber tupoffset, HeapPageScanDesc scan)
 {
 	int			start = 0,
 				end = scan->rs_ntuples - 1;
diff --git a/contrib/tsm_system_time/tsm_system_time.c b/contrib/tsm_system_time/tsm_system_time.c
index af8d025414..aa7252215a 100644
--- a/contrib/tsm_system_time/tsm_system_time.c
+++ b/contrib/tsm_system_time/tsm_system_time.c
@@ -219,7 +219,7 @@ static BlockNumber
 system_time_nextsampleblock(SampleScanState *node)
 {
 	SystemTimeSamplerData *sampler = (SystemTimeSamplerData *) node->tsm_state;
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = node->pagescan;
 	instr_time	cur_time;
 
 	/* First call within scan? */
@@ -232,14 +232,14 @@ system_time_nextsampleblock(SampleScanState *node)
 			SamplerRandomState randstate;
 
 			/* If relation is empty, there's nothing to scan */
-			if (scan->rs_nblocks == 0)
+			if (pagescan->rs_nblocks == 0)
 				return InvalidBlockNumber;
 
 			/* We only need an RNG during this setup step */
 			sampler_random_init_state(sampler->seed, randstate);
 
 			/* Compute nblocks/firstblock/step only once per query */
-			sampler->nblocks = scan->rs_nblocks;
+			sampler->nblocks = pagescan->rs_nblocks;
 
 			/* Choose random starting block within the relation */
 			/* (Actually this is the predecessor of the first block visited) */
@@ -275,7 +275,7 @@ system_time_nextsampleblock(SampleScanState *node)
 	{
 		/* Advance lb, using uint64 arithmetic to forestall overflow */
 		sampler->lb = ((uint64) sampler->lb + sampler->step) % sampler->nblocks;
-	} while (sampler->lb >= scan->rs_nblocks);
+	} while (sampler->lb >= pagescan->rs_nblocks);
 
 	return sampler->lb;
 }
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 5226f39f1e..90bbed9900 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -220,9 +220,9 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	 * lock that ensures the interesting tuple(s) won't change.)
 	 */
 	if (scan->rs_parallel != NULL)
-		scan->rs_nblocks = scan->rs_parallel->phs_nblocks;
+		scan->rs_pagescan.rs_nblocks = scan->rs_parallel->phs_nblocks;
 	else
-		scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
+		scan->rs_pagescan.rs_nblocks = RelationGetNumberOfBlocks(scan->rs_scan.rs_rd);
 
 	/*
 	 * If the table is large relative to NBuffers, use a bulk-read access
@@ -236,8 +236,8 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	 * Note that heap_parallelscan_initialize has a very similar test; if you
 	 * change this, consider changing that one, too.
 	 */
-	if (!RelationUsesLocalBuffers(scan->rs_rd) &&
-		scan->rs_nblocks > NBuffers / 4)
+	if (!RelationUsesLocalBuffers(scan->rs_scan.rs_rd) &&
+		scan->rs_pagescan.rs_nblocks > NBuffers / 4)
 	{
 		allow_strat = scan->rs_allow_strat;
 		allow_sync = scan->rs_allow_sync;
@@ -248,20 +248,20 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	if (allow_strat)
 	{
 		/* During a rescan, keep the previous strategy object. */
-		if (scan->rs_strategy == NULL)
-			scan->rs_strategy = GetAccessStrategy(BAS_BULKREAD);
+		if (scan->rs_pagescan.rs_strategy == NULL)
+			scan->rs_pagescan.rs_strategy = GetAccessStrategy(BAS_BULKREAD);
 	}
 	else
 	{
-		if (scan->rs_strategy != NULL)
-			FreeAccessStrategy(scan->rs_strategy);
-		scan->rs_strategy = NULL;
+		if (scan->rs_pagescan.rs_strategy != NULL)
+			FreeAccessStrategy(scan->rs_pagescan.rs_strategy);
+		scan->rs_pagescan.rs_strategy = NULL;
 	}
 
 	if (scan->rs_parallel != NULL)
 	{
 		/* For parallel scan, believe whatever ParallelHeapScanDesc says. */
-		scan->rs_syncscan = scan->rs_parallel->phs_syncscan;
+		scan->rs_pagescan.rs_syncscan = scan->rs_parallel->phs_syncscan;
 	}
 	else if (keep_startblock)
 	{
@@ -270,25 +270,25 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 		 * so that rewinding a cursor doesn't generate surprising results.
 		 * Reset the active syncscan setting, though.
 		 */
-		scan->rs_syncscan = (allow_sync && synchronize_seqscans);
+		scan->rs_pagescan.rs_syncscan = (allow_sync && synchronize_seqscans);
 	}
 	else if (allow_sync && synchronize_seqscans)
 	{
-		scan->rs_syncscan = true;
-		scan->rs_startblock = ss_get_location(scan->rs_rd, scan->rs_nblocks);
+		scan->rs_pagescan.rs_syncscan = true;
+		scan->rs_pagescan.rs_startblock = ss_get_location(scan->rs_scan.rs_rd, scan->rs_pagescan.rs_nblocks);
 	}
 	else
 	{
-		scan->rs_syncscan = false;
-		scan->rs_startblock = 0;
+		scan->rs_pagescan.rs_syncscan = false;
+		scan->rs_pagescan.rs_startblock = 0;
 	}
 
-	scan->rs_numblocks = InvalidBlockNumber;
-	scan->rs_inited = false;
+	scan->rs_pagescan.rs_numblocks = InvalidBlockNumber;
+	scan->rs_scan.rs_inited = false;
 	scan->rs_ctup.t_data = NULL;
 	ItemPointerSetInvalid(&scan->rs_ctup.t_self);
-	scan->rs_cbuf = InvalidBuffer;
-	scan->rs_cblock = InvalidBlockNumber;
+	scan->rs_scan.rs_cbuf = InvalidBuffer;
+	scan->rs_scan.rs_cblock = InvalidBlockNumber;
 
 	/* page-at-a-time fields are always invalid when not rs_inited */
 
@@ -296,7 +296,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	 * copy the scan key, if appropriate
 	 */
 	if (key != NULL)
-		memcpy(scan->rs_key, key, scan->rs_nkeys * sizeof(ScanKeyData));
+		memcpy(scan->rs_scan.rs_key, key, scan->rs_scan.rs_nkeys * sizeof(ScanKeyData));
 
 	/*
 	 * Currently, we don't have a stats counter for bitmap heap scans (but the
@@ -304,7 +304,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	 * update stats for tuple fetches there)
 	 */
 	if (!scan->rs_bitmapscan && !scan->rs_samplescan)
-		pgstat_count_heap_scan(scan->rs_rd);
+		pgstat_count_heap_scan(scan->rs_scan.rs_rd);
 }
 
 /*
@@ -314,16 +314,19 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
  * numBlks is number of pages to scan (InvalidBlockNumber means "all")
  */
 void
-heap_setscanlimits(HeapScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
+heap_setscanlimits(StorageScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
 {
-	Assert(!scan->rs_inited);	/* else too late to change */
-	Assert(!scan->rs_syncscan); /* else rs_startblock is significant */
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
+	Assert(!scan->rs_scan.rs_inited);	/* else too late to change */
+	Assert(!scan->rs_pagescan.rs_syncscan); /* else rs_startblock is
+											 * significant */
 
 	/* Check startBlk is valid (but allow case of zero blocks...) */
-	Assert(startBlk == 0 || startBlk < scan->rs_nblocks);
+	Assert(startBlk == 0 || startBlk < scan->rs_pagescan.rs_nblocks);
 
-	scan->rs_startblock = startBlk;
-	scan->rs_numblocks = numBlks;
+	scan->rs_pagescan.rs_startblock = startBlk;
+	scan->rs_pagescan.rs_numblocks = numBlks;
 }
 
 /*
@@ -334,8 +337,9 @@ heap_setscanlimits(HeapScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
  * which tuples on the page are visible.
  */
 void
-heapgetpage(HeapScanDesc scan, BlockNumber page)
+heapgetpage(StorageScanDesc sscan, BlockNumber page)
 {
+	HeapScanDesc scan = (HeapScanDesc) sscan;
 	Buffer		buffer;
 	Snapshot	snapshot;
 	Page		dp;
@@ -345,13 +349,13 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 	ItemId		lpp;
 	bool		all_visible;
 
-	Assert(page < scan->rs_nblocks);
+	Assert(page < scan->rs_pagescan.rs_nblocks);
 
 	/* release previous scan buffer, if any */
-	if (BufferIsValid(scan->rs_cbuf))
+	if (BufferIsValid(scan->rs_scan.rs_cbuf))
 	{
-		ReleaseBuffer(scan->rs_cbuf);
-		scan->rs_cbuf = InvalidBuffer;
+		ReleaseBuffer(scan->rs_scan.rs_cbuf);
+		scan->rs_scan.rs_cbuf = InvalidBuffer;
 	}
 
 	/*
@@ -362,20 +366,20 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 	CHECK_FOR_INTERRUPTS();
 
 	/* read page using selected strategy */
-	scan->rs_cbuf = ReadBufferExtended(scan->rs_rd, MAIN_FORKNUM, page,
-									   RBM_NORMAL, scan->rs_strategy);
-	scan->rs_cblock = page;
+	scan->rs_scan.rs_cbuf = ReadBufferExtended(scan->rs_scan.rs_rd, MAIN_FORKNUM, page,
+											   RBM_NORMAL, scan->rs_pagescan.rs_strategy);
+	scan->rs_scan.rs_cblock = page;
 
-	if (!scan->rs_pageatatime)
+	if (!scan->rs_pagescan.rs_pageatatime)
 		return;
 
-	buffer = scan->rs_cbuf;
-	snapshot = scan->rs_snapshot;
+	buffer = scan->rs_scan.rs_cbuf;
+	snapshot = scan->rs_scan.rs_snapshot;
 
 	/*
 	 * Prune and repair fragmentation for the whole page, if possible.
 	 */
-	heap_page_prune_opt(scan->rs_rd, buffer);
+	heap_page_prune_opt(scan->rs_scan.rs_rd, buffer);
 
 	/*
 	 * We must hold share lock on the buffer content while examining tuple
@@ -385,7 +389,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 	LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 	dp = BufferGetPage(buffer);
-	TestForOldSnapshot(snapshot, scan->rs_rd, dp);
+	TestForOldSnapshot(snapshot, scan->rs_scan.rs_rd, dp);
 	lines = PageGetMaxOffsetNumber(dp);
 	ntup = 0;
 
@@ -420,7 +424,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 			HeapTupleData loctup;
 			bool		valid;
 
-			loctup.t_tableOid = RelationGetRelid(scan->rs_rd);
+			loctup.t_tableOid = RelationGetRelid(scan->rs_scan.rs_rd);
 			loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
 			loctup.t_len = ItemIdGetLength(lpp);
 			ItemPointerSet(&(loctup.t_self), page, lineoff);
@@ -428,20 +432,20 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 			if (all_visible)
 				valid = true;
 			else
-				valid = HeapTupleSatisfiesVisibility(scan->rs_rd->rd_stamroutine, &loctup, snapshot, buffer);
+				valid = HeapTupleSatisfiesVisibility(scan->rs_scan.rs_rd->rd_stamroutine, &loctup, snapshot, buffer);
 
-			CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
+			CheckForSerializableConflictOut(valid, scan->rs_scan.rs_rd, &loctup,
 											buffer, snapshot);
 
 			if (valid)
-				scan->rs_vistuples[ntup++] = lineoff;
+				scan->rs_pagescan.rs_vistuples[ntup++] = lineoff;
 		}
 	}
 
 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 
 	Assert(ntup <= MaxHeapTuplesPerPage);
-	scan->rs_ntuples = ntup;
+	scan->rs_pagescan.rs_ntuples = ntup;
 }
 
 /* ----------------
@@ -474,7 +478,7 @@ heapgettup(HeapScanDesc scan,
 		   ScanKey key)
 {
 	HeapTuple	tuple = &(scan->rs_ctup);
-	Snapshot	snapshot = scan->rs_snapshot;
+	Snapshot	snapshot = scan->rs_scan.rs_snapshot;
 	bool		backward = ScanDirectionIsBackward(dir);
 	BlockNumber page;
 	bool		finished;
@@ -489,14 +493,14 @@ heapgettup(HeapScanDesc scan,
 	 */
 	if (ScanDirectionIsForward(dir))
 	{
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			/*
 			 * return null immediately if relation is empty
 			 */
-			if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
+			if (scan->rs_pagescan.rs_nblocks == 0 || scan->rs_pagescan.rs_numblocks == 0)
 			{
-				Assert(!BufferIsValid(scan->rs_cbuf));
+				Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 				tuple->t_data = NULL;
 				return;
 			}
@@ -509,29 +513,29 @@ heapgettup(HeapScanDesc scan,
 				/* Other processes might have already finished the scan. */
 				if (page == InvalidBlockNumber)
 				{
-					Assert(!BufferIsValid(scan->rs_cbuf));
+					Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 					tuple->t_data = NULL;
 					return;
 				}
 			}
 			else
-				page = scan->rs_startblock; /* first page */
-			heapgetpage(scan, page);
+				page = scan->rs_pagescan.rs_startblock; /* first page */
+			heapgetpage((StorageScanDesc) scan, page);
 			lineoff = FirstOffsetNumber;	/* first offnum */
-			scan->rs_inited = true;
+			scan->rs_scan.rs_inited = true;
 		}
 		else
 		{
 			/* continue from previously returned page/tuple */
-			page = scan->rs_cblock; /* current page */
+			page = scan->rs_scan.rs_cblock; /* current page */
 			lineoff =			/* next offnum */
 				OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
 		}
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
 
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(snapshot, scan->rs_rd, dp);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(snapshot, scan->rs_scan.rs_rd, dp);
 		lines = PageGetMaxOffsetNumber(dp);
 		/* page and lineoff now reference the physically next tid */
 
@@ -542,14 +546,14 @@ heapgettup(HeapScanDesc scan,
 		/* backward parallel scan not supported */
 		Assert(scan->rs_parallel == NULL);
 
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			/*
 			 * return null immediately if relation is empty
 			 */
-			if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
+			if (scan->rs_pagescan.rs_nblocks == 0 || scan->rs_pagescan.rs_numblocks == 0)
 			{
-				Assert(!BufferIsValid(scan->rs_cbuf));
+				Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 				tuple->t_data = NULL;
 				return;
 			}
@@ -560,30 +564,30 @@ heapgettup(HeapScanDesc scan,
 			 * time, and much more likely that we'll just bollix things for
 			 * forward scanners.
 			 */
-			scan->rs_syncscan = false;
+			scan->rs_pagescan.rs_syncscan = false;
 			/* start from last page of the scan */
-			if (scan->rs_startblock > 0)
-				page = scan->rs_startblock - 1;
+			if (scan->rs_pagescan.rs_startblock > 0)
+				page = scan->rs_pagescan.rs_startblock - 1;
 			else
-				page = scan->rs_nblocks - 1;
-			heapgetpage(scan, page);
+				page = scan->rs_pagescan.rs_nblocks - 1;
+			heapgetpage((StorageScanDesc) scan, page);
 		}
 		else
 		{
 			/* continue from previously returned page/tuple */
-			page = scan->rs_cblock; /* current page */
+			page = scan->rs_scan.rs_cblock; /* current page */
 		}
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
 
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(snapshot, scan->rs_rd, dp);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(snapshot, scan->rs_scan.rs_rd, dp);
 		lines = PageGetMaxOffsetNumber(dp);
 
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			lineoff = lines;	/* final offnum */
-			scan->rs_inited = true;
+			scan->rs_scan.rs_inited = true;
 		}
 		else
 		{
@@ -599,20 +603,20 @@ heapgettup(HeapScanDesc scan,
 		/*
 		 * ``no movement'' scan direction: refetch prior tuple
 		 */
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
+			Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 			tuple->t_data = NULL;
 			return;
 		}
 
 		page = ItemPointerGetBlockNumber(&(tuple->t_self));
-		if (page != scan->rs_cblock)
-			heapgetpage(scan, page);
+		if (page != scan->rs_scan.rs_cblock)
+			heapgetpage((StorageScanDesc) scan, page);
 
 		/* Since the tuple was previously fetched, needn't lock page here */
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(snapshot, scan->rs_rd, dp);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(snapshot, scan->rs_scan.rs_rd, dp);
 		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
 		lpp = PageGetItemId(dp, lineoff);
 		Assert(ItemIdIsNormal(lpp));
@@ -643,21 +647,21 @@ heapgettup(HeapScanDesc scan,
 				/*
 				 * if current tuple qualifies, return it.
 				 */
-				valid = HeapTupleSatisfiesVisibility(scan->rs_rd->rd_stamroutine,
+				valid = HeapTupleSatisfiesVisibility(scan->rs_scan.rs_rd->rd_stamroutine,
 													 tuple,
 													 snapshot,
-													 scan->rs_cbuf);
+													 scan->rs_scan.rs_cbuf);
 
-				CheckForSerializableConflictOut(valid, scan->rs_rd, tuple,
-												scan->rs_cbuf, snapshot);
+				CheckForSerializableConflictOut(valid, scan->rs_scan.rs_rd, tuple,
+												scan->rs_scan.rs_cbuf, snapshot);
 
 				if (valid && key != NULL)
-					HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),
+					HeapKeyTest(tuple, RelationGetDescr(scan->rs_scan.rs_rd),
 								nkeys, key, valid);
 
 				if (valid)
 				{
-					LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+					LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_UNLOCK);
 					return;
 				}
 			}
@@ -682,17 +686,17 @@ heapgettup(HeapScanDesc scan,
 		 * if we get here, it means we've exhausted the items on this page and
 		 * it's time to move to the next.
 		 */
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_UNLOCK);
 
 		/*
 		 * advance to next/prior page and detect end of scan
 		 */
 		if (backward)
 		{
-			finished = (page == scan->rs_startblock) ||
-				(scan->rs_numblocks != InvalidBlockNumber ? --scan->rs_numblocks == 0 : false);
+			finished = (page == scan->rs_pagescan.rs_startblock) ||
+				(scan->rs_pagescan.rs_numblocks != InvalidBlockNumber ? --scan->rs_pagescan.rs_numblocks == 0 : false);
 			if (page == 0)
-				page = scan->rs_nblocks;
+				page = scan->rs_pagescan.rs_nblocks;
 			page--;
 		}
 		else if (scan->rs_parallel != NULL)
@@ -703,10 +707,10 @@ heapgettup(HeapScanDesc scan,
 		else
 		{
 			page++;
-			if (page >= scan->rs_nblocks)
+			if (page >= scan->rs_pagescan.rs_nblocks)
 				page = 0;
-			finished = (page == scan->rs_startblock) ||
-				(scan->rs_numblocks != InvalidBlockNumber ? --scan->rs_numblocks == 0 : false);
+			finished = (page == scan->rs_pagescan.rs_startblock) ||
+				(scan->rs_pagescan.rs_numblocks != InvalidBlockNumber ? --scan->rs_pagescan.rs_numblocks == 0 : false);
 
 			/*
 			 * Report our new scan position for synchronization purposes. We
@@ -720,8 +724,8 @@ heapgettup(HeapScanDesc scan,
 			 * a little bit backwards on every invocation, which is confusing.
 			 * We don't guarantee any specific ordering in general, though.
 			 */
-			if (scan->rs_syncscan)
-				ss_report_location(scan->rs_rd, page);
+			if (scan->rs_pagescan.rs_syncscan)
+				ss_report_location(scan->rs_scan.rs_rd, page);
 		}
 
 		/*
@@ -729,21 +733,21 @@ heapgettup(HeapScanDesc scan,
 		 */
 		if (finished)
 		{
-			if (BufferIsValid(scan->rs_cbuf))
-				ReleaseBuffer(scan->rs_cbuf);
-			scan->rs_cbuf = InvalidBuffer;
-			scan->rs_cblock = InvalidBlockNumber;
+			if (BufferIsValid(scan->rs_scan.rs_cbuf))
+				ReleaseBuffer(scan->rs_scan.rs_cbuf);
+			scan->rs_scan.rs_cbuf = InvalidBuffer;
+			scan->rs_scan.rs_cblock = InvalidBlockNumber;
 			tuple->t_data = NULL;
-			scan->rs_inited = false;
+			scan->rs_scan.rs_inited = false;
 			return;
 		}
 
-		heapgetpage(scan, page);
+		heapgetpage((StorageScanDesc) scan, page);
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
 
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(snapshot, scan->rs_rd, dp);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(snapshot, scan->rs_scan.rs_rd, dp);
 		lines = PageGetMaxOffsetNumber((Page) dp);
 		linesleft = lines;
 		if (backward)
@@ -794,14 +798,14 @@ heapgettup_pagemode(HeapScanDesc scan,
 	 */
 	if (ScanDirectionIsForward(dir))
 	{
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			/*
 			 * return null immediately if relation is empty
 			 */
-			if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
+			if (scan->rs_pagescan.rs_nblocks == 0 || scan->rs_pagescan.rs_numblocks == 0)
 			{
-				Assert(!BufferIsValid(scan->rs_cbuf));
+				Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 				tuple->t_data = NULL;
 				return;
 			}
@@ -814,28 +818,28 @@ heapgettup_pagemode(HeapScanDesc scan,
 				/* Other processes might have already finished the scan. */
 				if (page == InvalidBlockNumber)
 				{
-					Assert(!BufferIsValid(scan->rs_cbuf));
+					Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 					tuple->t_data = NULL;
 					return;
 				}
 			}
 			else
-				page = scan->rs_startblock; /* first page */
-			heapgetpage(scan, page);
+				page = scan->rs_pagescan.rs_startblock; /* first page */
+			heapgetpage((StorageScanDesc) scan, page);
 			lineindex = 0;
-			scan->rs_inited = true;
+			scan->rs_scan.rs_inited = true;
 		}
 		else
 		{
 			/* continue from previously returned page/tuple */
-			page = scan->rs_cblock; /* current page */
-			lineindex = scan->rs_cindex + 1;
+			page = scan->rs_scan.rs_cblock; /* current page */
+			lineindex = scan->rs_pagescan.rs_cindex + 1;
 		}
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_snapshot, scan->rs_rd, dp);
-		lines = scan->rs_ntuples;
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(scan->rs_scan.rs_snapshot, scan->rs_scan.rs_rd, dp);
+		lines = scan->rs_pagescan.rs_ntuples;
 		/* page and lineindex now reference the next visible tid */
 
 		linesleft = lines - lineindex;
@@ -845,14 +849,14 @@ heapgettup_pagemode(HeapScanDesc scan,
 		/* backward parallel scan not supported */
 		Assert(scan->rs_parallel == NULL);
 
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			/*
 			 * return null immediately if relation is empty
 			 */
-			if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
+			if (scan->rs_pagescan.rs_nblocks == 0 || scan->rs_pagescan.rs_numblocks == 0)
 			{
-				Assert(!BufferIsValid(scan->rs_cbuf));
+				Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 				tuple->t_data = NULL;
 				return;
 			}
@@ -863,33 +867,33 @@ heapgettup_pagemode(HeapScanDesc scan,
 			 * time, and much more likely that we'll just bollix things for
 			 * forward scanners.
 			 */
-			scan->rs_syncscan = false;
+			scan->rs_pagescan.rs_syncscan = false;
 			/* start from last page of the scan */
-			if (scan->rs_startblock > 0)
-				page = scan->rs_startblock - 1;
+			if (scan->rs_pagescan.rs_startblock > 0)
+				page = scan->rs_pagescan.rs_startblock - 1;
 			else
-				page = scan->rs_nblocks - 1;
-			heapgetpage(scan, page);
+				page = scan->rs_pagescan.rs_nblocks - 1;
+			heapgetpage((StorageScanDesc) scan, page);
 		}
 		else
 		{
 			/* continue from previously returned page/tuple */
-			page = scan->rs_cblock; /* current page */
+			page = scan->rs_scan.rs_cblock; /* current page */
 		}
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_snapshot, scan->rs_rd, dp);
-		lines = scan->rs_ntuples;
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(scan->rs_scan.rs_snapshot, scan->rs_scan.rs_rd, dp);
+		lines = scan->rs_pagescan.rs_ntuples;
 
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
 			lineindex = lines - 1;
-			scan->rs_inited = true;
+			scan->rs_scan.rs_inited = true;
 		}
 		else
 		{
-			lineindex = scan->rs_cindex - 1;
+			lineindex = scan->rs_pagescan.rs_cindex - 1;
 		}
 		/* page and lineindex now reference the previous visible tid */
 
@@ -900,20 +904,20 @@ heapgettup_pagemode(HeapScanDesc scan,
 		/*
 		 * ``no movement'' scan direction: refetch prior tuple
 		 */
-		if (!scan->rs_inited)
+		if (!scan->rs_scan.rs_inited)
 		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
+			Assert(!BufferIsValid(scan->rs_scan.rs_cbuf));
 			tuple->t_data = NULL;
 			return;
 		}
 
 		page = ItemPointerGetBlockNumber(&(tuple->t_self));
-		if (page != scan->rs_cblock)
-			heapgetpage(scan, page);
+		if (page != scan->rs_scan.rs_cblock)
+			heapgetpage((StorageScanDesc) scan, page);
 
 		/* Since the tuple was previously fetched, needn't lock page here */
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_snapshot, scan->rs_rd, dp);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(scan->rs_scan.rs_snapshot, scan->rs_scan.rs_rd, dp);
 		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
 		lpp = PageGetItemId(dp, lineoff);
 		Assert(ItemIdIsNormal(lpp));
@@ -922,8 +926,8 @@ heapgettup_pagemode(HeapScanDesc scan,
 		tuple->t_len = ItemIdGetLength(lpp);
 
 		/* check that rs_cindex is in sync */
-		Assert(scan->rs_cindex < scan->rs_ntuples);
-		Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]);
+		Assert(scan->rs_pagescan.rs_cindex < scan->rs_pagescan.rs_ntuples);
+		Assert(lineoff == scan->rs_pagescan.rs_vistuples[scan->rs_pagescan.rs_cindex]);
 
 		return;
 	}
@@ -936,7 +940,7 @@ heapgettup_pagemode(HeapScanDesc scan,
 	{
 		while (linesleft > 0)
 		{
-			lineoff = scan->rs_vistuples[lineindex];
+			lineoff = scan->rs_pagescan.rs_vistuples[lineindex];
 			lpp = PageGetItemId(dp, lineoff);
 			Assert(ItemIdIsNormal(lpp));
 
@@ -947,7 +951,7 @@ heapgettup_pagemode(HeapScanDesc scan,
 			/*
 			 * if current tuple qualifies, return it.
 			 */
-			if (HeapTupleSatisfiesVisibility(scan->rs_rd->rd_stamroutine, tuple, scan->rs_snapshot, scan->rs_cbuf))
+			if (HeapTupleSatisfiesVisibility(scan->rs_scan.rs_rd->rd_stamroutine, tuple, scan->rs_scan.rs_snapshot, scan->rs_scan.rs_cbuf))
 			{
 				/*
 				 * if current tuple qualifies, return it.
@@ -956,19 +960,19 @@ heapgettup_pagemode(HeapScanDesc scan,
 				{
 					bool		valid;
 
-					HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),
+					HeapKeyTest(tuple, RelationGetDescr(scan->rs_scan.rs_rd),
 								nkeys, key, valid);
 					if (valid)
 					{
-						scan->rs_cindex = lineindex;
-						LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+						scan->rs_pagescan.rs_cindex = lineindex;
+						LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_UNLOCK);
 						return;
 					}
 				}
 				else
 				{
-					scan->rs_cindex = lineindex;
-					LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+					scan->rs_pagescan.rs_cindex = lineindex;
+					LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_UNLOCK);
 					return;
 				}
 			}
@@ -987,7 +991,7 @@ heapgettup_pagemode(HeapScanDesc scan,
 		 * if we get here, it means we've exhausted the items on this page and
 		 * it's time to move to the next.
 		 */
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_UNLOCK);
 
 		/*
 		 * if we get here, it means we've exhausted the items on this page and
@@ -995,10 +999,10 @@ heapgettup_pagemode(HeapScanDesc scan,
 		 */
 		if (backward)
 		{
-			finished = (page == scan->rs_startblock) ||
-				(scan->rs_numblocks != InvalidBlockNumber ? --scan->rs_numblocks == 0 : false);
+			finished = (page == scan->rs_pagescan.rs_startblock) ||
+				(scan->rs_pagescan.rs_numblocks != InvalidBlockNumber ? --scan->rs_pagescan.rs_numblocks == 0 : false);
 			if (page == 0)
-				page = scan->rs_nblocks;
+				page = scan->rs_pagescan.rs_nblocks;
 			page--;
 		}
 		else if (scan->rs_parallel != NULL)
@@ -1009,10 +1013,10 @@ heapgettup_pagemode(HeapScanDesc scan,
 		else
 		{
 			page++;
-			if (page >= scan->rs_nblocks)
+			if (page >= scan->rs_pagescan.rs_nblocks)
 				page = 0;
-			finished = (page == scan->rs_startblock) ||
-				(scan->rs_numblocks != InvalidBlockNumber ? --scan->rs_numblocks == 0 : false);
+			finished = (page == scan->rs_pagescan.rs_startblock) ||
+				(scan->rs_pagescan.rs_numblocks != InvalidBlockNumber ? --scan->rs_pagescan.rs_numblocks == 0 : false);
 
 			/*
 			 * Report our new scan position for synchronization purposes. We
@@ -1026,8 +1030,8 @@ heapgettup_pagemode(HeapScanDesc scan,
 			 * a little bit backwards on every invocation, which is confusing.
 			 * We don't guarantee any specific ordering in general, though.
 			 */
-			if (scan->rs_syncscan)
-				ss_report_location(scan->rs_rd, page);
+			if (scan->rs_pagescan.rs_syncscan)
+				ss_report_location(scan->rs_scan.rs_rd, page);
 		}
 
 		/*
@@ -1035,21 +1039,21 @@ heapgettup_pagemode(HeapScanDesc scan,
 		 */
 		if (finished)
 		{
-			if (BufferIsValid(scan->rs_cbuf))
-				ReleaseBuffer(scan->rs_cbuf);
-			scan->rs_cbuf = InvalidBuffer;
-			scan->rs_cblock = InvalidBlockNumber;
+			if (BufferIsValid(scan->rs_scan.rs_cbuf))
+				ReleaseBuffer(scan->rs_scan.rs_cbuf);
+			scan->rs_scan.rs_cbuf = InvalidBuffer;
+			scan->rs_scan.rs_cblock = InvalidBlockNumber;
 			tuple->t_data = NULL;
-			scan->rs_inited = false;
+			scan->rs_scan.rs_inited = false;
 			return;
 		}
 
-		heapgetpage(scan, page);
+		heapgetpage((StorageScanDesc) scan, page);
 
-		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-		dp = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_snapshot, scan->rs_rd, dp);
-		lines = scan->rs_ntuples;
+		LockBuffer(scan->rs_scan.rs_cbuf, BUFFER_LOCK_SHARE);
+		dp = BufferGetPage(scan->rs_scan.rs_cbuf);
+		TestForOldSnapshot(scan->rs_scan.rs_snapshot, scan->rs_scan.rs_rd, dp);
+		lines = scan->rs_pagescan.rs_ntuples;
 		linesleft = lines;
 		if (backward)
 			lineindex = lines - 1;
@@ -1376,7 +1380,7 @@ heap_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
 	return r;
 }
 
-HeapScanDesc
+StorageScanDesc
 heap_beginscan(Relation relation, Snapshot snapshot,
 			   int nkeys, ScanKey key,
 			   ParallelHeapScanDesc parallel_scan,
@@ -1403,12 +1407,12 @@ heap_beginscan(Relation relation, Snapshot snapshot,
 	 */
 	scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
 
-	scan->rs_rd = relation;
-	scan->rs_snapshot = snapshot;
-	scan->rs_nkeys = nkeys;
+	scan->rs_scan.rs_rd = relation;
+	scan->rs_scan.rs_snapshot = snapshot;
+	scan->rs_scan.rs_nkeys = nkeys;
 	scan->rs_bitmapscan = is_bitmapscan;
 	scan->rs_samplescan = is_samplescan;
-	scan->rs_strategy = NULL;	/* set in initscan */
+	scan->rs_pagescan.rs_strategy = NULL;	/* set in initscan */
 	scan->rs_allow_strat = allow_strat;
 	scan->rs_allow_sync = allow_sync;
 	scan->rs_temp_snap = temp_snap;
@@ -1417,7 +1421,7 @@ heap_beginscan(Relation relation, Snapshot snapshot,
 	/*
 	 * we can use page-at-a-time mode if it's an MVCC-safe snapshot
 	 */
-	scan->rs_pageatatime = allow_pagemode && IsMVCCSnapshot(snapshot);
+	scan->rs_pagescan.rs_pageatatime = allow_pagemode && IsMVCCSnapshot(snapshot);
 
 	/*
 	 * For a seqscan in a serializable transaction, acquire a predicate lock
@@ -1441,13 +1445,13 @@ heap_beginscan(Relation relation, Snapshot snapshot,
 	 * initscan() and we don't want to allocate memory again
 	 */
 	if (nkeys > 0)
-		scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
+		scan->rs_scan.rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
 	else
-		scan->rs_key = NULL;
+		scan->rs_scan.rs_key = NULL;
 
 	initscan(scan, key, false);
 
-	return scan;
+	return (StorageScanDesc) scan;
 }
 
 /* ----------------
@@ -1455,21 +1459,23 @@ heap_beginscan(Relation relation, Snapshot snapshot,
  * ----------------
  */
 void
-heap_rescan(HeapScanDesc scan, ScanKey key, bool set_params,
+heap_rescan(StorageScanDesc sscan, ScanKey key, bool set_params,
 			bool allow_strat, bool allow_sync, bool allow_pagemode)
 {
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
 	if (set_params)
 	{
 		scan->rs_allow_strat = allow_strat;
 		scan->rs_allow_sync = allow_sync;
-		scan->rs_pageatatime = allow_pagemode && IsMVCCSnapshot(scan->rs_snapshot);
+		scan->rs_pagescan.rs_pageatatime = allow_pagemode && IsMVCCSnapshot(scan->rs_scan.rs_snapshot);
 	}
 
 	/*
 	 * unpin scan buffers
 	 */
-	if (BufferIsValid(scan->rs_cbuf))
-		ReleaseBuffer(scan->rs_cbuf);
+	if (BufferIsValid(scan->rs_scan.rs_cbuf))
+		ReleaseBuffer(scan->rs_scan.rs_cbuf);
 
 	/*
 	 * reinitialize scan descriptor
@@ -1500,29 +1506,31 @@ heap_rescan(HeapScanDesc scan, ScanKey key, bool set_params,
  * ----------------
  */
 void
-heap_endscan(HeapScanDesc scan)
+heap_endscan(StorageScanDesc sscan)
 {
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
 	/* Note: no locking manipulations needed */
 
 	/*
 	 * unpin scan buffers
 	 */
-	if (BufferIsValid(scan->rs_cbuf))
-		ReleaseBuffer(scan->rs_cbuf);
+	if (BufferIsValid(scan->rs_scan.rs_cbuf))
+		ReleaseBuffer(scan->rs_scan.rs_cbuf);
 
 	/*
 	 * decrement relation reference count and free scan descriptor storage
 	 */
-	RelationDecrementReferenceCount(scan->rs_rd);
+	RelationDecrementReferenceCount(scan->rs_scan.rs_rd);
 
-	if (scan->rs_key)
-		pfree(scan->rs_key);
+	if (scan->rs_scan.rs_key)
+		pfree(scan->rs_scan.rs_key);
 
-	if (scan->rs_strategy != NULL)
-		FreeAccessStrategy(scan->rs_strategy);
+	if (scan->rs_pagescan.rs_strategy != NULL)
+		FreeAccessStrategy(scan->rs_pagescan.rs_strategy);
 
 	if (scan->rs_temp_snap)
-		UnregisterSnapshot(scan->rs_snapshot);
+		UnregisterSnapshot(scan->rs_scan.rs_snapshot);
 
 	pfree(scan);
 }
@@ -1618,7 +1626,7 @@ retry:
 		else
 		{
 			SpinLockRelease(&parallel_scan->phs_mutex);
-			sync_startpage = ss_get_location(scan->rs_rd, scan->rs_nblocks);
+			sync_startpage = ss_get_location(scan->rs_scan.rs_rd, scan->rs_pagescan.rs_nblocks);
 			goto retry;
 		}
 	}
@@ -1660,10 +1668,10 @@ heap_parallelscan_nextpage(HeapScanDesc scan)
 	 * starting block number, modulo nblocks.
 	 */
 	nallocated = pg_atomic_fetch_add_u64(&parallel_scan->phs_nallocated, 1);
-	if (nallocated >= scan->rs_nblocks)
+	if (nallocated >= scan->rs_pagescan.rs_nblocks)
 		page = InvalidBlockNumber;	/* all blocks have been allocated */
 	else
-		page = (nallocated + parallel_scan->phs_startblock) % scan->rs_nblocks;
+		page = (nallocated + parallel_scan->phs_startblock) % scan->rs_pagescan.rs_nblocks;
 
 	/*
 	 * Report scan location.  Normally, we report the current page number.
@@ -1672,12 +1680,12 @@ heap_parallelscan_nextpage(HeapScanDesc scan)
 	 * doesn't slew backwards.  We only report the position at the end of the
 	 * scan once, though: subsequent callers will report nothing.
 	 */
-	if (scan->rs_syncscan)
+	if (scan->rs_pagescan.rs_syncscan)
 	{
 		if (page != InvalidBlockNumber)
-			ss_report_location(scan->rs_rd, page);
-		else if (nallocated == scan->rs_nblocks)
-			ss_report_location(scan->rs_rd, parallel_scan->phs_startblock);
+			ss_report_location(scan->rs_scan.rs_rd, page);
+		else if (nallocated == scan->rs_pagescan.rs_nblocks)
+			ss_report_location(scan->rs_scan.rs_rd, parallel_scan->phs_startblock);
 	}
 
 	return page;
@@ -1690,12 +1698,14 @@ heap_parallelscan_nextpage(HeapScanDesc scan)
  * ----------------
  */
 void
-heap_update_snapshot(HeapScanDesc scan, Snapshot snapshot)
+heap_update_snapshot(StorageScanDesc sscan, Snapshot snapshot)
 {
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
 	Assert(IsMVCCSnapshot(snapshot));
 
 	RegisterSnapshot(snapshot);
-	scan->rs_snapshot = snapshot;
+	scan->rs_scan.rs_snapshot = snapshot;
 	scan->rs_temp_snap = true;
 }
 
@@ -1723,17 +1733,19 @@ heap_update_snapshot(HeapScanDesc scan, Snapshot snapshot)
 #endif							/* !defined(HEAPDEBUGALL) */
 
 StorageTuple
-heap_getnext(HeapScanDesc scan, ScanDirection direction)
+heap_getnext(StorageScanDesc sscan, ScanDirection direction)
 {
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
 	/* Note: no locking manipulations needed */
 
 	HEAPDEBUG_1;				/* heap_getnext( info ) */
 
-	if (scan->rs_pageatatime)
+	if (scan->rs_pagescan.rs_pageatatime)
 		heapgettup_pagemode(scan, direction,
-							scan->rs_nkeys, scan->rs_key);
+							scan->rs_scan.rs_nkeys, scan->rs_scan.rs_key);
 	else
-		heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key);
+		heapgettup(scan, direction, scan->rs_scan.rs_nkeys, scan->rs_scan.rs_key);
 
 	if (scan->rs_ctup.t_data == NULL)
 	{
@@ -1747,7 +1759,7 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
 	 */
 	HEAPDEBUG_3;				/* heap_getnext returning tuple */
 
-	pgstat_count_heap_getnext(scan->rs_rd);
+	pgstat_count_heap_getnext(scan->rs_scan.rs_rd);
 
 	return heap_copytuple(&(scan->rs_ctup));
 }
@@ -1755,7 +1767,7 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
 #ifdef HEAPAMSLOTDEBUGALL
 #define HEAPAMSLOTDEBUG_1 \
 	elog(DEBUG2, "heapam_getnext([%s,nkeys=%d],dir=%d) called", \
-		 RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, (int) direction)
+		 RelationGetRelationName(scan->rs_scan.rs_rd), scan->rs_scan.rs_nkeys, (int) direction)
 #define HEAPAMSLOTDEBUG_2 \
 	elog(DEBUG2, "heapam_getnext returning EOS")
 #define HEAPAMSLOTDEBUG_3 \
@@ -1767,7 +1779,7 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
 #endif
 
 TupleTableSlot *
-heap_getnextslot(HeapScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
+heap_getnextslot(StorageScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
 {
 	HeapScanDesc scan = (HeapScanDesc) sscan;
 
@@ -1775,11 +1787,11 @@ heap_getnextslot(HeapScanDesc sscan, ScanDirection direction, TupleTableSlot *sl
 
 	HEAPAMSLOTDEBUG_1;			/* heap_getnext( info ) */
 
-	if (scan->rs_pageatatime)
+	if (scan->rs_pagescan.rs_pageatatime)
 		heapgettup_pagemode(scan, direction,
-							scan->rs_nkeys, scan->rs_key);
+							scan->rs_scan.rs_nkeys, scan->rs_scan.rs_key);
 	else
-		heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key);
+		heapgettup(scan, direction, scan->rs_scan.rs_nkeys, scan->rs_scan.rs_key);
 
 	if (scan->rs_ctup.t_data == NULL)
 	{
@@ -1794,7 +1806,7 @@ heap_getnextslot(HeapScanDesc sscan, ScanDirection direction, TupleTableSlot *sl
 	 */
 	HEAPAMSLOTDEBUG_3;			/* heap_getnext returning tuple */
 
-	pgstat_count_heap_getnext(scan->rs_rd);
+	pgstat_count_heap_getnext(scan->rs_scan.rs_rd);
 	return ExecStoreTuple(heap_copytuple(&(scan->rs_ctup)),
 						  slot, InvalidBuffer, true);
 }
diff --git a/src/backend/access/heap/heapam_storage.c b/src/backend/access/heap/heapam_storage.c
index e7b669a2dd..ea2b640693 100644
--- a/src/backend/access/heap/heapam_storage.c
+++ b/src/backend/access/heap/heapam_storage.c
@@ -21,7 +21,9 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
+#include "access/relscan.h"
 #include "access/storageamapi.h"
+#include "pgstat.h"
 #include "utils/builtins.h"
 #include "utils/rel.h"
 
@@ -241,6 +243,44 @@ heapam_form_tuple_by_datum(Datum data, Oid tableoid)
 	return heap_form_tuple_by_datum(data, tableoid);
 }
 
+static ParallelHeapScanDesc
+heapam_get_parallelheapscandesc(StorageScanDesc sscan)
+{
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
+	return scan->rs_parallel;
+}
+
+static HeapPageScanDesc
+heapam_get_heappagescandesc(StorageScanDesc sscan)
+{
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+
+	return &scan->rs_pagescan;
+}
+
+static StorageTuple
+heapam_fetch_tuple_from_offset(StorageScanDesc sscan, BlockNumber blkno, OffsetNumber offset)
+{
+	HeapScanDesc scan = (HeapScanDesc) sscan;
+	Page		dp;
+	ItemId		lp;
+
+	dp = (Page) BufferGetPage(scan->rs_scan.rs_cbuf);
+	lp = PageGetItemId(dp, offset);
+	Assert(ItemIdIsNormal(lp));
+
+	scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
+	scan->rs_ctup.t_len = ItemIdGetLength(lp);
+	scan->rs_ctup.t_tableOid = scan->rs_scan.rs_rd->rd_id;
+	ItemPointerSet(&scan->rs_ctup.t_self, blkno, offset);
+
+	pgstat_count_heap_fetch(scan->rs_scan.rs_rd);
+
+	return &(scan->rs_ctup);
+}
+
+
 Datum
 heapam_storage_handler(PG_FUNCTION_ARGS)
 {
@@ -261,6 +301,19 @@ heapam_storage_handler(PG_FUNCTION_ARGS)
 	amroutine->scan_rescan = heap_rescan;
 	amroutine->scan_update_snapshot = heap_update_snapshot;
 	amroutine->hot_search_buffer = heap_hot_search_buffer;
+	amroutine->scan_fetch_tuple_from_offset = heapam_fetch_tuple_from_offset;
+
+	/*
+	 * The following routine needs to be provided when the storage support
+	 * parallel sequential scan
+	 */
+	amroutine->scan_get_parallelheapscandesc = heapam_get_parallelheapscandesc;
+
+	/*
+	 * The following routine needs to be provided when the storage support
+	 * BitmapHeap and Sample Scans
+	 */
+	amroutine->scan_get_heappagescandesc = heapam_get_heappagescandesc;
 
 	amroutine->tuple_fetch = heapam_fetch;
 	amroutine->tuple_insert = heapam_heap_insert;
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 26a9ccb657..ee9352df06 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -478,10 +478,10 @@ systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup)
 	}
 	else
 	{
-		HeapScanDesc scan = sysscan->scan;
+		StorageScanDesc scan = sysscan->scan;
 
 		Assert(IsMVCCSnapshot(scan->rs_snapshot));
-		Assert(tup == &scan->rs_ctup);
+		/* hari Assert(tup == &scan->rs_ctup); */
 		Assert(BufferIsValid(scan->rs_cbuf));
 		/* must hold a buffer lock to call HeapTupleSatisfiesVisibility */
 		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
diff --git a/src/backend/access/storage/storageam.c b/src/backend/access/storage/storageam.c
index 75e69db6ab..f14673e88e 100644
--- a/src/backend/access/storage/storageam.c
+++ b/src/backend/access/storage/storageam.c
@@ -56,7 +56,7 @@ storage_lock_tuple(Relation relation, ItemPointer tid, StorageTuple * stuple,
  *		Caller must hold a suitable lock on the correct relation.
  * ----------------
  */
-HeapScanDesc
+StorageScanDesc
 storage_beginscan_parallel(Relation relation, ParallelHeapScanDesc parallel_scan)
 {
 	Snapshot	snapshot;
@@ -69,6 +69,25 @@ storage_beginscan_parallel(Relation relation, ParallelHeapScanDesc parallel_scan
 												true, true, true, false, false, true);
 }
 
+ParallelHeapScanDesc
+storageam_get_parallelheapscandesc(StorageScanDesc sscan)
+{
+	return sscan->rs_rd->rd_stamroutine->scan_get_parallelheapscandesc(sscan);
+}
+
+HeapPageScanDesc
+storageam_get_heappagescandesc(StorageScanDesc sscan)
+{
+	/*
+	 * Planner should have already validated whether the current storage
+	 * supports Page scans are not? This function will be called only from
+	 * Bitmap Heap scan and sample scan
+	 */
+	Assert(sscan->rs_rd->rd_stamroutine->scan_get_heappagescandesc != NULL);
+
+	return sscan->rs_rd->rd_stamroutine->scan_get_heappagescandesc(sscan);
+}
+
 /*
  * heap_setscanlimits - restrict range of a heapscan
  *
@@ -76,7 +95,7 @@ storage_beginscan_parallel(Relation relation, ParallelHeapScanDesc parallel_scan
  * numBlks is number of pages to scan (InvalidBlockNumber means "all")
  */
 void
-storage_setscanlimits(HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
+storage_setscanlimits(StorageScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
 {
 	sscan->rs_rd->rd_stamroutine->scansetlimits(sscan, startBlk, numBlks);
 }
@@ -106,7 +125,7 @@ storage_setscanlimits(HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numB
  * also allows control of whether page-mode visibility checking is used.
  * ----------------
  */
-HeapScanDesc
+StorageScanDesc
 storage_beginscan(Relation relation, Snapshot snapshot,
 				  int nkeys, ScanKey key)
 {
@@ -114,7 +133,7 @@ storage_beginscan(Relation relation, Snapshot snapshot,
 												true, true, true, false, false, false);
 }
 
-HeapScanDesc
+StorageScanDesc
 storage_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
 {
 	Oid			relid = RelationGetRelid(relation);
@@ -124,7 +143,7 @@ storage_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
 												true, true, true, false, false, true);
 }
 
-HeapScanDesc
+StorageScanDesc
 storage_beginscan_strat(Relation relation, Snapshot snapshot,
 						int nkeys, ScanKey key,
 						bool allow_strat, bool allow_sync)
@@ -134,7 +153,7 @@ storage_beginscan_strat(Relation relation, Snapshot snapshot,
 												false, false, false);
 }
 
-HeapScanDesc
+StorageScanDesc
 storage_beginscan_bm(Relation relation, Snapshot snapshot,
 					 int nkeys, ScanKey key)
 {
@@ -142,7 +161,7 @@ storage_beginscan_bm(Relation relation, Snapshot snapshot,
 												false, false, true, true, false, false);
 }
 
-HeapScanDesc
+StorageScanDesc
 storage_beginscan_sampling(Relation relation, Snapshot snapshot,
 						   int nkeys, ScanKey key,
 						   bool allow_strat, bool allow_sync, bool allow_pagemode)
@@ -157,7 +176,7 @@ storage_beginscan_sampling(Relation relation, Snapshot snapshot,
  * ----------------
  */
 void
-storage_rescan(HeapScanDesc scan,
+storage_rescan(StorageScanDesc scan,
 			   ScanKey key)
 {
 	scan->rs_rd->rd_stamroutine->scan_rescan(scan, key, false, false, false, false);
@@ -173,7 +192,7 @@ storage_rescan(HeapScanDesc scan,
  * ----------------
  */
 void
-storage_rescan_set_params(HeapScanDesc scan, ScanKey key,
+storage_rescan_set_params(StorageScanDesc scan, ScanKey key,
 						  bool allow_strat, bool allow_sync, bool allow_pagemode)
 {
 	scan->rs_rd->rd_stamroutine->scan_rescan(scan, key, true,
@@ -188,7 +207,7 @@ storage_rescan_set_params(HeapScanDesc scan, ScanKey key,
  * ----------------
  */
 void
-storage_endscan(HeapScanDesc scan)
+storage_endscan(StorageScanDesc scan)
 {
 	scan->rs_rd->rd_stamroutine->scan_end(scan);
 }
@@ -201,23 +220,29 @@ storage_endscan(HeapScanDesc scan)
  * ----------------
  */
 void
-storage_update_snapshot(HeapScanDesc scan, Snapshot snapshot)
+storage_update_snapshot(StorageScanDesc scan, Snapshot snapshot)
 {
 	scan->rs_rd->rd_stamroutine->scan_update_snapshot(scan, snapshot);
 }
 
 StorageTuple
-storage_getnext(HeapScanDesc sscan, ScanDirection direction)
+storage_getnext(StorageScanDesc sscan, ScanDirection direction)
 {
 	return sscan->rs_rd->rd_stamroutine->scan_getnext(sscan, direction);
 }
 
 TupleTableSlot *
-storage_getnextslot(HeapScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
+storage_getnextslot(StorageScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
 {
 	return sscan->rs_rd->rd_stamroutine->scan_getnextslot(sscan, direction, slot);
 }
 
+StorageTuple
+storage_fetch_tuple_from_offset(StorageScanDesc sscan, BlockNumber blkno, OffsetNumber offset)
+{
+	return sscan->rs_rd->rd_stamroutine->scan_fetch_tuple_from_offset(sscan, blkno, offset);
+}
+
 /*
  * Insert a tuple from a slot into storage AM routine
  */
diff --git a/src/backend/access/tablesample/system.c b/src/backend/access/tablesample/system.c
index e270cbc4a0..8793b95c08 100644
--- a/src/backend/access/tablesample/system.c
+++ b/src/backend/access/tablesample/system.c
@@ -183,7 +183,7 @@ static BlockNumber
 system_nextsampleblock(SampleScanState *node)
 {
 	SystemSamplerData *sampler = (SystemSamplerData *) node->tsm_state;
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	HeapPageScanDesc scan = node->pagescan;
 	BlockNumber nextblock = sampler->nextblock;
 	uint32		hashinput[2];
 
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index a73a363a49..da3d48b9cc 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -577,7 +577,7 @@ boot_openrel(char *relname)
 	int			i;
 	struct typmap **app;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 
 	if (strlen(relname) >= NAMEDATALEN)
@@ -893,7 +893,7 @@ gettype(char *type)
 {
 	int			i;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 	struct typmap **app;
 
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 0b3be57a88..c058a1bccd 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -822,7 +822,7 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
 					ScanKeyData key[2];
 					int			keycount;
 					Relation	rel;
-					HeapScanDesc scan;
+					StorageScanDesc scan;
 					HeapTuple	tuple;
 
 					keycount = 0;
@@ -880,7 +880,7 @@ getRelationsInNamespace(Oid namespaceId, char relkind)
 	List	   *relations = NIL;
 	ScanKeyData key[2];
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 
 	ScanKeyInit(&key[0],
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 16bb70ef45..1c508767cf 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1900,7 +1900,7 @@ index_update_stats(Relation rel,
 		ReindexIsProcessingHeap(RelationRelationId))
 	{
 		/* don't assume syscache will work */
-		HeapScanDesc pg_class_scan;
+		StorageScanDesc pg_class_scan;
 		ScanKeyData key[1];
 
 		ScanKeyInit(&key[0],
@@ -2213,7 +2213,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 {
 	bool		is_system_catalog;
 	bool		checking_uniqueness;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	heapTuple;
 	Datum		values[INDEX_MAX_KEYS];
 	bool		isnull[INDEX_MAX_KEYS];
@@ -2652,7 +2652,7 @@ IndexCheckExclusion(Relation heapRelation,
 					Relation indexRelation,
 					IndexInfo *indexInfo)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	heapTuple;
 	Datum		values[INDEX_MAX_KEYS];
 	bool		isnull[INDEX_MAX_KEYS];
@@ -2966,7 +2966,7 @@ validate_index_heapscan(Relation heapRelation,
 						Snapshot snapshot,
 						v_i_state *state)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	heapTuple;
 	Datum		values[INDEX_MAX_KEYS];
 	bool		isnull[INDEX_MAX_KEYS];
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index a81b79d2f1..c6a580abb8 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1266,7 +1266,7 @@ check_default_allows_bound(Relation parent, Relation default_rel,
 		Snapshot	snapshot;
 		TupleDesc	tupdesc;
 		ExprContext *econtext;
-		HeapScanDesc scan;
+		StorageScanDesc scan;
 		MemoryContext oldCxt;
 		TupleTableSlot *tupslot;
 
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 1d048e6394..842abcc8b5 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -151,7 +151,7 @@ RemoveConversionById(Oid conversionOid)
 {
 	Relation	rel;
 	HeapTuple	tuple;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	ScanKeyData scanKeyData;
 
 	ScanKeyInit(&scanKeyData,
diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c
index 517e3101cd..63324cfc8e 100644
--- a/src/backend/catalog/pg_db_role_setting.c
+++ b/src/backend/catalog/pg_db_role_setting.c
@@ -171,7 +171,7 @@ void
 DropSetting(Oid databaseid, Oid roleid)
 {
 	Relation	relsetting;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	ScanKeyData keys[2];
 	HeapTuple	tup;
 	int			numkeys = 0;
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 145e3c1d65..5e3915b438 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -314,7 +314,7 @@ GetAllTablesPublicationRelations(void)
 {
 	Relation	classRel;
 	ScanKeyData key[1];
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	List	   *result = NIL;
 
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index a51f2e4dfc..050dfa3e4c 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -377,7 +377,7 @@ void
 RemoveSubscriptionRel(Oid subid, Oid relid)
 {
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	ScanKeyData skey[2];
 	HeapTuple	tup;
 	int			nkeys = 0;
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index e0f6973a3f..ccdbe70ff6 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -746,7 +746,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 	Datum	   *values;
 	bool	   *isnull;
 	IndexScanDesc indexScan;
-	HeapScanDesc heapScan;
+	StorageScanDesc heapScan;
 	bool		use_wal;
 	bool		is_system_catalog;
 	TransactionId OldestXmin;
@@ -1638,7 +1638,7 @@ static List *
 get_tables_to_cluster(MemoryContext cluster_context)
 {
 	Relation	indRelation;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	ScanKeyData entry;
 	HeapTuple	indexTuple;
 	Form_pg_index index;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f2209d9f81..42803c687b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2032,7 +2032,7 @@ CopyTo(CopyState cstate)
 	{
 		Datum	   *values;
 		bool	   *nulls;
-		HeapScanDesc scandesc;
+		StorageScanDesc scandesc;
 		HeapTuple	tuple;
 
 		values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 87d651002e..4a224b5bbc 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -99,7 +99,7 @@ static int	errdetail_busy_db(int notherbackends, int npreparedxacts);
 Oid
 createdb(ParseState *pstate, const CreatedbStmt *stmt)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	Relation	rel;
 	Oid			src_dboid;
 	Oid			src_owner;
@@ -1872,7 +1872,7 @@ static void
 remove_dbtablespaces(Oid db_id)
 {
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
@@ -1939,7 +1939,7 @@ check_db_file_conflict(Oid db_id)
 {
 	bool		result = false;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 400f936a2f..2152aa86e5 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1891,7 +1891,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 {
 	Oid			objectOid;
 	Relation	relationRelation;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	ScanKeyData scan_keys[1];
 	HeapTuple	tuple;
 	MemoryContext private_context;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3d4fa831b3..28874a27ae 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4492,7 +4492,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		bool	   *isnull;
 		TupleTableSlot *oldslot;
 		TupleTableSlot *newslot;
-		HeapScanDesc scan;
+		StorageScanDesc scan;
 		HeapTuple	tuple;
 		MemoryContext oldCxt;
 		List	   *dropped_attrs = NIL;
@@ -5065,7 +5065,7 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
 {
 	Relation	classRel;
 	ScanKeyData key[1];
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	List	   *result = NIL;
 
@@ -8219,7 +8219,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	Expr	   *origexpr;
 	ExprState  *exprstate;
 	TupleDesc	tupdesc;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	ExprContext *econtext;
 	MemoryContext oldcxt;
@@ -8302,7 +8302,7 @@ validateForeignKeyConstraint(char *conname,
 							 Oid pkindOid,
 							 Oid constraintOid)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	Trigger		trig;
 	Snapshot	snapshot;
@@ -10809,7 +10809,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 	ListCell   *l;
 	ScanKeyData key[1];
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	Oid			orig_tablespaceoid;
 	Oid			new_tablespaceoid;
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 6804182db7..0e2b93a5df 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -402,7 +402,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 {
 #ifdef HAVE_SYMLINK
 	char	   *tablespacename = stmt->tablespacename;
-	HeapScanDesc scandesc;
+	StorageScanDesc scandesc;
 	Relation	rel;
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
@@ -913,7 +913,7 @@ RenameTableSpace(const char *oldname, const char *newname)
 	Oid			tspId;
 	Relation	rel;
 	ScanKeyData entry[1];
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 	HeapTuple	newtuple;
 	Form_pg_tablespace newform;
@@ -988,7 +988,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 {
 	Relation	rel;
 	ScanKeyData entry[1];
-	HeapScanDesc scandesc;
+	StorageScanDesc scandesc;
 	HeapTuple	tup;
 	Oid			tablespaceoid;
 	Datum		datum;
@@ -1382,7 +1382,7 @@ get_tablespace_oid(const char *tablespacename, bool missing_ok)
 {
 	Oid			result;
 	Relation	rel;
-	HeapScanDesc scandesc;
+	StorageScanDesc scandesc;
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
 
@@ -1428,7 +1428,7 @@ get_tablespace_name(Oid spc_oid)
 {
 	char	   *result;
 	Relation	rel;
-	HeapScanDesc scandesc;
+	StorageScanDesc scandesc;
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 8a339d16be..e539570d9c 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2382,7 +2382,7 @@ AlterDomainNotNull(List *names, bool notNull)
 			RelToCheck *rtc = (RelToCheck *) lfirst(rt);
 			Relation	testrel = rtc->rel;
 			TupleDesc	tupdesc = RelationGetDescr(testrel);
-			HeapScanDesc scan;
+			StorageScanDesc scan;
 			HeapTuple	tuple;
 			Snapshot	snapshot;
 
@@ -2778,7 +2778,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 		RelToCheck *rtc = (RelToCheck *) lfirst(rt);
 		Relation	testrel = rtc->rel;
 		TupleDesc	tupdesc = RelationGetDescr(testrel);
-		HeapScanDesc scan;
+		StorageScanDesc scan;
 		HeapTuple	tuple;
 		Snapshot	snapshot;
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 3a8dc8eb0c..42e462861b 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -529,7 +529,7 @@ get_all_vacuum_rels(void)
 {
 	List	   *vacrels = NIL;
 	Relation	pgclass;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 
 	pgclass = heap_open(RelationRelationId, AccessShareLock);
@@ -1183,7 +1183,7 @@ vac_truncate_clog(TransactionId frozenXID,
 {
 	TransactionId nextXID = ReadNewTransactionId();
 	Relation	relation;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	Oid			oldestxid_datoid;
 	Oid			minmulti_datoid;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 0c5ae8fa41..fc6c4f909a 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -55,14 +55,14 @@
 
 
 static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
-static void bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres);
+static void bitgetpage(BitmapHeapScanState *node, TBMIterateResult *tbmres);
 static inline void BitmapDoneInitializingSharedState(
 								  ParallelBitmapHeapState *pstate);
 static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node,
 							 TBMIterateResult *tbmres);
 static inline void BitmapAdjustPrefetchTarget(BitmapHeapScanState *node);
 static inline void BitmapPrefetch(BitmapHeapScanState *node,
-			   HeapScanDesc scan);
+			   StorageScanDesc scan);
 static bool BitmapShouldInitializeSharedState(
 								  ParallelBitmapHeapState *pstate);
 
@@ -77,7 +77,8 @@ static TupleTableSlot *
 BitmapHeapNext(BitmapHeapScanState *node)
 {
 	ExprContext *econtext;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
+	HeapPageScanDesc pagescan;
 	TIDBitmap  *tbm;
 	TBMIterator *tbmiterator = NULL;
 	TBMSharedIterator *shared_tbmiterator = NULL;
@@ -93,6 +94,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 	econtext = node->ss.ps.ps_ExprContext;
 	slot = node->ss.ss_ScanTupleSlot;
 	scan = node->ss.ss_currentScanDesc;
+	pagescan = node->pagescan;
 	tbm = node->tbm;
 	if (pstate == NULL)
 		tbmiterator = node->tbmiterator;
@@ -192,8 +194,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 
 	for (;;)
 	{
-		Page		dp;
-		ItemId		lp;
+		StorageTuple tuple;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -220,7 +221,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 			 * least AccessShareLock on the table before performing any of the
 			 * indexscans, but let's be safe.)
 			 */
-			if (tbmres->blockno >= scan->rs_nblocks)
+			if (tbmres->blockno >= pagescan->rs_nblocks)
 			{
 				node->tbmres = tbmres = NULL;
 				continue;
@@ -243,14 +244,14 @@ BitmapHeapNext(BitmapHeapScanState *node)
 				 * The number of tuples on this page is put into
 				 * scan->rs_ntuples; note we don't fill scan->rs_vistuples.
 				 */
-				scan->rs_ntuples = tbmres->ntuples;
+				pagescan->rs_ntuples = tbmres->ntuples;
 			}
 			else
 			{
 				/*
 				 * Fetch the current heap page and identify candidate tuples.
 				 */
-				bitgetpage(scan, tbmres);
+				bitgetpage(node, tbmres);
 			}
 
 			if (tbmres->ntuples >= 0)
@@ -261,7 +262,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 			/*
 			 * Set rs_cindex to first slot to examine
 			 */
-			scan->rs_cindex = 0;
+			pagescan->rs_cindex = 0;
 
 			/* Adjust the prefetch target */
 			BitmapAdjustPrefetchTarget(node);
@@ -271,7 +272,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 			/*
 			 * Continuing in previously obtained page; advance rs_cindex
 			 */
-			scan->rs_cindex++;
+			pagescan->rs_cindex++;
 
 #ifdef USE_PREFETCH
 
@@ -298,7 +299,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 		/*
 		 * Out of range?  If so, nothing more to look at on this page
 		 */
-		if (scan->rs_cindex < 0 || scan->rs_cindex >= scan->rs_ntuples)
+		if (pagescan->rs_cindex < 0 || pagescan->rs_cindex >= pagescan->rs_ntuples)
 		{
 			node->tbmres = tbmres = NULL;
 			continue;
@@ -325,23 +326,14 @@ BitmapHeapNext(BitmapHeapScanState *node)
 			/*
 			 * Okay to fetch the tuple.
 			 */
-			targoffset = scan->rs_vistuples[scan->rs_cindex];
-			dp = (Page) BufferGetPage(scan->rs_cbuf);
-			lp = PageGetItemId(dp, targoffset);
-			Assert(ItemIdIsNormal(lp));
-
-			scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
-			scan->rs_ctup.t_len = ItemIdGetLength(lp);
-			scan->rs_ctup.t_tableOid = scan->rs_rd->rd_id;
-			ItemPointerSet(&scan->rs_ctup.t_self, tbmres->blockno, targoffset);
-
-			pgstat_count_heap_fetch(scan->rs_rd);
+			targoffset = pagescan->rs_vistuples[pagescan->rs_cindex];
+			tuple = storage_fetch_tuple_from_offset(scan, tbmres->blockno, targoffset);
 
 			/*
 			 * Set up the result slot to point to this tuple.  Note that the
 			 * slot acquires a pin on the buffer.
 			 */
-			ExecStoreTuple(&scan->rs_ctup,
+			ExecStoreTuple(tuple,
 						   slot,
 						   scan->rs_cbuf,
 						   false);
@@ -383,8 +375,10 @@ BitmapHeapNext(BitmapHeapScanState *node)
  * interesting according to the bitmap, and visible according to the snapshot.
  */
 static void
-bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
+bitgetpage(BitmapHeapScanState *node, TBMIterateResult *tbmres)
 {
+	StorageScanDesc scan = node->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = node->pagescan;
 	BlockNumber page = tbmres->blockno;
 	Buffer		buffer;
 	Snapshot	snapshot;
@@ -393,7 +387,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
 	/*
 	 * Acquire pin on the target heap page, trading in any pin we held before.
 	 */
-	Assert(page < scan->rs_nblocks);
+	Assert(page < pagescan->rs_nblocks);
 
 	scan->rs_cbuf = ReleaseAndReadBuffer(scan->rs_cbuf,
 										 scan->rs_rd,
@@ -436,7 +430,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
 			ItemPointerSet(&tid, page, offnum);
 			if (storage_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot,
 										  &heapTuple, NULL, true))
-				scan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
+				pagescan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
 		}
 	}
 	else
@@ -452,23 +446,20 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
 		for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
 		{
 			ItemId		lp;
-			HeapTupleData loctup;
+			StorageTuple loctup;
 			bool		valid;
 
 			lp = PageGetItemId(dp, offnum);
 			if (!ItemIdIsNormal(lp))
 				continue;
-			loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
-			loctup.t_len = ItemIdGetLength(lp);
-			loctup.t_tableOid = scan->rs_rd->rd_id;
-			ItemPointerSet(&loctup.t_self, page, offnum);
-			valid = HeapTupleSatisfiesVisibility(scan->rs_rd->rd_stamroutine, &loctup, snapshot, buffer);
+			loctup = storage_fetch_tuple_from_offset(scan, page, offnum);
+			valid = HeapTupleSatisfiesVisibility(scan->rs_rd->rd_stamroutine, loctup, snapshot, buffer);
 			if (valid)
 			{
-				scan->rs_vistuples[ntup++] = offnum;
-				PredicateLockTuple(scan->rs_rd, &loctup, snapshot);
+				pagescan->rs_vistuples[ntup++] = offnum;
+				PredicateLockTuple(scan->rs_rd, loctup, snapshot);
 			}
-			CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
+			CheckForSerializableConflictOut(valid, scan->rs_rd, loctup,
 											buffer, snapshot);
 		}
 	}
@@ -476,7 +467,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
 	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 
 	Assert(ntup <= MaxHeapTuplesPerPage);
-	scan->rs_ntuples = ntup;
+	pagescan->rs_ntuples = ntup;
 }
 
 /*
@@ -602,7 +593,7 @@ BitmapAdjustPrefetchTarget(BitmapHeapScanState *node)
  * BitmapPrefetch - Prefetch, if prefetch_pages are behind prefetch_target
  */
 static inline void
-BitmapPrefetch(BitmapHeapScanState *node, HeapScanDesc scan)
+BitmapPrefetch(BitmapHeapScanState *node, StorageScanDesc scan)
 {
 #ifdef USE_PREFETCH
 	ParallelBitmapHeapState *pstate = node->pstate;
@@ -793,7 +784,7 @@ void
 ExecEndBitmapHeapScan(BitmapHeapScanState *node)
 {
 	Relation	relation;
-	HeapScanDesc scanDesc;
+	StorageScanDesc scanDesc;
 
 	/*
 	 * extract information from the node
@@ -958,6 +949,8 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
 															0,
 															NULL);
 
+	scanstate->pagescan = storageam_get_heappagescandesc(scanstate->ss.ss_currentScanDesc);
+
 	/*
 	 * get the scan type from the relation descriptor.
 	 */
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 7e990dc35e..064b655aea 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -31,9 +31,7 @@ static TupleTableSlot *SampleNext(SampleScanState *node);
 static void tablesample_init(SampleScanState *scanstate);
 static StorageTuple tablesample_getnext(SampleScanState *scanstate);
 static bool SampleTupleVisible(StorageTuple tuple, OffsetNumber tupoffset,
-				   HeapScanDesc scan);
-
-/* hari */
+				   SampleScanState *scanstate);
 
 /* ----------------------------------------------------------------
  *						Scan Support
@@ -357,6 +355,7 @@ tablesample_init(SampleScanState *scanstate)
 									   scanstate->use_bulkread,
 									   allow_sync,
 									   scanstate->use_pagemode);
+		scanstate->pagescan = storageam_get_heappagescandesc(scanstate->ss.ss_currentScanDesc);
 	}
 	else
 	{
@@ -382,10 +381,11 @@ static StorageTuple
 tablesample_getnext(SampleScanState *scanstate)
 {
 	TsmRoutine *tsm = scanstate->tsmroutine;
-	HeapScanDesc scan = scanstate->ss.ss_currentScanDesc;
-	HeapTuple	tuple = &(scan->rs_ctup);
+	StorageScanDesc scan = scanstate->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = scanstate->pagescan;
+	StorageTuple tuple;
 	Snapshot	snapshot = scan->rs_snapshot;
-	bool		pagemode = scan->rs_pageatatime;
+	bool		pagemode = pagescan->rs_pageatatime;
 	BlockNumber blockno;
 	Page		page;
 	bool		all_visible;
@@ -396,10 +396,9 @@ tablesample_getnext(SampleScanState *scanstate)
 		/*
 		 * return null immediately if relation is empty
 		 */
-		if (scan->rs_nblocks == 0)
+		if (pagescan->rs_nblocks == 0)
 		{
 			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
 			return NULL;
 		}
 		if (tsm->NextSampleBlock)
@@ -407,13 +406,12 @@ tablesample_getnext(SampleScanState *scanstate)
 			blockno = tsm->NextSampleBlock(scanstate);
 			if (!BlockNumberIsValid(blockno))
 			{
-				tuple->t_data = NULL;
 				return NULL;
 			}
 		}
 		else
-			blockno = scan->rs_startblock;
-		Assert(blockno < scan->rs_nblocks);
+			blockno = pagescan->rs_startblock;
+		Assert(blockno < pagescan->rs_nblocks);
 		heapgetpage(scan, blockno);
 		scan->rs_inited = true;
 	}
@@ -456,14 +454,12 @@ tablesample_getnext(SampleScanState *scanstate)
 			if (!ItemIdIsNormal(itemid))
 				continue;
 
-			tuple->t_data = (HeapTupleHeader) PageGetItem(page, itemid);
-			tuple->t_len = ItemIdGetLength(itemid);
-			ItemPointerSet(&(tuple->t_self), blockno, tupoffset);
+			tuple = storage_fetch_tuple_from_offset(scan, blockno, tupoffset);
 
 			if (all_visible)
 				visible = true;
 			else
-				visible = SampleTupleVisible(tuple, tupoffset, scan);
+				visible = SampleTupleVisible(tuple, tupoffset, scanstate);
 
 			/* in pagemode, heapgetpage did this for us */
 			if (!pagemode)
@@ -494,14 +490,14 @@ tablesample_getnext(SampleScanState *scanstate)
 		if (tsm->NextSampleBlock)
 		{
 			blockno = tsm->NextSampleBlock(scanstate);
-			Assert(!scan->rs_syncscan);
+			Assert(!pagescan->rs_syncscan);
 			finished = !BlockNumberIsValid(blockno);
 		}
 		else
 		{
 			/* Without NextSampleBlock, just do a plain forward seqscan. */
 			blockno++;
-			if (blockno >= scan->rs_nblocks)
+			if (blockno >= pagescan->rs_nblocks)
 				blockno = 0;
 
 			/*
@@ -514,10 +510,10 @@ tablesample_getnext(SampleScanState *scanstate)
 			 * a little bit backwards on every invocation, which is confusing.
 			 * We don't guarantee any specific ordering in general, though.
 			 */
-			if (scan->rs_syncscan)
+			if (pagescan->rs_syncscan)
 				ss_report_location(scan->rs_rd, blockno);
 
-			finished = (blockno == scan->rs_startblock);
+			finished = (blockno == pagescan->rs_startblock);
 		}
 
 		/*
@@ -529,12 +525,11 @@ tablesample_getnext(SampleScanState *scanstate)
 				ReleaseBuffer(scan->rs_cbuf);
 			scan->rs_cbuf = InvalidBuffer;
 			scan->rs_cblock = InvalidBlockNumber;
-			tuple->t_data = NULL;
 			scan->rs_inited = false;
 			return NULL;
 		}
 
-		Assert(blockno < scan->rs_nblocks);
+		Assert(blockno < pagescan->rs_nblocks);
 		heapgetpage(scan, blockno);
 
 		/* Re-establish state for new page */
@@ -549,16 +544,19 @@ tablesample_getnext(SampleScanState *scanstate)
 	/* Count successfully-fetched tuples as heap fetches */
 	pgstat_count_heap_getnext(scan->rs_rd);
 
-	return &(scan->rs_ctup);
+	return tuple;
 }
 
 /*
  * Check visibility of the tuple.
  */
 static bool
-SampleTupleVisible(StorageTuple tuple, OffsetNumber tupoffset, HeapScanDesc scan) //hari
+SampleTupleVisible(StorageTuple tuple, OffsetNumber tupoffset, SampleScanState *scanstate)
 {
-	if (scan->rs_pageatatime)
+	StorageScanDesc scan = scanstate->ss.ss_currentScanDesc;
+	HeapPageScanDesc pagescan = scanstate->pagescan;
+
+	if (pagescan->rs_pageatatime)
 	{
 		/*
 		 * In pageatatime mode, heapgetpage() already did visibility checks,
@@ -570,12 +568,12 @@ SampleTupleVisible(StorageTuple tuple, OffsetNumber tupoffset, HeapScanDesc scan
 		 * gain to justify the restriction.
 		 */
 		int			start = 0,
-					end = scan->rs_ntuples - 1;
+					end = pagescan->rs_ntuples - 1;
 
 		while (start <= end)
 		{
 			int			mid = (start + end) / 2;
-			OffsetNumber curoffset = scan->rs_vistuples[mid];
+			OffsetNumber curoffset = pagescan->rs_vistuples[mid];
 
 			if (tupoffset == curoffset)
 				return true;
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 7cfc2107f6..32484ea84c 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -317,9 +317,10 @@ void
 ExecSeqScanReInitializeDSM(SeqScanState *node,
 						   ParallelContext *pcxt)
 {
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	ParallelHeapScanDesc pscan;
 
-	heap_parallelscan_reinitialize(scan->rs_parallel);
+	pscan = storageam_get_parallelheapscandesc(node->ss.ss_currentScanDesc);
+	heap_parallelscan_reinitialize(pscan);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index f7438714c4..1d8caf3c79 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -21,6 +21,7 @@
 #include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/nbtree.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "access/transam.h"
 #include "access/xlog.h"
@@ -253,7 +254,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			info->amsearchnulls = amroutine->amsearchnulls;
 			info->amcanparallel = amroutine->amcanparallel;
 			info->amhasgettuple = (amroutine->amgettuple != NULL);
-			info->amhasgetbitmap = (amroutine->amgetbitmap != NULL);
+			info->amhasgetbitmap = ((amroutine->amgetbitmap != NULL)
+									&& (relation->rd_stamroutine->scan_get_heappagescandesc != NULL));
 			info->amcostestimate = amroutine->amcostestimate;
 			Assert(info->amcostestimate != NULL);
 
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0d2e1733bf..ee005d4168 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1865,7 +1865,7 @@ get_database_list(void)
 {
 	List	   *dblist = NIL;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 	MemoryContext resultcxt;
 
@@ -1931,7 +1931,7 @@ do_autovacuum(void)
 {
 	Relation	classRel;
 	HeapTuple	tuple;
-	HeapScanDesc relScan;
+	StorageScanDesc relScan;
 	Form_pg_database dbForm;
 	List	   *table_oids = NIL;
 	List	   *orphan_oids = NIL;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index a4cbedd54a..5b30fb281f 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -1207,7 +1207,7 @@ pgstat_collect_oids(Oid catalogid)
 	HTAB	   *htab;
 	HASHCTL		hash_ctl;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 	Snapshot	snapshot;
 
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index bade3fefc5..a7a2ef7bf6 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -107,7 +107,7 @@ get_subscription_list(void)
 {
 	List	   *res = NIL;
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tup;
 	MemoryContext resultcxt;
 
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index c6791c758c..4140ff7603 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -420,7 +420,7 @@ DefineQueryRewrite(const char *rulename,
 		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
 			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
 		{
-			HeapScanDesc scanDesc;
+			StorageScanDesc scanDesc;
 			Snapshot	snapshot;
 
 			if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 03b7cc76d7..42a35824e5 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -1208,7 +1208,7 @@ static bool
 ThereIsAtLeastOneRole(void)
 {
 	Relation	pg_authid_rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	bool		result;
 
 	pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 4b16de02bd..0501bb7bb0 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -98,6 +98,8 @@ extern Relation heap_openrv_extended(const RangeVar *relation,
 #define heap_close(r,l)  relation_close(r,l)
 
 /* struct definitions appear in relscan.h */
+typedef struct HeapPageScanDescData *HeapPageScanDesc;
+typedef struct StorageScanDescData *StorageScanDesc;
 typedef struct HeapScanDescData *HeapScanDesc;
 typedef struct ParallelHeapScanDescData *ParallelHeapScanDesc;
 
@@ -107,25 +109,25 @@ typedef struct ParallelHeapScanDescData *ParallelHeapScanDesc;
  */
 #define HeapScanIsValid(scan) PointerIsValid(scan)
 
-extern HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot,
-			   int nkeys, ScanKey key,
-			   ParallelHeapScanDesc parallel_scan,
-			   bool allow_strat,
-			   bool allow_sync,
-			   bool allow_pagemode,
-			   bool is_bitmapscan,
-			   bool is_samplescan,
-			   bool temp_snap);
-extern void heap_setscanlimits(HeapScanDesc scan, BlockNumber startBlk,
+extern StorageScanDesc heap_beginscan(Relation relation, Snapshot snapshot,
+									  int nkeys, ScanKey key,
+									  ParallelHeapScanDesc parallel_scan,
+									  bool allow_strat,
+									  bool allow_sync,
+									  bool allow_pagemode,
+									  bool is_bitmapscan,
+									  bool is_samplescan,
+									  bool temp_snap);
+extern void heap_setscanlimits(StorageScanDesc scan, BlockNumber startBlk,
 				   BlockNumber endBlk);
-extern void heapgetpage(HeapScanDesc scan, BlockNumber page);
-extern void heap_rescan(HeapScanDesc scan, ScanKey key, bool set_params,
+extern void heapgetpage(StorageScanDesc scan, BlockNumber page);
+extern void heap_rescan(StorageScanDesc scan, ScanKey key, bool set_params,
 			bool allow_strat, bool allow_sync, bool allow_pagemode);
-extern void heap_rescan_set_params(HeapScanDesc scan, ScanKey key,
+extern void heap_rescan_set_params(StorageScanDesc scan, ScanKey key,
 					   bool allow_strat, bool allow_sync, bool allow_pagemode);
-extern void heap_endscan(HeapScanDesc scan);
-extern StorageTuple heap_getnext(HeapScanDesc scan, ScanDirection direction);
-extern TupleTableSlot *heap_getnextslot(HeapScanDesc sscan, ScanDirection direction,
+extern void heap_endscan(StorageScanDesc scan);
+extern StorageTuple heap_getnext(StorageScanDesc scan, ScanDirection direction);
+extern TupleTableSlot *heap_getnextslot(StorageScanDesc sscan, ScanDirection direction,
 				 TupleTableSlot *slot);
 extern Size heap_parallelscan_estimate(Snapshot snapshot);
 extern void heap_parallelscan_initialize(ParallelHeapScanDesc target,
@@ -181,7 +183,7 @@ extern void simple_heap_update(Relation relation, ItemPointer otid,
 				   HeapTuple tup);
 
 extern void heap_sync(Relation relation);
-extern void heap_update_snapshot(HeapScanDesc scan, Snapshot snapshot);
+extern void heap_update_snapshot(StorageScanDesc scan, Snapshot snapshot);
 
 /* in heap/heapam_visibility.c */
 extern HTSU_Result HeapTupleSatisfiesUpdate(StorageTuple stup, CommandId curcid,
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index 147f862a2b..2651fd73d7 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
+#include "access/storageam.h"
 #include "access/htup_details.h"
 #include "access/itup.h"
 #include "access/tupdesc.h"
@@ -42,40 +43,54 @@ typedef struct ParallelHeapScanDescData
 	char		phs_snapshot_data[FLEXIBLE_ARRAY_MEMBER];
 }			ParallelHeapScanDescData;
 
-typedef struct HeapScanDescData
+typedef struct StorageScanDescData
 {
 	/* scan parameters */
 	Relation	rs_rd;			/* heap relation descriptor */
 	Snapshot	rs_snapshot;	/* snapshot to see */
 	int			rs_nkeys;		/* number of scan keys */
 	ScanKey		rs_key;			/* array of scan key descriptors */
-	bool		rs_bitmapscan;	/* true if this is really a bitmap scan */
-	bool		rs_samplescan;	/* true if this is really a sample scan */
+
+	/* scan current state */
+	bool		rs_inited;		/* false = scan not init'd yet */
+	BlockNumber rs_cblock;		/* current block # in scan, if any */
+	Buffer		rs_cbuf;		/* current buffer in scan, if any */
+}			StorageScanDescData;
+
+typedef struct HeapPageScanDescData
+{
 	bool		rs_pageatatime; /* verify visibility page-at-a-time? */
-	bool		rs_allow_strat; /* allow or disallow use of access strategy */
-	bool		rs_allow_sync;	/* allow or disallow use of syncscan */
-	bool		rs_temp_snap;	/* unregister snapshot at scan end? */
 
 	/* state set up at initscan time */
 	BlockNumber rs_nblocks;		/* total number of blocks in rel */
 	BlockNumber rs_startblock;	/* block # to start at */
 	BlockNumber rs_numblocks;	/* max number of blocks to scan */
+
 	/* rs_numblocks is usually InvalidBlockNumber, meaning "scan whole rel" */
 	BufferAccessStrategy rs_strategy;	/* access strategy for reads */
 	bool		rs_syncscan;	/* report location to syncscan logic? */
 
-	/* scan current state */
-	bool		rs_inited;		/* false = scan not init'd yet */
-	HeapTupleData rs_ctup;		/* current tuple in scan, if any */
-	BlockNumber rs_cblock;		/* current block # in scan, if any */
-	Buffer		rs_cbuf;		/* current buffer in scan, if any */
-	/* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
-	ParallelHeapScanDesc rs_parallel;	/* parallel scan information */
-
 	/* these fields only used in page-at-a-time mode and for bitmap scans */
 	int			rs_cindex;		/* current tuple's index in vistuples */
 	int			rs_ntuples;		/* number of visible tuples on page */
 	OffsetNumber rs_vistuples[MaxHeapTuplesPerPage];	/* their offsets */
+}			HeapPageScanDescData;
+
+typedef struct HeapScanDescData
+{
+	/* scan parameters */
+	StorageScanDescData rs_scan;	/* */
+	HeapPageScanDescData rs_pagescan;
+	bool		rs_bitmapscan;	/* true if this is really a bitmap scan */
+	bool		rs_samplescan;	/* true if this is really a sample scan */
+	bool		rs_allow_strat; /* allow or disallow use of access strategy */
+	bool		rs_allow_sync;	/* allow or disallow use of syncscan */
+	bool		rs_temp_snap;	/* unregister snapshot at scan end? */
+
+	HeapTupleData rs_ctup;		/* current tuple in scan, if any */
+
+	/* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
+	ParallelHeapScanDesc rs_parallel;	/* parallel scan information */
 }			HeapScanDescData;
 
 /*
@@ -149,12 +164,12 @@ typedef struct ParallelIndexScanDescData
 	char		ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER];
 }			ParallelIndexScanDescData;
 
-/* Struct for heap-or-index scans of system tables */
+/* Struct for storage-or-index scans of system tables */
 typedef struct SysScanDescData
 {
 	Relation	heap_rel;		/* catalog being scanned */
 	Relation	irel;			/* NULL if doing heap scan */
-	HeapScanDesc scan;			/* only valid in heap-scan case */
+	StorageScanDesc scan;		/* only valid in storage-scan case */
 	IndexScanDesc iscan;		/* only valid in index-scan case */
 	Snapshot	snapshot;		/* snapshot to unregister at end of scan */
 }			SysScanDescData;
diff --git a/src/include/access/storage_common.h b/src/include/access/storage_common.h
index f9a1075339..0c43ae4310 100644
--- a/src/include/access/storage_common.h
+++ b/src/include/access/storage_common.h
@@ -27,7 +27,6 @@
 
 /* A physical tuple coming from a storage AM scan */
 typedef void *StorageTuple;
-typedef void *StorageScanDesc;
 
 /*
  * slot storage routine functions
diff --git a/src/include/access/storageam.h b/src/include/access/storageam.h
index b08d7f401e..e1d01193d3 100644
--- a/src/include/access/storageam.h
+++ b/src/include/access/storageam.h
@@ -40,29 +40,31 @@ typedef List *(*InsertIndexTuples) (TupleTableSlot *slot, EState *estate, bool n
 									bool *specConflict, List *arbiterIndexes);
 
 
-extern HeapScanDesc storage_beginscan_parallel(Relation relation, ParallelHeapScanDesc parallel_scan);
-
-extern void storage_setscanlimits(HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
-extern HeapScanDesc storage_beginscan(Relation relation, Snapshot snapshot,
-				  int nkeys, ScanKey key);
-extern HeapScanDesc storage_beginscan_catalog(Relation relation, int nkeys, ScanKey key);
-extern HeapScanDesc storage_beginscan_strat(Relation relation, Snapshot snapshot,
-						int nkeys, ScanKey key,
-						bool allow_strat, bool allow_sync);
-extern HeapScanDesc storage_beginscan_bm(Relation relation, Snapshot snapshot,
-					 int nkeys, ScanKey key);
-extern HeapScanDesc storage_beginscan_sampling(Relation relation, Snapshot snapshot,
-						   int nkeys, ScanKey key,
-						   bool allow_strat, bool allow_sync, bool allow_pagemode);
-
-extern void storage_endscan(HeapScanDesc scan);
-extern void storage_rescan(HeapScanDesc scan, ScanKey key);
-extern void storage_rescan_set_params(HeapScanDesc scan, ScanKey key,
+extern StorageScanDesc storage_beginscan_parallel(Relation relation, ParallelHeapScanDesc parallel_scan);
+extern ParallelHeapScanDesc storageam_get_parallelheapscandesc(StorageScanDesc sscan);
+extern HeapPageScanDesc storageam_get_heappagescandesc(StorageScanDesc sscan);
+extern void storage_setscanlimits(StorageScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
+extern StorageScanDesc storage_beginscan(Relation relation, Snapshot snapshot,
+										 int nkeys, ScanKey key);
+extern StorageScanDesc storage_beginscan_catalog(Relation relation, int nkeys, ScanKey key);
+extern StorageScanDesc storage_beginscan_strat(Relation relation, Snapshot snapshot,
+											   int nkeys, ScanKey key,
+											   bool allow_strat, bool allow_sync);
+extern StorageScanDesc storage_beginscan_bm(Relation relation, Snapshot snapshot,
+											int nkeys, ScanKey key);
+extern StorageScanDesc storage_beginscan_sampling(Relation relation, Snapshot snapshot,
+												  int nkeys, ScanKey key,
+												  bool allow_strat, bool allow_sync, bool allow_pagemode);
+
+extern void storage_endscan(StorageScanDesc scan);
+extern void storage_rescan(StorageScanDesc scan, ScanKey key);
+extern void storage_rescan_set_params(StorageScanDesc scan, ScanKey key,
 						  bool allow_strat, bool allow_sync, bool allow_pagemode);
-extern void storage_update_snapshot(HeapScanDesc scan, Snapshot snapshot);
+extern void storage_update_snapshot(StorageScanDesc scan, Snapshot snapshot);
 
-extern StorageTuple storage_getnext(HeapScanDesc sscan, ScanDirection direction);
-extern TupleTableSlot *storage_getnextslot(HeapScanDesc sscan, ScanDirection direction, TupleTableSlot *slot);
+extern StorageTuple storage_getnext(StorageScanDesc sscan, ScanDirection direction);
+extern TupleTableSlot *storage_getnextslot(StorageScanDesc sscan, ScanDirection direction, TupleTableSlot *slot);
+extern StorageTuple storage_fetch_tuple_from_offset(StorageScanDesc sscan, BlockNumber blkno, OffsetNumber offset);
 
 extern void storage_get_latest_tid(Relation relation,
 					   Snapshot snapshot,
diff --git a/src/include/access/storageamapi.h b/src/include/access/storageamapi.h
index 4ea2ac4388..d626115b51 100644
--- a/src/include/access/storageamapi.h
+++ b/src/include/access/storageamapi.h
@@ -81,32 +81,37 @@ typedef StorageTuple(*TupleFromDatum_function) (Datum data, Oid tableoid);
 typedef void (*RelationSync_function) (Relation relation);
 
 
-typedef HeapScanDesc (*ScanBegin_function) (Relation relation,
-											Snapshot snapshot,
-											int nkeys, ScanKey key,
-											ParallelHeapScanDesc parallel_scan,
-											bool allow_strat,
-											bool allow_sync,
-											bool allow_pagemode,
-											bool is_bitmapscan,
-											bool is_samplescan,
-											bool temp_snap);
-typedef void (*ScanSetlimits_function) (HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
+typedef StorageScanDesc(*ScanBegin_function) (Relation relation,
+											  Snapshot snapshot,
+											  int nkeys, ScanKey key,
+											  ParallelHeapScanDesc parallel_scan,
+											  bool allow_strat,
+											  bool allow_sync,
+											  bool allow_pagemode,
+											  bool is_bitmapscan,
+											  bool is_samplescan,
+											  bool temp_snap);
+typedef ParallelHeapScanDesc (*ScanGetParallelheapscandesc_function) (StorageScanDesc scan);
+typedef HeapPageScanDesc(*ScanGetHeappagescandesc_function) (StorageScanDesc scan);
+
+typedef void (*ScanSetlimits_function) (StorageScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks);
 
 /* must return a TupleTableSlot? */
-typedef StorageTuple(*ScanGetnext_function) (HeapScanDesc scan,
+typedef StorageTuple(*ScanGetnext_function) (StorageScanDesc scan,
 											 ScanDirection direction);
 
-typedef TupleTableSlot *(*ScanGetnextSlot_function) (HeapScanDesc scan,
+typedef TupleTableSlot *(*ScanGetnextSlot_function) (StorageScanDesc scan,
 													 ScanDirection direction, TupleTableSlot *slot);
+typedef StorageTuple(*ScanFetchTupleFromOffset_function) (StorageScanDesc scan,
+														  BlockNumber blkno, OffsetNumber offset);
 
-typedef void (*ScanEnd_function) (HeapScanDesc scan);
+typedef void (*ScanEnd_function) (StorageScanDesc scan);
 
 
-typedef void (*ScanGetpage_function) (HeapScanDesc scan, BlockNumber page);
-typedef void (*ScanRescan_function) (HeapScanDesc scan, ScanKey key, bool set_params,
+typedef void (*ScanGetpage_function) (StorageScanDesc scan, BlockNumber page);
+typedef void (*ScanRescan_function) (StorageScanDesc scan, ScanKey key, bool set_params,
 									 bool allow_strat, bool allow_sync, bool allow_pagemode);
-typedef void (*ScanUpdateSnapshot_function) (HeapScanDesc scan, Snapshot snapshot);
+typedef void (*ScanUpdateSnapshot_function) (StorageScanDesc scan, Snapshot snapshot);
 
 typedef bool (*HotSearchBuffer_function) (ItemPointer tid, Relation relation,
 										  Buffer buffer, Snapshot snapshot, HeapTuple heapTuple,
@@ -148,9 +153,12 @@ typedef struct StorageAmRoutine
 
 	/* Operations on relation scans */
 	ScanBegin_function scan_begin;
+	ScanGetParallelheapscandesc_function scan_get_parallelheapscandesc;
+	ScanGetHeappagescandesc_function scan_get_heappagescandesc;
 	ScanSetlimits_function scansetlimits;
 	ScanGetnext_function scan_getnext;
 	ScanGetnextSlot_function scan_getnextslot;
+	ScanFetchTupleFromOffset_function scan_fetch_tuple_from_offset;
 	ScanEnd_function scan_end;
 	ScanGetpage_function scan_getpage;
 	ScanRescan_function scan_rescan;
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 75ca1543fc..62bb60c301 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1118,7 +1118,7 @@ typedef struct ScanState
 {
 	PlanState	ps;				/* its first field is NodeTag */
 	Relation	ss_currentRelation;
-	HeapScanDesc ss_currentScanDesc;
+	StorageScanDesc ss_currentScanDesc;
 	TupleTableSlot *ss_ScanTupleSlot;
 } ScanState;
 
@@ -1139,6 +1139,7 @@ typedef struct SeqScanState
 typedef struct SampleScanState
 {
 	ScanState	ss;
+	HeapPageScanDesc pagescan;
 	List	   *args;			/* expr states for TABLESAMPLE params */
 	ExprState  *repeatable;		/* expr state for REPEATABLE expr */
 	/* use struct pointer to avoid including tsmapi.h here */
@@ -1367,6 +1368,7 @@ typedef struct ParallelBitmapHeapState
 typedef struct BitmapHeapScanState
 {
 	ScanState	ss;				/* its first field is NodeTag */
+	HeapPageScanDesc pagescan;
 	ExprState  *bitmapqualorig;
 	TIDBitmap  *tbm;
 	TBMIterator *tbmiterator;
-- 
2.15.0.windows.1

