From 9041e7225262a3ab81e85a69288c2bdbd9a6f684 Mon Sep 17 00:00:00 2001
From: Hari <haribabuk@fast.au.fujitsu.com>
Date: Fri, 9 Jun 2017 11:36:35 +1000
Subject: [PATCH 08/10] Replace heap_* functions with storage access methods

Replace all heap_* functions with storage access methods
in the entire code, but these are not yet removed the
HeapTuple and HeapScanDesc use.
---
 contrib/pgrowlocks/pgrowlocks.c            | 14 +++++---
 contrib/pgstattuple/pgstattuple.c          |  9 ++---
 contrib/postgres_fdw/postgres_fdw.c        |  2 +-
 contrib/tsm_system_rows/tsm_system_rows.c  |  8 ++---
 contrib/tsm_system_time/tsm_system_time.c  |  2 +-
 src/backend/access/index/genam.c           |  8 +++--
 src/backend/bootstrap/bootstrap.c          | 30 ++++++++++-------
 src/backend/catalog/aclchk.c               | 17 ++++++----
 src/backend/catalog/index.c                | 32 +++++++++++-------
 src/backend/catalog/pg_conversion.c        | 10 +++---
 src/backend/catalog/pg_db_role_setting.c   | 10 +++---
 src/backend/catalog/pg_publication.c       |  8 +++--
 src/backend/catalog/pg_subscription.c      |  7 ++--
 src/backend/commands/cluster.c             | 18 ++++++----
 src/backend/commands/copy.c                |  7 ++--
 src/backend/commands/dbcommands.c          | 26 +++++++++-----
 src/backend/commands/indexcmds.c           |  9 +++--
 src/backend/commands/tablecmds.c           | 42 +++++++++++++----------
 src/backend/commands/tablespace.c          | 54 +++++++++++++++++-------------
 src/backend/commands/typecmds.c            | 15 +++++----
 src/backend/commands/vacuum.c              | 18 ++++++----
 src/backend/executor/execReplication.c     | 12 ++++---
 src/backend/executor/nodeBitmapHeapscan.c  | 13 +++----
 src/backend/executor/nodeSamplescan.c      |  6 ++--
 src/backend/executor/nodeSeqscan.c         | 11 +++---
 src/backend/postmaster/autovacuum.c        | 23 ++++++++-----
 src/backend/postmaster/pgstat.c            |  9 +++--
 src/backend/replication/logical/launcher.c |  8 +++--
 src/backend/rewrite/rewriteDefine.c        |  9 +++--
 src/backend/utils/init/postinit.c          |  9 +++--
 30 files changed, 269 insertions(+), 177 deletions(-)

diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index 00e2015..97ee00f 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -26,6 +26,7 @@
 
 #include "access/multixact.h"
 #include "access/relscan.h"
+#include "access/storageamapi.h"
 #include "access/xact.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_authid.h"
@@ -55,7 +56,7 @@ PG_FUNCTION_INFO_V1(pgrowlocks);
 typedef struct
 {
 	Relation	rel;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	int			ncolumns;
 } MyData;
 
@@ -70,13 +71,16 @@ Datum
 pgrowlocks(PG_FUNCTION_ARGS)
 {
 	FuncCallContext *funcctx;
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	TupleDesc	tupdesc;
 	AttInMetadata *attinmeta;
 	Datum		result;
 	MyData	   *mydata;
 	Relation	rel;
+	StorageAmRoutine *method;
+
+	method = rel->rd_stamroutine;
 
 	if (SRF_IS_FIRSTCALL())
 	{
@@ -112,7 +116,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 			aclcheck_error(aclresult, ACL_KIND_CLASS,
 						   RelationGetRelationName(rel));
 
-		scan = heap_beginscan(rel, GetActiveSnapshot(), 0, NULL);
+		scan = method->scan_begin(rel, GetActiveSnapshot(), 0, NULL);
 		mydata = palloc(sizeof(*mydata));
 		mydata->rel = rel;
 		mydata->scan = scan;
@@ -128,7 +132,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 	scan = mydata->scan;
 
 	/* scan the relation */
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		HTSU_Result htsu;
 		TransactionId xmax;
@@ -293,7 +297,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 		}
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(mydata->rel, AccessShareLock);
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index eb02ec5..5ff67e4 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -314,7 +314,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 static Datum
 pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 {
-	HeapScanDesc scan;
+	StorageScanDesc scan;
 	HeapTuple	tuple;
 	BlockNumber nblocks;
 	BlockNumber block = 0;		/* next block to count free space in */
@@ -322,15 +322,16 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 	Buffer		buffer;
 	pgstattuple_type stat = {0};
 	SnapshotData SnapshotDirty;
+	StorageAmRoutine *method = rel->rd_stamroutine;
 
 	/* Disable syncscan because we assume we scan from block zero upwards */
-	scan = heap_beginscan_strat(rel, SnapshotAny, 0, NULL, true, false);
+	scan = method->scan_begin_strat(rel, SnapshotAny, 0, NULL, true, false);
 	InitDirtySnapshot(SnapshotDirty);
 
 	nblocks = scan->rs_nblocks; /* # blocks to be scanned */
 
 	/* scan the relation */
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		CHECK_FOR_INTERRUPTS();
 
@@ -383,7 +384,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 		block++;
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	relation_close(rel, AccessShareLock);
 
 	stat.table_len = (uint64) nblocks *BLCKSZ;
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 080cb0a..498b812 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -3219,7 +3219,7 @@ convert_prep_stmt_params(PgFdwModifyState *fmstate,
 			Datum		value;
 			bool		isnull;
 
-			value = slot_getattr(slot, attnum, &isnull);
+			value = slot->tts_storageam->slot_getattr(slot, attnum, &isnull);
 			if (isnull)
 				p_values[pindex] = NULL;
 			else
diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c
index 544458e..ed0078e 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, StorageScanDesc 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;
+	StorageScanDesc scan = node->ss.ss_currentScanDesc;
 
 	/* First call within scan? */
 	if (sampler->doneblocks == 0)
@@ -278,7 +278,7 @@ system_rows_nextsampletuple(SampleScanState *node,
 							OffsetNumber maxoffset)
 {
 	SystemRowsSamplerData *sampler = (SystemRowsSamplerData *) node->tsm_state;
-	HeapScanDesc scan = node->ss.ss_currentScanDesc;
+	StorageScanDesc scan = node->ss.ss_currentScanDesc;
 	OffsetNumber tupoffset = sampler->lt;
 
 	/* Quit if we've returned all needed tuples */
@@ -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, StorageScanDesc 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 af8d025..4c32166 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;
+	StorageScanDesc scan = node->ss.ss_currentScanDesc;
 	instr_time	cur_time;
 
 	/* First call within scan? */
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index a91fda7..7b85395 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -20,6 +20,7 @@
 #include "postgres.h"
 
 #include "access/relscan.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "catalog/index.h"
 #include "lib/stringinfo.h"
@@ -387,6 +388,7 @@ systable_beginscan(Relation heapRelation,
 	}
 	else
 	{
+		StorageAmRoutine *method = heapRelation->rd_stamroutine;
 		/*
 		 * We disallow synchronized scans when forced to use a heapscan on a
 		 * catalog.  In most cases the desired rows are near the front, so
@@ -394,7 +396,7 @@ systable_beginscan(Relation heapRelation,
 		 * disadvantage; and there are no compensating advantages, because
 		 * it's unlikely that such scans will occur in parallel.
 		 */
-		sysscan->scan = heap_beginscan_strat(heapRelation, snapshot,
+		sysscan->scan = method->scan_begin_strat(heapRelation, snapshot,
 											 nkeys, key,
 											 true, false);
 		sysscan->iscan = NULL;
@@ -432,7 +434,7 @@ systable_getnext(SysScanDesc sysscan)
 			elog(ERROR, "system catalog scans with lossy index conditions are not implemented");
 	}
 	else
-		htup = heap_getnext(sysscan->scan, ForwardScanDirection);
+		htup = sysscan->heap_rel->rd_stamroutine->scan_getnext(sysscan->scan, ForwardScanDirection);
 
 	return htup;
 }
@@ -504,7 +506,7 @@ systable_endscan(SysScanDesc sysscan)
 		index_close(sysscan->irel, AccessShareLock);
 	}
 	else
-		heap_endscan(sysscan->scan);
+		sysscan->heap_rel->rd_stamroutine->scan_end(sysscan->scan);
 
 	if (sysscan->snapshot)
 		UnregisterSnapshot(sysscan->snapshot);
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 4c28b2b..9b7241a 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -18,6 +18,7 @@
 #include <signal.h>
 
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/xact.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/index.h"
@@ -571,20 +572,23 @@ boot_openrel(char *relname)
 
 	if (Typ == NULL)
 	{
+		StorageAmRoutine *method;
+
 		/* We can now load the pg_type data */
 		rel = heap_open(TypeRelationId, NoLock);
-		scan = heap_beginscan_catalog(rel, 0, NULL);
+		method = rel->rd_stamroutine;
+		scan = method->scan_begin_catalog(rel, 0, NULL);
 		i = 0;
-		while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tup = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 			++i;
-		heap_endscan(scan);
+		method->scan_end(scan);
 		app = Typ = ALLOC(struct typmap *, i + 1);
 		while (i-- > 0)
 			*app++ = ALLOC(struct typmap, 1);
 		*app = NULL;
-		scan = heap_beginscan_catalog(rel, 0, NULL);
+		scan = method->scan_begin_catalog(rel, 0, NULL);
 		app = Typ;
-		while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tup = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			(*app)->am_oid = HeapTupleGetOid(tup);
 			memcpy((char *) &(*app)->am_typ,
@@ -592,7 +596,7 @@ boot_openrel(char *relname)
 				   sizeof((*app)->am_typ));
 			app++;
 		}
-		heap_endscan(scan);
+		method->scan_end(scan);
 		heap_close(rel, NoLock);
 	}
 
@@ -877,6 +881,7 @@ gettype(char *type)
 	HeapScanDesc scan;
 	HeapTuple	tup;
 	struct typmap **app;
+	StorageAmRoutine *method;
 
 	if (Typ != NULL)
 	{
@@ -898,25 +903,26 @@ gettype(char *type)
 		}
 		elog(DEBUG4, "external type: %s", type);
 		rel = heap_open(TypeRelationId, NoLock);
-		scan = heap_beginscan_catalog(rel, 0, NULL);
+		method = rel->rd_stamroutine;
+		scan = method->scan_begin_catalog(rel, 0, NULL);
 		i = 0;
-		while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tup = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 			++i;
-		heap_endscan(scan);
+		method->scan_end(scan);
 		app = Typ = ALLOC(struct typmap *, i + 1);
 		while (i-- > 0)
 			*app++ = ALLOC(struct typmap, 1);
 		*app = NULL;
-		scan = heap_beginscan_catalog(rel, 0, NULL);
+		scan = method->scan_begin_catalog(rel, 0, NULL);
 		app = Typ;
-		while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tup = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			(*app)->am_oid = HeapTupleGetOid(tup);
 			memmove((char *) &(*app++)->am_typ,
 					(char *) GETSTRUCT(tup),
 					sizeof((*app)->am_typ));
 		}
-		heap_endscan(scan);
+		method->scan_end(scan);
 		heap_close(rel, NoLock);
 		return gettype(type);
 	}
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 387a3be..22ccd34 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -20,6 +20,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "catalog/binary_upgrade.h"
@@ -790,6 +791,7 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
 					Relation	rel;
 					HeapScanDesc scan;
 					HeapTuple	tuple;
+					StorageAmRoutine *method;
 
 					ScanKeyInit(&key[0],
 								Anum_pg_proc_pronamespace,
@@ -797,14 +799,15 @@ objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
 								ObjectIdGetDatum(namespaceId));
 
 					rel = heap_open(ProcedureRelationId, AccessShareLock);
-					scan = heap_beginscan_catalog(rel, 1, key);
+					method = rel->rd_stamroutine;
+					scan = method->scan_begin_catalog(rel, 1, key);
 
-					while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+					while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 					{
 						objects = lappend_oid(objects, HeapTupleGetOid(tuple));
 					}
 
-					heap_endscan(scan);
+					method->scan_end(scan);
 					heap_close(rel, AccessShareLock);
 				}
 				break;
@@ -831,6 +834,7 @@ getRelationsInNamespace(Oid namespaceId, char relkind)
 	Relation	rel;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
+	StorageAmRoutine *method;
 
 	ScanKeyInit(&key[0],
 				Anum_pg_class_relnamespace,
@@ -842,14 +846,15 @@ getRelationsInNamespace(Oid namespaceId, char relkind)
 				CharGetDatum(relkind));
 
 	rel = heap_open(RelationRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 2, key);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 2, key);
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		relations = lappend_oid(relations, HeapTupleGetOid(tuple));
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 
 	return relations;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 558dbbc..42be25b 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1892,16 +1892,18 @@ index_update_stats(Relation rel,
 		/* don't assume syscache will work */
 		HeapScanDesc pg_class_scan;
 		ScanKeyData key[1];
+		StorageAmRoutine *method;
 
 		ScanKeyInit(&key[0],
 					ObjectIdAttributeNumber,
 					BTEqualStrategyNumber, F_OIDEQ,
 					ObjectIdGetDatum(relid));
 
-		pg_class_scan = heap_beginscan_catalog(pg_class, 1, key);
-		tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
+		method =  pg_class->rd_stamroutine;
+		pg_class_scan = method->scan_begin_catalog(pg_class, 1, key);
+		tuple = method->scan_getnext(pg_class_scan, ForwardScanDirection);
 		tuple = heap_copytuple(tuple);
-		heap_endscan(pg_class_scan);
+		method->scan_end(pg_class_scan);
 	}
 	else
 	{
@@ -2216,6 +2218,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 	TransactionId OldestXmin;
 	BlockNumber root_blkno = InvalidBlockNumber;
 	OffsetNumber root_offsets[MaxHeapTuplesPerPage];
+	StorageAmRoutine *method;
 
 	/*
 	 * sanity checks
@@ -2271,7 +2274,8 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 		OldestXmin = GetOldestXmin(heapRelation, PROCARRAY_FLAGS_VACUUM);
 	}
 
-	scan = heap_beginscan_strat(heapRelation,	/* relation */
+	method = heapRelation->rd_stamroutine;
+	scan = method->scan_begin_strat(heapRelation,	/* relation */
 								snapshot,		/* snapshot */
 								0,		/* number of keys */
 								NULL,	/* scan key */
@@ -2280,7 +2284,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 
 	/* set our scan endpoints */
 	if (!allow_sync)
-		heap_setscanlimits(scan, start_blockno, numblocks);
+		method->scansetlimits(scan, start_blockno, numblocks);
 	else
 	{
 		/* syncscan can only be requested on whole relation */
@@ -2293,7 +2297,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 	/*
 	 * Scan all tuples in the base relation.
 	 */
-	while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((heapTuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		bool		tupleIsAlive;
 
@@ -2605,7 +2609,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 		}
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	/* we can now forget our snapshot, if set */
 	if (IsBootstrapProcessingMode() || indexInfo->ii_Concurrent)
@@ -2649,6 +2653,7 @@ IndexCheckExclusion(Relation heapRelation,
 	EState	   *estate;
 	ExprContext *econtext;
 	Snapshot	snapshot;
+	StorageAmRoutine *method = heapRelation->rd_stamroutine;
 
 	/*
 	 * If we are reindexing the target index, mark it as no longer being
@@ -2676,14 +2681,14 @@ IndexCheckExclusion(Relation heapRelation,
 	 * Scan all live tuples in the base relation.
 	 */
 	snapshot = RegisterSnapshot(GetLatestSnapshot());
-	scan = heap_beginscan_strat(heapRelation,	/* relation */
+	scan = method->scan_begin_strat(heapRelation,	/* relation */
 								snapshot,		/* snapshot */
 								0,		/* number of keys */
 								NULL,	/* scan key */
 								true,	/* buffer access strategy OK */
 								true);	/* syncscan OK */
 
-	while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((heapTuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		CHECK_FOR_INTERRUPTS();
 
@@ -2719,7 +2724,7 @@ IndexCheckExclusion(Relation heapRelation,
 								   estate, true);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	UnregisterSnapshot(snapshot);
 
 	ExecDropSingleTupleTableSlot(slot);
@@ -2970,6 +2975,7 @@ validate_index_heapscan(Relation heapRelation,
 	ItemPointer indexcursor = NULL;
 	ItemPointerData decoded;
 	bool		tuplesort_empty = false;
+	StorageAmRoutine *method = heapRelation->rd_stamroutine;
 
 	/*
 	 * sanity checks
@@ -2996,7 +3002,7 @@ validate_index_heapscan(Relation heapRelation,
 	 * here, because it's critical that we read from block zero forward to
 	 * match the sorted TIDs.
 	 */
-	scan = heap_beginscan_strat(heapRelation,	/* relation */
+	scan = method->scan_begin_strat(heapRelation,	/* relation */
 								snapshot,		/* snapshot */
 								0,		/* number of keys */
 								NULL,	/* scan key */
@@ -3006,7 +3012,7 @@ validate_index_heapscan(Relation heapRelation,
 	/*
 	 * Scan all tuples matching the snapshot.
 	 */
-	while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((heapTuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		ItemPointer heapcursor = &heapTuple->t_self;
 		ItemPointerData rootTuple;
@@ -3163,7 +3169,7 @@ validate_index_heapscan(Relation heapRelation,
 		}
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	ExecDropSingleTupleTableSlot(slot);
 
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 5746dc3..01fb130 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -16,6 +16,7 @@
 
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
@@ -152,6 +153,7 @@ RemoveConversionById(Oid conversionOid)
 	HeapTuple	tuple;
 	HeapScanDesc scan;
 	ScanKeyData scanKeyData;
+	StorageAmRoutine *method;
 
 	ScanKeyInit(&scanKeyData,
 				ObjectIdAttributeNumber,
@@ -160,15 +162,15 @@ RemoveConversionById(Oid conversionOid)
 
 	/* open pg_conversion */
 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
-
-	scan = heap_beginscan_catalog(rel, 1, &scanKeyData);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 1, &scanKeyData);
 
 	/* search for the target tuple */
-	if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
+	if (HeapTupleIsValid(tuple = method->scan_getnext(scan, ForwardScanDirection)))
 		CatalogTupleDelete(rel, &tuple->t_self);
 	else
 		elog(ERROR, "could not find tuple for conversion %u", conversionOid);
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, RowExclusiveLock);
 }
 
diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c
index 323471b..c0adb61 100644
--- a/src/backend/catalog/pg_db_role_setting.c
+++ b/src/backend/catalog/pg_db_role_setting.c
@@ -13,6 +13,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "catalog/indexing.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_db_role_setting.h"
@@ -174,9 +175,10 @@ DropSetting(Oid databaseid, Oid roleid)
 	ScanKeyData keys[2];
 	HeapTuple	tup;
 	int			numkeys = 0;
+	StorageAmRoutine *method;
 
 	relsetting = heap_open(DbRoleSettingRelationId, RowExclusiveLock);
-
+	method = relsetting->rd_stamroutine;
 	if (OidIsValid(databaseid))
 	{
 		ScanKeyInit(&keys[numkeys],
@@ -196,12 +198,12 @@ DropSetting(Oid databaseid, Oid roleid)
 		numkeys++;
 	}
 
-	scan = heap_beginscan_catalog(relsetting, numkeys, keys);
-	while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+	scan = method->scan_begin_catalog(relsetting, numkeys, keys);
+	while (HeapTupleIsValid(tup = method->scan_getnext(scan, ForwardScanDirection)))
 	{
 		CatalogTupleDelete(relsetting, &tup->t_self);
 	}
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	heap_close(relsetting, RowExclusiveLock);
 }
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 17105f4..f1eeccb 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -292,17 +292,19 @@ GetAllTablesPublicationRelations(void)
 	HeapScanDesc scan;
 	HeapTuple	tuple;
 	List	   *result = NIL;
+	StorageAmRoutine *method;
 
 	classRel = heap_open(RelationRelationId, AccessShareLock);
+	method = classRel->rd_stamroutine;
 
 	ScanKeyInit(&key[0],
 				Anum_pg_class_relkind,
 				BTEqualStrategyNumber, F_CHAREQ,
 				CharGetDatum(RELKIND_RELATION));
 
-	scan = heap_beginscan_catalog(classRel, 1, key);
+	scan = method->scan_begin_catalog(classRel, 1, key);
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Oid			relid = HeapTupleGetOid(tuple);
 		Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
@@ -311,7 +313,7 @@ GetAllTablesPublicationRelations(void)
 			result = lappend_oid(result, relid);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(classRel, AccessShareLock);
 
 	return result;
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index ab5f371..93d89d2 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -19,6 +19,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/xact.h"
 
 #include "catalog/indexing.h"
@@ -393,12 +394,12 @@ RemoveSubscriptionRel(Oid subid, Oid relid)
 	}
 
 	/* Do the search and delete what we found. */
-	scan = heap_beginscan_catalog(rel, nkeys, skey);
-	while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+	scan = rel->rd_stamroutine->scan_begin_catalog(rel, nkeys, skey);
+	while (HeapTupleIsValid(tup = rel->rd_stamroutine->scan_getnext(scan, ForwardScanDirection)))
 	{
 		simple_heap_delete(rel, &tup->t_self);
 	}
-	heap_endscan(scan);
+	rel->rd_stamroutine->scan_end(scan);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index ef1abf3..5786226 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -21,6 +21,7 @@
 #include "access/multixact.h"
 #include "access/relscan.h"
 #include "access/rewriteheap.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "access/tuptoaster.h"
 #include "access/xact.h"
@@ -758,6 +759,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 				tups_recently_dead = 0;
 	int			elevel = verbose ? INFO : DEBUG2;
 	PGRUsage	ru0;
+	StorageAmRoutine *method;
 
 	pg_rusage_init(&ru0);
 
@@ -771,6 +773,8 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 	else
 		OldIndex = NULL;
 
+	method = OldHeap->rd_stamroutine;
+
 	/*
 	 * Their tuple descriptors should be exactly alike, but here we only need
 	 * assume that they have the same number of columns.
@@ -908,7 +912,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 	}
 	else
 	{
-		heapScan = heap_beginscan(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
+		heapScan = method->scan_begin(OldHeap, SnapshotAny, 0, (ScanKey) NULL);
 		indexScan = NULL;
 	}
 
@@ -958,7 +962,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 		}
 		else
 		{
-			tuple = heap_getnext(heapScan, ForwardScanDirection);
+			tuple = method->scan_getnext(heapScan, ForwardScanDirection);
 			if (tuple == NULL)
 				break;
 
@@ -1044,7 +1048,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 	if (indexScan != NULL)
 		index_endscan(indexScan);
 	if (heapScan != NULL)
-		heap_endscan(heapScan);
+		method->scan_end(heapScan);
 
 	/*
 	 * In scan-and-sort mode, complete the sort, then read out all live tuples
@@ -1643,6 +1647,7 @@ get_tables_to_cluster(MemoryContext cluster_context)
 	MemoryContext old_context;
 	RelToCluster *rvtc;
 	List	   *rvs = NIL;
+	StorageAmRoutine *method;
 
 	/*
 	 * Get all indexes that have indisclustered set and are owned by
@@ -1651,12 +1656,13 @@ get_tables_to_cluster(MemoryContext cluster_context)
 	 * called with one of them as argument.
 	 */
 	indRelation = heap_open(IndexRelationId, AccessShareLock);
+	method = indRelation->rd_stamroutine;
 	ScanKeyInit(&entry,
 				Anum_pg_index_indisclustered,
 				BTEqualStrategyNumber, F_BOOLEQ,
 				BoolGetDatum(true));
-	scan = heap_beginscan_catalog(indRelation, 1, &entry);
-	while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	scan = method->scan_begin_catalog(indRelation, 1, &entry);
+	while ((indexTuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		index = (Form_pg_index) GETSTRUCT(indexTuple);
 
@@ -1676,7 +1682,7 @@ get_tables_to_cluster(MemoryContext cluster_context)
 
 		MemoryContextSwitchTo(old_context);
 	}
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	relation_close(indRelation, AccessShareLock);
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index afa4cb1..810c0cd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2042,14 +2042,15 @@ CopyTo(CopyState cstate)
 		bool	   *nulls;
 		HeapScanDesc scandesc;
 		HeapTuple	tuple;
+		StorageAmRoutine *method = cstate->rel->rd_stamroutine;
 
 		values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
 		nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));
 
-		scandesc = heap_beginscan(cstate->rel, GetActiveSnapshot(), 0, NULL);
+		scandesc = method->scan_begin(cstate->rel, GetActiveSnapshot(), 0, NULL);
 
 		processed = 0;
-		while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL)
+		while ((tuple = method->scan_getnext(scandesc, ForwardScanDirection)) != NULL)
 		{
 			CHECK_FOR_INTERRUPTS();
 
@@ -2061,7 +2062,7 @@ CopyTo(CopyState cstate)
 			processed++;
 		}
 
-		heap_endscan(scandesc);
+		method->scan_end(scandesc);
 
 		pfree(values);
 		pfree(nulls);
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 11038f6..ed19018 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -26,6 +26,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/xact.h"
 #include "access/xloginsert.h"
 #include "access/xlogutils.h"
@@ -585,13 +586,16 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 	PG_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
 							PointerGetDatum(&fparms));
 	{
+		StorageAmRoutine *method;
+
 		/*
 		 * Iterate through all tablespaces of the template database, and copy
 		 * each one to the new database.
 		 */
 		rel = heap_open(TableSpaceRelationId, AccessShareLock);
-		scan = heap_beginscan_catalog(rel, 0, NULL);
-		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		method = rel->rd_stamroutine;
+		scan = method->scan_begin_catalog(rel, 0, NULL);
+		while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			Oid			srctablespace = HeapTupleGetOid(tuple);
 			Oid			dsttablespace;
@@ -643,7 +647,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 								  XLOG_DBASE_CREATE | XLR_SPECIAL_REL_UPDATE);
 			}
 		}
-		heap_endscan(scan);
+		method->scan_end(scan);
 		heap_close(rel, AccessShareLock);
 
 		/*
@@ -1873,10 +1877,12 @@ remove_dbtablespaces(Oid db_id)
 	Relation	rel;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
+	StorageAmRoutine *method;
 
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 0, NULL);
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 0, NULL);
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Oid			dsttablespace = HeapTupleGetOid(tuple);
 		char	   *dstpath;
@@ -1917,7 +1923,7 @@ remove_dbtablespaces(Oid db_id)
 		pfree(dstpath);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 }
 
@@ -1940,10 +1946,12 @@ check_db_file_conflict(Oid db_id)
 	Relation	rel;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
+	StorageAmRoutine *method;
 
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 0, NULL);
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 0, NULL);
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Oid			dsttablespace = HeapTupleGetOid(tuple);
 		char	   *dstpath;
@@ -1966,7 +1974,7 @@ check_db_file_conflict(Oid db_id)
 		pfree(dstpath);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 
 	return result;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 4861799..d5554c5 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -18,6 +18,7 @@
 #include "access/amapi.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
@@ -1869,6 +1870,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 	List	   *relids = NIL;
 	ListCell   *l;
 	int			num_keys;
+	StorageAmRoutine *method;
 
 	AssertArg(objectName);
 	Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
@@ -1935,8 +1937,9 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 	 * rels will be processed indirectly by reindex_relation).
 	 */
 	relationRelation = heap_open(RelationRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(relationRelation, num_keys, scan_keys);
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	method = relationRelation->rd_stamroutine;
+	scan = method->scan_begin_catalog(relationRelation, num_keys, scan_keys);
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
 		Oid			relid = HeapTupleGetOid(tuple);
@@ -1976,7 +1979,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 
 		MemoryContextSwitchTo(old);
 	}
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(relationRelation, AccessShareLock);
 
 	/* Now reindex each rel in a separate transaction */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index fb961e4..8256145 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4424,6 +4424,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		List	   *dropped_attrs = NIL;
 		ListCell   *lc;
 		Snapshot	snapshot;
+		StorageAmRoutine *method = oldrel->rd_stamroutine;
 
 		if (newrel)
 			ereport(DEBUG1,
@@ -4477,7 +4478,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		 * checking all the constraints.
 		 */
 		snapshot = RegisterSnapshot(GetLatestSnapshot());
-		scan = heap_beginscan(oldrel, snapshot, 0, NULL);
+		scan = method->scan_begin(oldrel, snapshot, 0, NULL);
 
 		/*
 		 * Switch to per-tuple memory context and reset it for each tuple
@@ -4485,7 +4486,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		 */
 		oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
-		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			if (tab->rewrite > 0)
 			{
@@ -4579,7 +4580,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
 			/* Write the tuple out to the new relation */
 			if (newrel)
-				heap_insert(newrel, tuple, mycid, hi_options, bistate);
+				newrel->rd_stamroutine->tuple_insert(newrel, newslot, mycid, hi_options, bistate, &tuple->t_self);
 
 			ResetExprContext(econtext);
 
@@ -4587,7 +4588,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		}
 
 		MemoryContextSwitchTo(oldCxt);
-		heap_endscan(scan);
+		method->scan_end(scan);
 		UnregisterSnapshot(snapshot);
 
 		ExecDropSingleTupleTableSlot(oldslot);
@@ -4969,17 +4970,18 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
 	HeapScanDesc scan;
 	HeapTuple	tuple;
 	List	   *result = NIL;
+	StorageAmRoutine *method;
 
 	classRel = heap_open(RelationRelationId, AccessShareLock);
-
+	method = classRel->rd_stamroutine;
 	ScanKeyInit(&key[0],
 				Anum_pg_class_reloftype,
 				BTEqualStrategyNumber, F_OIDEQ,
 				ObjectIdGetDatum(typeOid));
 
-	scan = heap_beginscan_catalog(classRel, 1, key);
+	scan = method->scan_begin_catalog(classRel, 1, key);
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		if (behavior == DROP_RESTRICT)
 			ereport(ERROR,
@@ -4991,7 +4993,7 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
 			result = lappend_oid(result, HeapTupleGetOid(tuple));
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(classRel, AccessShareLock);
 
 	return result;
@@ -8090,6 +8092,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	Form_pg_constraint constrForm;
 	bool		isnull;
 	Snapshot	snapshot;
+	StorageAmRoutine *method;
 
 	/*
 	 * VALIDATE CONSTRAINT is a no-op for foreign tables and partitioned
@@ -8123,7 +8126,8 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	econtext->ecxt_scantuple = slot;
 
 	snapshot = RegisterSnapshot(GetLatestSnapshot());
-	scan = heap_beginscan(rel, snapshot, 0, NULL);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin(rel, snapshot, 0, NULL);
 
 	/*
 	 * Switch to per-tuple memory context and reset it for each tuple
@@ -8131,7 +8135,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	 */
 	oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		ExecStoreTuple(tuple, slot, InvalidBuffer, false);
 
@@ -8146,7 +8150,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	}
 
 	MemoryContextSwitchTo(oldcxt);
-	heap_endscan(scan);
+	method->scan_end(scan);
 	UnregisterSnapshot(snapshot);
 	ExecDropSingleTupleTableSlot(slot);
 	FreeExecutorState(estate);
@@ -8169,6 +8173,7 @@ validateForeignKeyConstraint(char *conname,
 	HeapTuple	tuple;
 	Trigger		trig;
 	Snapshot	snapshot;
+	StorageAmRoutine *method;
 
 	ereport(DEBUG1,
 			(errmsg("validating foreign key constraint \"%s\"", conname)));
@@ -8201,9 +8206,10 @@ validateForeignKeyConstraint(char *conname,
 	 * ereport(ERROR) and that's that.
 	 */
 	snapshot = RegisterSnapshot(GetLatestSnapshot());
-	scan = heap_beginscan(rel, snapshot, 0, NULL);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin(rel, snapshot, 0, NULL);
 
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		FunctionCallInfoData fcinfo;
 		TriggerData trigdata;
@@ -8232,7 +8238,7 @@ validateForeignKeyConstraint(char *conname,
 		RI_FKey_check_ins(&fcinfo);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	UnregisterSnapshot(snapshot);
 }
 
@@ -10620,6 +10626,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 	Oid			orig_tablespaceoid;
 	Oid			new_tablespaceoid;
 	List	   *role_oids = roleSpecsToIds(stmt->roles);
+	StorageAmRoutine *method;
 
 	/* Ensure we were not asked to move something we can't */
 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
@@ -10680,8 +10687,9 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 				ObjectIdGetDatum(orig_tablespaceoid));
 
 	rel = heap_open(RelationRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 1, key);
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 1, key);
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Oid			relOid = HeapTupleGetOid(tuple);
 		Form_pg_class relForm;
@@ -10740,7 +10748,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 		relations = lappend_oid(relations, relOid);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 
 	if (relations == NIL)
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index f9c2620..ca7145e 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -53,6 +53,7 @@
 #include "access/heapam.h"
 #include "access/reloptions.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "access/xlog.h"
@@ -406,18 +407,19 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
 	Oid			tablespaceoid;
+	StorageAmRoutine *method;
 
 	/*
 	 * Find the target tuple
 	 */
 	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
-
+	method = rel->rd_stamroutine;
 	ScanKeyInit(&entry[0],
 				Anum_pg_tablespace_spcname,
 				BTEqualStrategyNumber, F_NAMEEQ,
 				CStringGetDatum(tablespacename));
-	scandesc = heap_beginscan_catalog(rel, 1, entry);
-	tuple = heap_getnext(scandesc, ForwardScanDirection);
+	scandesc = method->scan_begin_catalog(rel, 1, entry);
+	tuple = method->scan_getnext(scandesc, ForwardScanDirection);
 
 	if (!HeapTupleIsValid(tuple))
 	{
@@ -434,7 +436,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 					(errmsg("tablespace \"%s\" does not exist, skipping",
 							tablespacename)));
 			/* XXX I assume I need one or both of these next two calls */
-			heap_endscan(scandesc);
+			method->scan_end(scandesc);
 			heap_close(rel, NoLock);
 		}
 		return;
@@ -461,7 +463,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 	 */
 	CatalogTupleDelete(rel, &tuple->t_self);
 
-	heap_endscan(scandesc);
+	method->scan_end(scandesc);
 
 	/*
 	 * Remove any comments or security labels on this tablespace.
@@ -917,16 +919,17 @@ RenameTableSpace(const char *oldname, const char *newname)
 	HeapTuple	newtuple;
 	Form_pg_tablespace newform;
 	ObjectAddress address;
+	StorageAmRoutine *method;
 
 	/* Search pg_tablespace */
 	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
-
+	method = rel->rd_stamroutine;
 	ScanKeyInit(&entry[0],
 				Anum_pg_tablespace_spcname,
 				BTEqualStrategyNumber, F_NAMEEQ,
 				CStringGetDatum(oldname));
-	scan = heap_beginscan_catalog(rel, 1, entry);
-	tup = heap_getnext(scan, ForwardScanDirection);
+	scan = method->scan_begin_catalog(rel, 1, entry);
+	tup = method->scan_getnext(scan, ForwardScanDirection);
 	if (!HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -937,7 +940,7 @@ RenameTableSpace(const char *oldname, const char *newname)
 	newtuple = heap_copytuple(tup);
 	newform = (Form_pg_tablespace) GETSTRUCT(newtuple);
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	/* Must be owner */
 	if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId()))
@@ -955,15 +958,15 @@ RenameTableSpace(const char *oldname, const char *newname)
 				Anum_pg_tablespace_spcname,
 				BTEqualStrategyNumber, F_NAMEEQ,
 				CStringGetDatum(newname));
-	scan = heap_beginscan_catalog(rel, 1, entry);
-	tup = heap_getnext(scan, ForwardScanDirection);
+	scan = method->scan_begin_catalog(rel, 1, entry);
+	tup = method->scan_getnext(scan, ForwardScanDirection);
 	if (HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("tablespace \"%s\" already exists",
 						newname)));
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	/* OK, update the entry */
 	namestrcpy(&(newform->spcname), newname);
@@ -997,16 +1000,17 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	bool		repl_null[Natts_pg_tablespace];
 	bool		repl_repl[Natts_pg_tablespace];
 	HeapTuple	newtuple;
+	StorageAmRoutine *method;
 
 	/* Search pg_tablespace */
 	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
-
+	method = rel->rd_stamroutine;
 	ScanKeyInit(&entry[0],
 				Anum_pg_tablespace_spcname,
 				BTEqualStrategyNumber, F_NAMEEQ,
 				CStringGetDatum(stmt->tablespacename));
-	scandesc = heap_beginscan_catalog(rel, 1, entry);
-	tup = heap_getnext(scandesc, ForwardScanDirection);
+	scandesc = method->scan_begin_catalog(rel, 1, entry);
+	tup = method->scan_getnext(scandesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -1047,7 +1051,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
-	heap_endscan(scandesc);
+	method->scan_end(scandesc);
 	heap_close(rel, NoLock);
 
 	return tablespaceoid;
@@ -1384,6 +1388,7 @@ get_tablespace_oid(const char *tablespacename, bool missing_ok)
 	HeapScanDesc scandesc;
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
+	StorageAmRoutine *method;
 
 	/*
 	 * Search pg_tablespace.  We use a heapscan here even though there is an
@@ -1391,13 +1396,13 @@ get_tablespace_oid(const char *tablespacename, bool missing_ok)
 	 * a few entries and so an indexed lookup is a waste of effort.
 	 */
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
-
+	method = rel->rd_stamroutine;
 	ScanKeyInit(&entry[0],
 				Anum_pg_tablespace_spcname,
 				BTEqualStrategyNumber, F_NAMEEQ,
 				CStringGetDatum(tablespacename));
-	scandesc = heap_beginscan_catalog(rel, 1, entry);
-	tuple = heap_getnext(scandesc, ForwardScanDirection);
+	scandesc = method->scan_begin_catalog(rel, 1, entry);
+	tuple = method->scan_getnext(scandesc, ForwardScanDirection);
 
 	/* We assume that there can be at most one matching tuple */
 	if (HeapTupleIsValid(tuple))
@@ -1405,7 +1410,7 @@ get_tablespace_oid(const char *tablespacename, bool missing_ok)
 	else
 		result = InvalidOid;
 
-	heap_endscan(scandesc);
+	method->scan_end(scandesc);
 	heap_close(rel, AccessShareLock);
 
 	if (!OidIsValid(result) && !missing_ok)
@@ -1430,6 +1435,7 @@ get_tablespace_name(Oid spc_oid)
 	HeapScanDesc scandesc;
 	HeapTuple	tuple;
 	ScanKeyData entry[1];
+	StorageAmRoutine *method;
 
 	/*
 	 * Search pg_tablespace.  We use a heapscan here even though there is an
@@ -1437,13 +1443,13 @@ get_tablespace_name(Oid spc_oid)
 	 * few entries and so an indexed lookup is a waste of effort.
 	 */
 	rel = heap_open(TableSpaceRelationId, AccessShareLock);
-
+	method = rel->rd_stamroutine;
 	ScanKeyInit(&entry[0],
 				ObjectIdAttributeNumber,
 				BTEqualStrategyNumber, F_OIDEQ,
 				ObjectIdGetDatum(spc_oid));
-	scandesc = heap_beginscan_catalog(rel, 1, entry);
-	tuple = heap_getnext(scandesc, ForwardScanDirection);
+	scandesc = method->scan_begin_catalog(rel, 1, entry);
+	tuple = method->scan_getnext(scandesc, ForwardScanDirection);
 
 	/* We assume that there can be at most one matching tuple */
 	if (HeapTupleIsValid(tuple))
@@ -1451,7 +1457,7 @@ get_tablespace_name(Oid spc_oid)
 	else
 		result = NULL;
 
-	heap_endscan(scandesc);
+	method->scan_end(scandesc);
 	heap_close(rel, AccessShareLock);
 
 	return result;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index c765e97..2c494cc 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2312,11 +2312,13 @@ AlterDomainNotNull(List *names, bool notNull)
 			HeapScanDesc scan;
 			HeapTuple	tuple;
 			Snapshot	snapshot;
+			StorageAmRoutine *method;
 
 			/* Scan all tuples in this relation */
 			snapshot = RegisterSnapshot(GetLatestSnapshot());
-			scan = heap_beginscan(testrel, snapshot, 0, NULL);
-			while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+			method = testrel->rd_stamroutine;
+			scan = method->scan_begin(testrel, snapshot, 0, NULL);
+			while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 			{
 				int			i;
 
@@ -2344,7 +2346,7 @@ AlterDomainNotNull(List *names, bool notNull)
 					}
 				}
 			}
-			heap_endscan(scan);
+			method->scan_end(scan);
 			UnregisterSnapshot(snapshot);
 
 			/* Close each rel after processing, but keep lock */
@@ -2707,11 +2709,12 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 		HeapScanDesc scan;
 		HeapTuple	tuple;
 		Snapshot	snapshot;
+		StorageAmRoutine *method = testrel->rd_stamroutine;
 
 		/* Scan all tuples in this relation */
 		snapshot = RegisterSnapshot(GetLatestSnapshot());
-		scan = heap_beginscan(testrel, snapshot, 0, NULL);
-		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		scan = method->scan_begin(testrel, snapshot, 0, NULL);
+		while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			int			i;
 
@@ -2753,7 +2756,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 
 			ResetExprContext(econtext);
 		}
-		heap_endscan(scan);
+		method->scan_end(scan);
 		UnregisterSnapshot(snapshot);
 
 		/* Hold relation lock till commit (XXX bad for concurrency) */
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 9fbb0eb..e30f270 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -28,6 +28,7 @@
 #include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/multixact.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/namespace.h"
@@ -444,12 +445,14 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
 		Relation	pgclass;
 		HeapScanDesc scan;
 		HeapTuple	tuple;
+		StorageAmRoutine *method;
 
 		pgclass = heap_open(RelationRelationId, AccessShareLock);
+		method = pgclass->rd_stamroutine;
 
-		scan = heap_beginscan_catalog(pgclass, 0, NULL);
+		scan = method->scan_begin_catalog(pgclass, 0, NULL);
 
-		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+		while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 		{
 			Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
 
@@ -469,7 +472,7 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
 			MemoryContextSwitchTo(oldcontext);
 		}
 
-		heap_endscan(scan);
+		method->scan_end(scan);
 		heap_close(pgclass, AccessShareLock);
 	}
 
@@ -1096,6 +1099,7 @@ vac_truncate_clog(TransactionId frozenXID,
 	Oid			minmulti_datoid;
 	bool		bogus = false;
 	bool		frozenAlreadyWrapped = false;
+	StorageAmRoutine *method;
 
 	/* init oldest datoids to sync with my frozenXID/minMulti values */
 	oldestxid_datoid = MyDatabaseId;
@@ -1120,10 +1124,10 @@ vac_truncate_clog(TransactionId frozenXID,
 	 * as it could be.
 	 */
 	relation = heap_open(DatabaseRelationId, AccessShareLock);
+	method = relation->rd_stamroutine;
+	scan = method->scan_begin_catalog(relation, 0, NULL);
 
-	scan = heap_beginscan_catalog(relation, 0, NULL);
-
-	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		volatile FormData_pg_database *dbform = (Form_pg_database) GETSTRUCT(tuple);
 		TransactionId datfrozenxid = dbform->datfrozenxid;
@@ -1160,7 +1164,7 @@ vac_truncate_clog(TransactionId frozenXID,
 		}
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	heap_close(relation, AccessShareLock);
 
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 206238a..dca2f08 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -270,25 +270,27 @@ RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
 						 TupleTableSlot *searchslot, TupleTableSlot *outslot)
 {
     StorageTuple            scantuple;
-	HeapScanDesc scan;
+    StorageScanDesc scan;
 	SnapshotData snap;
 	TransactionId xwait;
 	bool		found;
 	TupleDesc	desc = RelationGetDescr(rel);
+    StorageAmRoutine *method;
 
 	Assert(equalTupleDescs(desc, outslot->tts_tupleDescriptor));
 
 	/* Start an index scan. */
 	InitDirtySnapshot(snap);
-	scan = heap_beginscan(rel, &snap, 0, NULL);
+    method = rel->rd_stamroutine;
+    scan = method->scan_begin(rel, &snap, 0, NULL);
 
 retry:
 	found = false;
 
-	heap_rescan(scan, NULL);
+    method->scan_rescan(scan, NULL);
 
 	/* Try to find the tuple */
-	while ((scantuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	while ((scantuple = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		if (!tuple_equals_slot(desc, scantuple, searchslot))
 			continue;
@@ -353,7 +355,7 @@ retry:
 		}
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 
 	return found;
 }
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index f8a4e7d..51d8f74 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -690,7 +690,7 @@ ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
 	PlanState  *outerPlan = outerPlanState(node);
 
 	/* rescan to release any page pin */
-	heap_rescan(node->ss.ss_currentScanDesc, NULL);
+	node->ss.ss_currentRelation->rd_stamroutine->scan_rescan(node->ss.ss_currentScanDesc, NULL);
 
 	if (node->tbmiterator)
 		tbm_end_iterate(node->tbmiterator);
@@ -745,7 +745,7 @@ void
 ExecEndBitmapHeapScan(BitmapHeapScanState *node)
 {
 	Relation	relation;
-	HeapScanDesc scanDesc;
+	StorageScanDesc scanDesc;
 
 	/*
 	 * extract information from the node
@@ -786,7 +786,7 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
 	/*
 	 * close heap scan
 	 */
-	heap_endscan(scanDesc);
+	relation->rd_stamroutine->scan_end(scanDesc);
 
 	/*
 	 * close the heap relation.
@@ -884,9 +884,10 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
 
 	/*
 	 * Even though we aren't going to do a conventional seqscan, it is useful
-	 * to create a HeapScanDesc --- most of the fields in it are usable.
+	 * to create a StorageScanDesc --- most of the fields in it are usable.
 	 */
-	scanstate->ss.ss_currentScanDesc = heap_beginscan_bm(currentRelation,
+	scanstate->ss.ss_currentScanDesc
+			= currentRelation->rd_stamroutine->scan_begin_bm(currentRelation,
 														 estate->es_snapshot,
 														 0,
 														 NULL);
@@ -1019,5 +1020,5 @@ ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node, shm_toc *toc)
 	node->pstate = pstate;
 
 	snapshot = RestoreSnapshot(pstate->phs_snapshot_data);
-	heap_update_snapshot(node->ss.ss_currentScanDesc, snapshot);
+	node->ss.ss_currentRelation->rd_stamroutine->scan_update_snapshot(node->ss.ss_currentScanDesc, snapshot);
 }
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 51fb182..a7d2ba8 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -242,7 +242,7 @@ ExecEndSampleScan(SampleScanState *node)
 	 * close heap scan
 	 */
 	if (node->ss.ss_currentScanDesc)
-		heap_endscan(node->ss.ss_currentScanDesc);
+		node->ss.ss_currentRelation->rd_stamroutine->scan_end(node->ss.ss_currentScanDesc);
 
 	/*
 	 * close the heap relation.
@@ -347,7 +347,7 @@ tablesample_init(SampleScanState *scanstate)
 	if (scanstate->ss.ss_currentScanDesc == NULL)
 	{
 		scanstate->ss.ss_currentScanDesc =
-			heap_beginscan_sampling(scanstate->ss.ss_currentRelation,
+				scanstate->ss.ss_currentRelation->rd_stamroutine->scan_begin_sampling(scanstate->ss.ss_currentRelation,
 									scanstate->ss.ps.state->es_snapshot,
 									0, NULL,
 									scanstate->use_bulkread,
@@ -356,7 +356,7 @@ tablesample_init(SampleScanState *scanstate)
 	}
 	else
 	{
-		heap_rescan_set_params(scanstate->ss.ss_currentScanDesc, NULL,
+		scanstate->ss.ss_currentRelation->rd_stamroutine->scan_rescan_set_params(scanstate->ss.ss_currentScanDesc, NULL,
 							   scanstate->use_bulkread,
 							   allow_sync,
 							   scanstate->use_pagemode);
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 9cba6b3..5096248 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -27,6 +27,7 @@
 #include "postgres.h"
 
 #include "access/relscan.h"
+#include "access/storageamapi.h"
 #include "executor/execdebug.h"
 #include "executor/nodeSeqscan.h"
 #include "utils/rel.h"
@@ -53,10 +54,12 @@ SeqNext(SeqScanState *node)
 	EState	   *estate;
 	ScanDirection direction;
 	TupleTableSlot *slot;
+	StorageAmRoutine *method;
 
 	/*
 	 * get information from the estate and scan state
 	 */
+	method = node->ss.ss_currentRelation->rd_stamroutine;
 	scandesc = node->ss.ss_currentScanDesc;
 	estate = node->ss.ps.state;
 	direction = estate->es_direction;
@@ -68,7 +71,7 @@ SeqNext(SeqScanState *node)
 		 * We reach here if the scan is not parallel, or if we're executing a
 		 * scan that was intended to be parallel serially.
 		 */
-		scandesc = heap_beginscan(node->ss.ss_currentRelation,
+		scandesc = method->scan_begin(node->ss.ss_currentRelation,
 								  estate->es_snapshot,
 								  0, NULL);
 		node->ss.ss_currentScanDesc = scandesc;
@@ -77,7 +80,7 @@ SeqNext(SeqScanState *node)
 	/*
 	 * get the next tuple from the table
 	 */
-	tuple = heap_getnext(scandesc, direction);
+	tuple = method->scan_getnext(scandesc, direction);
 
 	/*
 	 * save the tuple and the buffer returned to us by the access methods in
@@ -245,7 +248,7 @@ ExecEndSeqScan(SeqScanState *node)
 	 * close heap scan
 	 */
 	if (scanDesc != NULL)
-		heap_endscan(scanDesc);
+		relation->rd_stamroutine->scan_end(scanDesc);
 
 	/*
 	 * close the heap relation.
@@ -272,7 +275,7 @@ ExecReScanSeqScan(SeqScanState *node)
 	scan = node->ss.ss_currentScanDesc;
 
 	if (scan != NULL)
-		heap_rescan(scan,		/* scan desc */
+		node->ss.ss_currentRelation->rd_stamroutine->scan_rescan(scan,		/* scan desc */
 					NULL);		/* new scan keys */
 
 	ExecScanReScan((ScanState *) node);
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 89dd3b3..e6b8ee0 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -69,6 +69,7 @@
 #include "access/htup_details.h"
 #include "access/multixact.h"
 #include "access/reloptions.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/dependency.h"
@@ -1887,6 +1888,7 @@ get_database_list(void)
 	HeapScanDesc scan;
 	HeapTuple	tup;
 	MemoryContext resultcxt;
+	StorageAmRoutine *method;
 
 	/* This is the context that we will allocate our output data in */
 	resultcxt = CurrentMemoryContext;
@@ -1902,9 +1904,10 @@ get_database_list(void)
 	(void) GetTransactionSnapshot();
 
 	rel = heap_open(DatabaseRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 0, NULL);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 0, NULL);
 
-	while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+	while (HeapTupleIsValid(tup = method->scan_getnext(scan, ForwardScanDirection)))
 	{
 		Form_pg_database pgdatabase = (Form_pg_database) GETSTRUCT(tup);
 		avw_dbase  *avdb;
@@ -1931,7 +1934,7 @@ get_database_list(void)
 		MemoryContextSwitchTo(oldcxt);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 
 	CommitTransactionCommand();
@@ -1965,6 +1968,7 @@ do_autovacuum(void)
 	int			effective_multixact_freeze_max_age;
 	bool		did_vacuum = false;
 	bool		found_concurrent_worker = false;
+	StorageAmRoutine *method;
 
 	/*
 	 * StartTransactionCommand and CommitTransactionCommand will automatically
@@ -2033,6 +2037,7 @@ do_autovacuum(void)
 	shared = pgstat_fetch_stat_dbentry(InvalidOid);
 
 	classRel = heap_open(RelationRelationId, AccessShareLock);
+	method = classRel->rd_stamroutine;
 
 	/* create a copy so we can use it after closing pg_class */
 	pg_class_desc = CreateTupleDescCopy(RelationGetDescr(classRel));
@@ -2061,13 +2066,13 @@ do_autovacuum(void)
 	 * wide tables there might be proportionally much more activity in the
 	 * TOAST table than in its parent.
 	 */
-	relScan = heap_beginscan_catalog(classRel, 0, NULL);
+	relScan = method->scan_begin_catalog(classRel, 0, NULL);
 
 	/*
 	 * On the first pass, we collect main tables to vacuum, and also the main
 	 * table relid to TOAST relid mapping.
 	 */
-	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
+	while ((tuple = method->scan_getnext(relScan, ForwardScanDirection)) != NULL)
 	{
 		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
 		PgStat_StatTabEntry *tabentry;
@@ -2153,7 +2158,7 @@ do_autovacuum(void)
 		}
 	}
 
-	heap_endscan(relScan);
+	method->scan_end(relScan);
 
 	/* second pass: check TOAST tables */
 	ScanKeyInit(&key,
@@ -2161,8 +2166,8 @@ do_autovacuum(void)
 				BTEqualStrategyNumber, F_CHAREQ,
 				CharGetDatum(RELKIND_TOASTVALUE));
 
-	relScan = heap_beginscan_catalog(classRel, 1, &key);
-	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
+	relScan = method->scan_begin_catalog(classRel, 1, &key);
+	while ((tuple = method->scan_getnext(relScan, ForwardScanDirection)) != NULL)
 	{
 		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
 		PgStat_StatTabEntry *tabentry;
@@ -2208,7 +2213,7 @@ do_autovacuum(void)
 			table_oids = lappend_oid(table_oids, relid);
 	}
 
-	heap_endscan(relScan);
+	method->scan_end(relScan);
 	heap_close(classRel, AccessShareLock);
 
 	/*
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index f453dad..d07914b 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -36,6 +36,7 @@
 
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "access/twophase_rmgr.h"
 #include "access/xact.h"
@@ -1209,6 +1210,7 @@ pgstat_collect_oids(Oid catalogid)
 	HeapScanDesc scan;
 	HeapTuple	tup;
 	Snapshot	snapshot;
+	StorageAmRoutine *method;
 
 	memset(&hash_ctl, 0, sizeof(hash_ctl));
 	hash_ctl.keysize = sizeof(Oid);
@@ -1221,8 +1223,9 @@ pgstat_collect_oids(Oid catalogid)
 
 	rel = heap_open(catalogid, AccessShareLock);
 	snapshot = RegisterSnapshot(GetLatestSnapshot());
-	scan = heap_beginscan(rel, snapshot, 0, NULL);
-	while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin(rel, snapshot, 0, NULL);
+	while ((tup = method->scan_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Oid			thisoid = HeapTupleGetOid(tup);
 
@@ -1230,7 +1233,7 @@ pgstat_collect_oids(Oid catalogid)
 
 		(void) hash_search(htab, (void *) &thisoid, HASH_ENTER, NULL);
 	}
-	heap_endscan(scan);
+	method->scan_end(scan);
 	UnregisterSnapshot(snapshot);
 	heap_close(rel, AccessShareLock);
 
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 4e2c350..9813efc 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -102,6 +102,7 @@ get_subscription_list(void)
 	HeapScanDesc scan;
 	HeapTuple	tup;
 	MemoryContext resultcxt;
+	StorageAmRoutine *method;
 
 	/* This is the context that we will allocate our output data in */
 	resultcxt = CurrentMemoryContext;
@@ -117,9 +118,10 @@ get_subscription_list(void)
 	(void) GetTransactionSnapshot();
 
 	rel = heap_open(SubscriptionRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(rel, 0, NULL);
+	method = rel->rd_stamroutine;
+	scan = method->scan_begin_catalog(rel, 0, NULL);
 
-	while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+	while (HeapTupleIsValid(tup = method->scan_getnext(scan, ForwardScanDirection)))
 	{
 		Form_pg_subscription subform = (Form_pg_subscription) GETSTRUCT(tup);
 		Subscription *sub;
@@ -145,7 +147,7 @@ get_subscription_list(void)
 		MemoryContextSwitchTo(oldcxt);
 	}
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(rel, AccessShareLock);
 
 	CommitTransactionCommand();
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index fd3768d..3db218d 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -17,6 +17,7 @@
 #include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/multixact.h"
+#include "access/storageamapi.h"
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
@@ -421,6 +422,7 @@ DefineQueryRewrite(char *rulename,
 		{
 			HeapScanDesc scanDesc;
 			Snapshot	snapshot;
+			StorageAmRoutine *method;
 
 			if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 				ereport(ERROR,
@@ -429,13 +431,14 @@ DefineQueryRewrite(char *rulename,
 					   RelationGetRelationName(event_relation))));
 
 			snapshot = RegisterSnapshot(GetLatestSnapshot());
-			scanDesc = heap_beginscan(event_relation, snapshot, 0, NULL);
-			if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
+			method = event_relation->rd_stamroutine;
+			scanDesc = method->scan_begin(event_relation, snapshot, 0, NULL);
+			if (method->scan_getnext(scanDesc, ForwardScanDirection) != NULL)
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("could not convert table \"%s\" to a view because it is not empty",
 								RelationGetRelationName(event_relation))));
-			heap_endscan(scanDesc);
+			method->scan_end(scanDesc);
 			UnregisterSnapshot(snapshot);
 
 			if (event_relation->rd_rel->relhastriggers)
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index b8b4a06..400da47 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -21,6 +21,7 @@
 
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/storageamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "access/xlog.h"
@@ -1205,13 +1206,15 @@ ThereIsAtLeastOneRole(void)
 	Relation	pg_authid_rel;
 	HeapScanDesc scan;
 	bool		result;
+	StorageAmRoutine *method;
 
 	pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
+	method = pg_authid_rel->rd_stamroutine;
 
-	scan = heap_beginscan_catalog(pg_authid_rel, 0, NULL);
-	result = (heap_getnext(scan, ForwardScanDirection) != NULL);
+	scan = method->scan_begin_catalog(pg_authid_rel, 0, NULL);
+	result = (method->scan_getnext(scan, ForwardScanDirection) != NULL);
 
-	heap_endscan(scan);
+	method->scan_end(scan);
 	heap_close(pg_authid_rel, AccessShareLock);
 
 	return result;
-- 
2.7.4.windows.1

