diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 90a6937..1161167 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -12,27 +12,40 @@
  *
  *
  * INTERFACE ROUTINES
- *		relation_open	- open any relation by relation OID
- *		relation_openrv - open any relation specified by a RangeVar
- *		relation_close	- close any relation
- *		heap_open		- open a heap relation by relation OID
- *		heap_openrv		- open a heap relation specified by a RangeVar
- *		heap_close		- (now just a macro for relation_close)
- *		heap_beginscan	- begin relation scan
- *		heap_rescan		- restart a relation scan
- *		heap_endscan	- end relation scan
+ *		heap_beginscan	- begin heap relation scan
+ *		heap_rescan		- restart a heap relation scan
+ *		heap_endscan	- end heap relation scan
  *		heap_getnext	- retrieve next tuple in scan
  *		heap_fetch		- retrieve tuple with given tid
- *		heap_insert		- insert tuple into a relation
- *		heap_multi_insert - insert multiple tuples into a relation
- *		heap_delete		- delete a tuple from a relation
- *		heap_update		- replace a tuple in a relation with another tuple
- *		heap_sync		- sync heap, for when no WAL has been written
+ *		heap_insert		- insert tuple into a heap relation
+ *		heap_multi_insert - insert multiple tuples into a heap relation
+ *		heap_delete		- delete a tuple from a heap relation
+ *		heap_update		- replace a tuple in a heap relation with another tuple
+ *
+ *	Heap AM code is spreaded across many files.
+ *	Files containing interface routines for heap AM:
+ *		Vacuum routines - src/backend/commands/vacuumlazy.c
+ *		CLUSTER and VACUUM FULL - rewriteheap.c
+ *		Page pruning and HOT-chain management - pruneheap.c
+ *		Routines related to interaction with buffer manager - hio.c
+ *		Heap creation, destroying and truncation - src/backend/catalog/heap.c
  *
  * NOTES
- *	  This file contains the heap_ routines which implement
- *	  the POSTGRES heap access method used for all POSTGRES
- *	  relations.
+ *	This file contains the heap_ routines which implement
+ *	the POSTGRES heap access method used for POSTGRES
+ *	relations of following kinds:
+ *		RELKIND_RELATION
+ *		RELKIND_SEQUENCE
+ *		RELKIND_TOASTVALUE
+ *		RELKIND_MATVIEW
+ *
+ *	Relations of types
+ *		RELKIND_VIEW
+ *		RELKIND_COMPOSITE_TYPE
+ *		RELKIND_FOREIGN_TABLE
+ *	have no physical storage, so they are not actually heap relations.
+ *	If they occur in heap functions, it's an overlooked code that
+ *	requres refactoring.
  *
  *-------------------------------------------------------------------------
  */
@@ -204,16 +217,16 @@ static const int MultiXactStatusLock[MaxMultiXactStatus + 1] =
 			(MultiXactStatusLock[(status)])
 
 /* ----------------------------------------------------------------
- *						 heap support routines
+ *						 heap scan routines
  * ----------------------------------------------------------------
  */
 
 /* ----------------
- *		initscan - scan code common to heap_beginscan and heap_rescan
+ *		heap_initscan - scan code common to heap_beginscan and heap_rescan
  * ----------------
  */
 static void
-initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
+heap_initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 {
 	bool		allow_strat;
 	bool		allow_sync;
@@ -337,9 +350,12 @@ heap_setscanlimits(HeapScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
 }
 
 /*
- * heapgetpage - subroutine for heapgettup()
+ * heapgetpage - this function is a subroutine for heapgettup().
+ *	But now it is also used by tablesample_getnext, so cannot be marked
+ *	as a static function.
  *
- * This routine reads and pins the specified page of the relation.
+ * This routine reads and pins the specified page of the heap relation.
+ * Besides, it prunes the page, if possible.
  * In page-at-a-time mode it performs additional work, namely determining
  * which tuples on the page are visible.
  */
@@ -1092,281 +1108,8 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
 }
 #endif   /* defined(DISABLE_COMPLEX_MACRO) */
 
-
-/* ----------------------------------------------------------------
- *					 heap access method interface
- * ----------------------------------------------------------------
- */
-
-/* ----------------
- *		relation_open - open any relation by relation OID
- *
- *		If lockmode is not "NoLock", the specified kind of lock is
- *		obtained on the relation.  (Generally, NoLock should only be
- *		used if the caller knows it has some appropriate lock on the
- *		relation already.)
- *
- *		An error is raised if the relation does not exist.
- *
- *		NB: a "relation" is anything with a pg_class entry.  The caller is
- *		expected to check whether the relkind is something it can handle.
- * ----------------
- */
-Relation
-relation_open(Oid relationId, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
-
-	/* Get the lock before trying to open the relcache entry */
-	if (lockmode != NoLock)
-		LockRelationOid(relationId, lockmode);
-
-	/* The relcache does all the real work... */
-	r = RelationIdGetRelation(relationId);
-
-	if (!RelationIsValid(r))
-		elog(ERROR, "could not open relation with OID %u", relationId);
-
-	/* Make note that we've accessed a temporary relation */
-	if (RelationUsesLocalBuffers(r))
-		MyXactAccessedTempRel = true;
-
-	pgstat_initstats(r);
-
-	return r;
-}
-
-/* ----------------
- *		try_relation_open - open any relation by relation OID
- *
- *		Same as relation_open, except return NULL instead of failing
- *		if the relation does not exist.
- * ----------------
- */
-Relation
-try_relation_open(Oid relationId, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
-
-	/* Get the lock first */
-	if (lockmode != NoLock)
-		LockRelationOid(relationId, lockmode);
-
-	/*
-	 * Now that we have the lock, probe to see if the relation really exists
-	 * or not.
-	 */
-	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
-	{
-		/* Release useless lock */
-		if (lockmode != NoLock)
-			UnlockRelationOid(relationId, lockmode);
-
-		return NULL;
-	}
-
-	/* Should be safe to do a relcache load */
-	r = RelationIdGetRelation(relationId);
-
-	if (!RelationIsValid(r))
-		elog(ERROR, "could not open relation with OID %u", relationId);
-
-	/* Make note that we've accessed a temporary relation */
-	if (RelationUsesLocalBuffers(r))
-		MyXactAccessedTempRel = true;
-
-	pgstat_initstats(r);
-
-	return r;
-}
-
-/* ----------------
- *		relation_openrv - open any relation specified by a RangeVar
- *
- *		Same as relation_open, but the relation is specified by a RangeVar.
- * ----------------
- */
-Relation
-relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Oid			relOid;
-
-	/*
-	 * Check for shared-cache-inval messages before trying to open the
-	 * relation.  This is needed even if we already hold a lock on the
-	 * relation, because GRANT/REVOKE are executed without taking any lock on
-	 * the target relation, and we want to be sure we see current ACL
-	 * information.  We can skip this if asked for NoLock, on the assumption
-	 * that such a call is not the first one in the current command, and so we
-	 * should be reasonably up-to-date already.  (XXX this all could stand to
-	 * be redesigned, but for the moment we'll keep doing this like it's been
-	 * done historically.)
-	 */
-	if (lockmode != NoLock)
-		AcceptInvalidationMessages();
-
-	/* Look up and lock the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, lockmode, false);
-
-	/* Let relation_open do the rest */
-	return relation_open(relOid, NoLock);
-}
-
-/* ----------------
- *		relation_openrv_extended - open any relation specified by a RangeVar
- *
- *		Same as relation_openrv, but with an additional missing_ok argument
- *		allowing a NULL return rather than an error if the relation is not
- *		found.  (Note that some other causes, such as permissions problems,
- *		will still result in an ereport.)
- * ----------------
- */
-Relation
-relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
-						 bool missing_ok)
-{
-	Oid			relOid;
-
-	/*
-	 * Check for shared-cache-inval messages before trying to open the
-	 * relation.  See comments in relation_openrv().
-	 */
-	if (lockmode != NoLock)
-		AcceptInvalidationMessages();
-
-	/* Look up and lock the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
-
-	/* Return NULL on not-found */
-	if (!OidIsValid(relOid))
-		return NULL;
-
-	/* Let relation_open do the rest */
-	return relation_open(relOid, NoLock);
-}
-
-/* ----------------
- *		relation_close - close any relation
- *
- *		If lockmode is not "NoLock", we then release the specified lock.
- *
- *		Note that it is often sensible to hold a lock beyond relation_close;
- *		in that case, the lock is released automatically at xact end.
- * ----------------
- */
-void
-relation_close(Relation relation, LOCKMODE lockmode)
-{
-	LockRelId	relid = relation->rd_lockInfo.lockRelId;
-
-	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
-
-	/* The relcache does the real work... */
-	RelationClose(relation);
-
-	if (lockmode != NoLock)
-		UnlockRelationId(&relid, lockmode);
-}
-
-
-/* ----------------
- *		heap_open - open a heap relation by relation OID
- *
- *		This is essentially relation_open plus check that the relation
- *		is not an index nor a composite type.  (The caller should also
- *		check that it's not a view or foreign table before assuming it has
- *		storage.)
- * ----------------
- */
-Relation
-heap_open(Oid relationId, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	r = relation_open(relationId, lockmode);
-
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
-
-	return r;
-}
-
-/* ----------------
- *		heap_openrv - open a heap relation specified
- *		by a RangeVar node
- *
- *		As above, but relation is specified by a RangeVar.
- * ----------------
- */
-Relation
-heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	r = relation_openrv(relation, lockmode);
-
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
-
-	return r;
-}
-
-/* ----------------
- *		heap_openrv_extended - open a heap relation specified
- *		by a RangeVar node
- *
- *		As above, but optionally return NULL instead of failing for
- *		relation-not-found.
- * ----------------
- */
-Relation
-heap_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
-					 bool missing_ok)
-{
-	Relation	r;
-
-	r = relation_openrv_extended(relation, lockmode, missing_ok);
-
-	if (r)
-	{
-		if (r->rd_rel->relkind == RELKIND_INDEX)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is an index",
-							RelationGetRelationName(r))));
-		else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a composite type",
-							RelationGetRelationName(r))));
-	}
-
-	return r;
-}
-
-
 /* ----------------
- *		heap_beginscan	- begin relation scan
+ *		heap_beginscan	- begin heap relation scan
  *
  * heap_beginscan is the "standard" case.
  *
@@ -1435,6 +1178,9 @@ heap_beginscan_sampling(Relation relation, Snapshot snapshot,
 								   false, true, false);
 }
 
+/*
+ * heap_beginscan_internal - a workhorse for the functions above
+ */
 static HeapScanDesc
 heap_beginscan_internal(Relation relation, Snapshot snapshot,
 						int nkeys, ScanKey key,
@@ -1496,21 +1242,21 @@ heap_beginscan_internal(Relation relation, Snapshot snapshot,
 	scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
 
 	/*
-	 * we do this here instead of in initscan() because heap_rescan also calls
-	 * initscan() and we don't want to allocate memory again
+	 * we do this here instead of in heap_initscan() because heap_rescan also
+	 * calls heap_initscan() and we don't want to allocate memory again
 	 */
 	if (nkeys > 0)
 		scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
 	else
 		scan->rs_key = NULL;
 
-	initscan(scan, key, false);
+	heap_initscan(scan, key, false);
 
 	return scan;
 }
 
 /* ----------------
- *		heap_rescan		- restart a relation scan
+ *		heap_rescan		- restart a heap relation scan
  * ----------------
  */
 void
@@ -1526,7 +1272,7 @@ heap_rescan(HeapScanDesc scan,
 	/*
 	 * reinitialize scan descriptor
 	 */
-	initscan(scan, key, true);
+	heap_initscan(scan, key, true);
 
 	/*
 	 * reset parallel scan, if present
@@ -1549,7 +1295,8 @@ heap_rescan(HeapScanDesc scan,
 }
 
 /* ----------------
- *		heap_rescan_set_params	- restart a relation scan after changing params
+ *		heap_rescan_set_params	- restart a heap relation scan after changing
+ *								  params
  *
  * This call allows changing the buffer strategy, syncscan, and pagemode
  * options before starting a fresh scan.  Note that although the actual use
@@ -1570,10 +1317,7 @@ heap_rescan_set_params(HeapScanDesc scan, ScanKey key,
 }
 
 /* ----------------
- *		heap_endscan	- end relation scan
- *
- *		See how to integrate with index scans.
- *		Check handling if reldesc caching.
+ *		heap_endscan - free resourses at the end of a heap relation scan
  * ----------------
  */
 void
@@ -1604,6 +1348,12 @@ heap_endscan(HeapScanDesc scan)
 	pfree(scan);
 }
 
+
+/* ----------------------------------------------------------------
+ *				 heap parallel scan support routines
+ * ----------------------------------------------------------------
+ */
+
 /* ----------------
  *		heap_parallelscan_estimate - estimate storage for ParallelHeapScanDesc
  *
@@ -1632,7 +1382,7 @@ heap_parallelscan_initialize(ParallelHeapScanDesc target, Relation relation,
 {
 	target->phs_relid = RelationGetRelid(relation);
 	target->phs_nblocks = RelationGetNumberOfBlocks(relation);
-	/* compare phs_syncscan initialization to similar logic in initscan */
+	/* compare phs_syncscan initialization to similar logic in heap_initscan */
 	target->phs_syncscan = synchronize_seqscans &&
 		!RelationUsesLocalBuffers(relation) &&
 		target->phs_nblocks > NBuffers / 4;
@@ -1752,15 +1502,6 @@ retry:
 	return page;
 }
 
-/* ----------------
- *		heap_getnext	- retrieve next tuple in scan
- *
- *		Fix to work with index relations.
- *		We don't return the buffer anymore, but you can get it from the
- *		returned HeapTuple.
- * ----------------
- */
-
 #ifdef HEAPDEBUGALL
 #define HEAPDEBUG_1 \
 	elog(DEBUG2, "heap_getnext([%s,nkeys=%d],dir=%d) called", \
@@ -1775,7 +1516,12 @@ retry:
 #define HEAPDEBUG_3
 #endif   /* !defined(HEAPDEBUGALL) */
 
-
+/* ----------------
+ *		heap_getnext - retrieve next heap tuple in scan.
+ * This function is an implementation of amgettuple interface,
+ * that should be used by external callers.
+ * ----------------
+ */
 HeapTuple
 heap_getnext(HeapScanDesc scan, ScanDirection direction)
 {
@@ -1796,8 +1542,8 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
 	}
 
 	/*
-	 * if we get here it means we have a new current scan tuple, so point to
-	 * the proper return buffer and return the tuple.
+	 * if we get here it means we have a new current scan tuple, so increase
+	 * stats counter and return the tuple.
 	 */
 	HEAPDEBUG_3;				/* heap_getnext returning tuple */
 
@@ -2262,42 +2008,59 @@ heap_get_latest_tid(Relation relation,
 	}							/* end of loop */
 }
 
+/* ----------------------------------------------------------------
+ *						 heap insert routines
+ * ----------------------------------------------------------------
+ */
 
 /*
- * UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends
- *
- * This is called after we have waited for the XMAX transaction to terminate.
- * If the transaction aborted, we guarantee the XMAX_INVALID hint bit will
- * be set on exit.  If the transaction committed, we set the XMAX_COMMITTED
- * hint bit if possible --- but beware that that may not yet be possible,
- * if the transaction committed asynchronously.
+ * RelationPutHeapTuple - place tuple at specified page
  *
- * Note that if the transaction was a locker only, we set HEAP_XMAX_INVALID
- * even if it commits.
+ * !!! EREPORT(ERROR) IS DISALLOWED HERE !!!  Must PANIC on failure!!!
  *
- * Hence callers should look only at XMAX_INVALID.
- *
- * Note this is not allowed for tuples whose xmax is a multixact.
+ * Note - caller must hold BUFFER_LOCK_EXCLUSIVE on the buffer.
  */
 static void
-UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
+RelationPutHeapTuple(Relation relation,
+					 Buffer buffer,
+					 HeapTuple tuple,
+					 bool token)
 {
-	Assert(TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple), xid));
-	Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+	Page		pageHeader;
+	OffsetNumber offnum;
 
-	if (!(tuple->t_infomask & (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID)))
+	/*
+	 * A tuple that's being inserted speculatively should already have its
+	 * token set.
+	 */
+	Assert(!token || HeapTupleHeaderIsSpeculative(tuple->t_data));
+
+	/* Add the tuple to the page */
+	pageHeader = BufferGetPage(buffer);
+
+	offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
+						 tuple->t_len, InvalidOffsetNumber, false, true);
+
+	if (offnum == InvalidOffsetNumber)
+		elog(PANIC, "failed to add tuple to page");
+
+	/* Update tuple->t_self to the actual position where it was stored */
+	ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum);
+
+	/*
+	 * Insert the correct position into CTID of the stored tuple, too (unless
+	 * this is a speculative insertion, in which case the token is held in
+	 * CTID field instead)
+	 */
+	if (!token)
 	{
-		if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) &&
-			TransactionIdDidCommit(xid))
-			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
-								 xid);
-		else
-			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
-								 InvalidTransactionId);
+		ItemId			itemId = PageGetItemId(pageHeader, offnum);
+		HeapTupleHeader	onpage_tup = PageGetItemHeapHeaderOnly(pageHeader, itemId);
+
+		onpage_tup->t_ctid = tuple->t_self;
 	}
 }
 
-
 /*
  * GetBulkInsertState - prepare status object for a bulk insert
  */
@@ -2324,7 +2087,6 @@ FreeBulkInsertState(BulkInsertState bistate)
 	pfree(bistate);
 }
 
-
 /*
  *	heap_insert		- insert tuple into a heap
  *
@@ -2916,6 +2678,45 @@ simple_heap_insert(Relation relation, HeapTuple tup)
 	return heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
 }
 
+/* ----------------------------------------------------------------
+ *						 heap delete/update routines
+ * ----------------------------------------------------------------
+ */
+
+/*
+ * UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends
+ *
+ * This is called after we have waited for the XMAX transaction to terminate.
+ * If the transaction aborted, we guarantee the XMAX_INVALID hint bit will
+ * be set on exit.  If the transaction committed, we set the XMAX_COMMITTED
+ * hint bit if possible --- but beware that that may not yet be possible,
+ * if the transaction committed asynchronously.
+ *
+ * Note that if the transaction was a locker only, we set HEAP_XMAX_INVALID
+ * even if it commits.
+ *
+ * Hence callers should look only at XMAX_INVALID.
+ *
+ * Note this is not allowed for tuples whose xmax is a multixact.
+ */
+static void
+UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
+{
+	Assert(TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple), xid));
+	Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));
+
+	if (!(tuple->t_infomask & (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID)))
+	{
+		if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) &&
+			TransactionIdDidCommit(xid))
+			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
+								 xid);
+		else
+			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
+								 InvalidTransactionId);
+	}
+}
+
 /*
  * Given infomask/infomask2, compute the bits that must be saved in the
  * "infobits" field of xl_heap_delete, xl_heap_update, xl_heap_lock,
@@ -4503,6 +4304,109 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
 	}
 }
 
+/*
+ * heap_inplace_update - update a tuple "in place" (ie, overwrite it)
+ *
+ * Overwriting violates both MVCC and transactional safety, so the uses
+ * of this function in Postgres are extremely limited.  Nonetheless we
+ * find some places to use it.
+ *
+ * The tuple cannot change size, and therefore it's reasonable to assume
+ * that its null bitmap (if any) doesn't change either.  So we just
+ * overwrite the data portion of the tuple without touching the null
+ * bitmap or any of the header fields.
+ *
+ * tuple is an in-memory tuple structure containing the data to be written
+ * over the target tuple.  Also, tuple->t_self identifies the target tuple.
+ */
+void
+heap_inplace_update(Relation relation, HeapTuple tuple)
+{
+	Buffer		buffer;
+	Page		page;
+	OffsetNumber offnum;
+	ItemId		lp = NULL;
+	HeapTupleHeader htup;
+	uint32		oldlen;
+	uint32		newlen;
+
+	/*
+	 * For now, parallel operations are required to be strictly read-only.
+	 * Unlike a regular update, this should never create a combo CID, so it
+	 * might be possible to relax this restriction, but not without more
+	 * thought and testing.  It's not clear that it would be useful, anyway.
+	 */
+	if (IsInParallelMode())
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
+				 errmsg("cannot update tuples during a parallel operation")));
+
+	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
+	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+	page = (Page) BufferGetPage(buffer);
+
+	offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
+	if (PageGetMaxOffsetNumber(page) >= offnum)
+		lp = PageGetItemId(page, offnum);
+
+	if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
+		elog(ERROR, "invalid lp");
+
+	htup = PageGetItemHeap(page, lp);
+
+	oldlen = ItemIdGetLength(lp) - htup->t_hoff;
+	newlen = tuple->t_len - tuple->t_data->t_hoff;
+	if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
+		elog(ERROR, "wrong tuple length");
+
+	/* NO EREPORT(ERROR) from here till changes are logged */
+	START_CRIT_SECTION();
+
+	memcpy((char *) htup + htup->t_hoff,
+		   (char *) tuple->t_data + tuple->t_data->t_hoff,
+		   newlen);
+
+	MarkBufferDirty(buffer);
+
+	/* XLOG stuff */
+	if (RelationNeedsWAL(relation))
+	{
+		xl_heap_inplace xlrec;
+		XLogRecPtr	recptr;
+
+		xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
+
+		XLogBeginInsert();
+		XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
+
+		XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
+		XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
+
+		/* inplace updates aren't decoded atm, don't log the origin */
+
+		recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
+
+		PageSetLSN(page, recptr);
+	}
+
+	END_CRIT_SECTION();
+
+	UnlockReleaseBuffer(buffer);
+
+	/*
+	 * Send out shared cache inval if necessary.  Note that because we only
+	 * pass the new version of the tuple, this mustn't be used for any
+	 * operations that could change catcache lookup keys.  But we aren't
+	 * bothering with index updates either, so that's true a fortiori.
+	 */
+	if (!IsBootstrapProcessingMode())
+		CacheInvalidateHeapTuple(relation, tuple, NULL);
+}
+
+/* ----------------------------------------------------------------
+ *						 heap lock tuple routines
+ * ----------------------------------------------------------------
+ */
 
 /*
  * Return the MultiXactStatus corresponding to the given tuple lock mode.
@@ -6153,104 +6057,10 @@ heap_abort_speculative(Relation relation, HeapTuple tuple)
 	pgstat_count_heap_delete(relation);
 }
 
-/*
- * heap_inplace_update - update a tuple "in place" (ie, overwrite it)
- *
- * Overwriting violates both MVCC and transactional safety, so the uses
- * of this function in Postgres are extremely limited.  Nonetheless we
- * find some places to use it.
- *
- * The tuple cannot change size, and therefore it's reasonable to assume
- * that its null bitmap (if any) doesn't change either.  So we just
- * overwrite the data portion of the tuple without touching the null
- * bitmap or any of the header fields.
- *
- * tuple is an in-memory tuple structure containing the data to be written
- * over the target tuple.  Also, tuple->t_self identifies the target tuple.
+/* ----------------------------------------------------------------
+ *						 heap multixact and freeze tuple routines
+ * ----------------------------------------------------------------
  */
-void
-heap_inplace_update(Relation relation, HeapTuple tuple)
-{
-	Buffer		buffer;
-	Page		page;
-	OffsetNumber offnum;
-	ItemId		lp = NULL;
-	HeapTupleHeader htup;
-	uint32		oldlen;
-	uint32		newlen;
-
-	/*
-	 * For now, parallel operations are required to be strictly read-only.
-	 * Unlike a regular update, this should never create a combo CID, so it
-	 * might be possible to relax this restriction, but not without more
-	 * thought and testing.  It's not clear that it would be useful, anyway.
-	 */
-	if (IsInParallelMode())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot update tuples during a parallel operation")));
-
-	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
-	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
-	page = (Page) BufferGetPage(buffer);
-
-	offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
-	if (PageGetMaxOffsetNumber(page) >= offnum)
-		lp = PageGetItemId(page, offnum);
-
-	if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
-		elog(ERROR, "invalid lp");
-
-	htup = PageGetItemHeap(page, lp);
-
-	oldlen = ItemIdGetLength(lp) - htup->t_hoff;
-	newlen = tuple->t_len - tuple->t_data->t_hoff;
-	if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
-		elog(ERROR, "wrong tuple length");
-
-	/* NO EREPORT(ERROR) from here till changes are logged */
-	START_CRIT_SECTION();
-
-	memcpy((char *) htup + htup->t_hoff,
-		   (char *) tuple->t_data + tuple->t_data->t_hoff,
-		   newlen);
-
-	MarkBufferDirty(buffer);
-
-	/* XLOG stuff */
-	if (RelationNeedsWAL(relation))
-	{
-		xl_heap_inplace xlrec;
-		XLogRecPtr	recptr;
-
-		xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
-
-		XLogBeginInsert();
-		XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
-
-		XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
-		XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
-
-		/* inplace updates aren't decoded atm, don't log the origin */
-
-		recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
-
-		PageSetLSN(page, recptr);
-	}
-
-	END_CRIT_SECTION();
-
-	UnlockReleaseBuffer(buffer);
-
-	/*
-	 * Send out shared cache inval if necessary.  Note that because we only
-	 * pass the new version of the tuple, this mustn't be used for any
-	 * operations that could change catcache lookup keys.  But we aren't
-	 * bothering with index updates either, so that's true a fortiori.
-	 */
-	if (!IsBootstrapProcessingMode())
-		CacheInvalidateHeapTuple(relation, tuple, NULL);
-}
 
 #define		FRM_NOOP				0x0001
 #define		FRM_INVALIDATE_XMAX		0x0002
@@ -7285,6 +7095,11 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
 	/* *latestRemovedXid may still be invalid at end */
 }
 
+/* ----------------------------------------------------------------
+ *						 heap log routines
+ * ----------------------------------------------------------------
+ */
+
 /*
  * Perform XLogInsert to register a heap cleanup info message. These
  * messages are sent once per VACUUM and are required because
@@ -9041,43 +8856,3 @@ heap2_redo(XLogReaderState *record)
 			elog(PANIC, "heap2_redo: unknown op code %u", info);
 	}
 }
-
-/*
- *	heap_sync		- sync a heap, for use when no WAL has been written
- *
- * This forces the heap contents (including TOAST heap if any) down to disk.
- * If we skipped using WAL, and WAL is otherwise needed, we must force the
- * relation down to disk before it's safe to commit the transaction.  This
- * requires writing out any dirty buffers and then doing a forced fsync.
- *
- * Indexes are not touched.  (Currently, index operations associated with
- * the commands that use this are WAL-logged and so do not need fsync.
- * That behavior might change someday, but in any case it's likely that
- * any fsync decisions required would be per-index and hence not appropriate
- * to be done here.)
- */
-void
-heap_sync(Relation rel)
-{
-	/* non-WAL-logged tables never need fsync */
-	if (!RelationNeedsWAL(rel))
-		return;
-
-	/* main heap */
-	FlushRelationBuffers(rel);
-	/* FlushRelationBuffers will have opened rd_smgr */
-	smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
-
-	/* FSM is not critical, don't bother syncing it */
-
-	/* toast heap, if any */
-	if (OidIsValid(rel->rd_rel->reltoastrelid))
-	{
-		Relation	toastrel;
-
-		toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
-		FlushRelationBuffers(toastrel);
-		smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
-		heap_close(toastrel, AccessShareLock);
-	}
-}
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index e4ef0e1..d89bdb5 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -10,6 +10,13 @@
  * IDENTIFICATION
  *	  src/backend/access/heap/hio.c
  *
+ *		relation_open	- open any relation by relation OID
+ *		relation_openrv - open any relation specified by a RangeVar
+ *		relation_close	- close any relation
+ *		heap_open		- open a heap relation by relation OID
+ *		heap_openrv		- open a heap relation specified by a RangeVar
+ *		heap_close		- (now just a macro for relation_close)
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -23,56 +30,320 @@
 #include "storage/freespace.h"
 #include "storage/lmgr.h"
 #include "storage/smgr.h"
+#include "access/xact.h"
+#include "pgstat.h"
+#include "utils/syscache.h"
+#include "utils/inval.h"
+#include "catalog/namespace.h"
 
 
-/*
- * RelationPutHeapTuple - place tuple at specified page
+/* ----------------
+ *		relation_open - open any relation by relation OID
+ *
+ *		If lockmode is not "NoLock", the specified kind of lock is
+ *		obtained on the relation.  (Generally, NoLock should only be
+ *		used if the caller knows it has some appropriate lock on the
+ *		relation already.)
  *
- * !!! EREPORT(ERROR) IS DISALLOWED HERE !!!  Must PANIC on failure!!!
+ *		An error is raised if the relation does not exist.
  *
- * Note - caller must hold BUFFER_LOCK_EXCLUSIVE on the buffer.
+ *		NB: a "relation" is anything with a pg_class entry.  The caller is
+ *		expected to check whether the relkind is something it can handle.
+ * ----------------
  */
-void
-RelationPutHeapTuple(Relation relation,
-					 Buffer buffer,
-					 HeapTuple tuple,
-					 bool token)
+Relation
+relation_open(Oid relationId, LOCKMODE lockmode)
+{
+	Relation	r;
+
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
+	/* Get the lock before trying to open the relcache entry */
+	if (lockmode != NoLock)
+		LockRelationOid(relationId, lockmode);
+
+	/* The relcache does all the real work... */
+	r = RelationIdGetRelation(relationId);
+
+	if (!RelationIsValid(r))
+		elog(ERROR, "could not open relation with OID %u", relationId);
+
+	/* Make note that we've accessed a temporary relation */
+	if (RelationUsesLocalBuffers(r))
+		MyXactAccessedTempRel = true;
+
+	pgstat_initstats(r);
+
+	return r;
+}
+
+/* ----------------
+ *		try_relation_open - open any relation by relation OID
+ *
+ *		Same as relation_open, except return NULL instead of failing
+ *		if the relation does not exist.
+ * ----------------
+ */
+Relation
+try_relation_open(Oid relationId, LOCKMODE lockmode)
 {
-	Page		pageHeader;
-	OffsetNumber offnum;
+	Relation	r;
+
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
+	/* Get the lock first */
+	if (lockmode != NoLock)
+		LockRelationOid(relationId, lockmode);
 
 	/*
-	 * A tuple that's being inserted speculatively should already have its
-	 * token set.
+	 * Now that we have the lock, probe to see if the relation really exists
+	 * or not.
 	 */
-	Assert(!token || HeapTupleHeaderIsSpeculative(tuple->t_data));
+	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
+	{
+		/* Release useless lock */
+		if (lockmode != NoLock)
+			UnlockRelationOid(relationId, lockmode);
+
+		return NULL;
+	}
 
-	/* Add the tuple to the page */
-	pageHeader = BufferGetPage(buffer);
+	/* Should be safe to do a relcache load */
+	r = RelationIdGetRelation(relationId);
 
-	offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
-						 tuple->t_len, InvalidOffsetNumber, false, true);
+	if (!RelationIsValid(r))
+		elog(ERROR, "could not open relation with OID %u", relationId);
 
-	if (offnum == InvalidOffsetNumber)
-		elog(PANIC, "failed to add tuple to page");
+	/* Make note that we've accessed a temporary relation */
+	if (RelationUsesLocalBuffers(r))
+		MyXactAccessedTempRel = true;
 
-	/* Update tuple->t_self to the actual position where it was stored */
-	ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum);
+	pgstat_initstats(r);
+
+	return r;
+}
+
+/* ----------------
+ *		relation_openrv - open any relation specified by a RangeVar
+ *
+ *		Same as relation_open, but the relation is specified by a RangeVar.
+ * ----------------
+ */
+Relation
+relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
+{
+	Oid			relOid;
 
 	/*
-	 * Insert the correct position into CTID of the stored tuple, too (unless
-	 * this is a speculative insertion, in which case the token is held in
-	 * CTID field instead)
+	 * Check for shared-cache-inval messages before trying to open the
+	 * relation.  This is needed even if we already hold a lock on the
+	 * relation, because GRANT/REVOKE are executed without taking any lock on
+	 * the target relation, and we want to be sure we see current ACL
+	 * information.  We can skip this if asked for NoLock, on the assumption
+	 * that such a call is not the first one in the current command, and so we
+	 * should be reasonably up-to-date already.  (XXX this all could stand to
+	 * be redesigned, but for the moment we'll keep doing this like it's been
+	 * done historically.)
 	 */
-	if (!token)
+	if (lockmode != NoLock)
+		AcceptInvalidationMessages();
+
+	/* Look up and lock the appropriate relation using namespace search */
+	relOid = RangeVarGetRelid(relation, lockmode, false);
+
+	/* Let relation_open do the rest */
+	return relation_open(relOid, NoLock);
+}
+
+/* ----------------
+ *		relation_openrv_extended - open any relation specified by a RangeVar
+ *
+ *		Same as relation_openrv, but with an additional missing_ok argument
+ *		allowing a NULL return rather than an error if the relation is not
+ *		found.  (Note that some other causes, such as permissions problems,
+ *		will still result in an ereport.)
+ * ----------------
+ */
+Relation
+relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
+						 bool missing_ok)
+{
+	Oid			relOid;
+
+	/*
+	 * Check for shared-cache-inval messages before trying to open the
+	 * relation.  See comments in relation_openrv().
+	 */
+	if (lockmode != NoLock)
+		AcceptInvalidationMessages();
+
+	/* Look up and lock the appropriate relation using namespace search */
+	relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
+
+	/* Return NULL on not-found */
+	if (!OidIsValid(relOid))
+		return NULL;
+
+	/* Let relation_open do the rest */
+	return relation_open(relOid, NoLock);
+}
+
+/* ----------------
+ *		relation_close - close any relation
+ *
+ *		If lockmode is not "NoLock", we then release the specified lock.
+ *
+ *		Note that it is often sensible to hold a lock beyond relation_close;
+ *		in that case, the lock is released automatically at xact end.
+ * ----------------
+ */
+void
+relation_close(Relation relation, LOCKMODE lockmode)
+{
+	LockRelId	relid = relation->rd_lockInfo.lockRelId;
+
+	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
+
+	/* The relcache does the real work... */
+	RelationClose(relation);
+
+	if (lockmode != NoLock)
+		UnlockRelationId(&relid, lockmode);
+}
+
+
+/* ----------------
+ *		heap_open - open a heap relation by relation OID
+ *
+ *		This is essentially relation_open plus check that the relation
+ *		is not an index nor a composite type.  (The caller should also
+ *		check that it's not a view or foreign table before assuming it has
+ *		storage.)
+ * ----------------
+ */
+Relation
+heap_open(Oid relationId, LOCKMODE lockmode)
+{
+	Relation	r;
+
+	r = relation_open(relationId, lockmode);
+
+	if (r->rd_rel->relkind == RELKIND_INDEX)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("\"%s\" is an index",
+						RelationGetRelationName(r))));
+	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("\"%s\" is a composite type",
+						RelationGetRelationName(r))));
+
+	return r;
+}
+
+/* ----------------
+ *		heap_openrv - open a heap relation specified
+ *		by a RangeVar node
+ *
+ *		As above, but relation is specified by a RangeVar.
+ * ----------------
+ */
+Relation
+heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
+{
+	Relation	r;
+
+	r = relation_openrv(relation, lockmode);
+
+	if (r->rd_rel->relkind == RELKIND_INDEX)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("\"%s\" is an index",
+						RelationGetRelationName(r))));
+	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("\"%s\" is a composite type",
+						RelationGetRelationName(r))));
+
+	return r;
+}
+
+/* ----------------
+ *		heap_openrv_extended - open a heap relation specified
+ *		by a RangeVar node
+ *
+ *		As above, but optionally return NULL instead of failing for
+ *		relation-not-found.
+ * ----------------
+ */
+Relation
+heap_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
+					 bool missing_ok)
+{
+	Relation	r;
+
+	r = relation_openrv_extended(relation, lockmode, missing_ok);
+
+	if (r)
 	{
-		ItemId			itemId = PageGetItemId(pageHeader, offnum);
-		HeapTupleHeader	onpage_tup = PageGetItemHeapHeaderOnly(pageHeader, itemId);
+		if (r->rd_rel->relkind == RELKIND_INDEX)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is an index",
+							RelationGetRelationName(r))));
+		else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(r))));
+	}
+
+	return r;
+}
 
-		onpage_tup->t_ctid = tuple->t_self;
+/*
+ *	heap_sync		- sync a heap, for use when no WAL has been written
+ *
+ * This forces the heap contents (including TOAST heap if any) down to disk.
+ * If we skipped using WAL, and WAL is otherwise needed, we must force the
+ * relation down to disk before it's safe to commit the transaction.  This
+ * requires writing out any dirty buffers and then doing a forced fsync.
+ *
+ * Indexes are not touched.  (Currently, index operations associated with
+ * the commands that use this are WAL-logged and so do not need fsync.
+ * That behavior might change someday, but in any case it's likely that
+ * any fsync decisions required would be per-index and hence not appropriate
+ * to be done here.)
+ */
+void
+heap_sync(Relation rel)
+{
+	/* non-WAL-logged tables never need fsync */
+	if (!RelationNeedsWAL(rel))
+		return;
+
+	/* main heap */
+	FlushRelationBuffers(rel);
+	/* FlushRelationBuffers will have opened rd_smgr */
+	smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
+
+	/* FSM is not critical, don't bother syncing it */
+
+	/* toast heap, if any */
+	if (OidIsValid(rel->rd_rel->reltoastrelid))
+	{
+		Relation	toastrel;
+
+		toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
+		FlushRelationBuffers(toastrel);
+		smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
+		heap_close(toastrel, AccessShareLock);
 	}
 }
 
+
 /*
  * Read in a buffer, using bulk-insert strategy if bistate isn't NULL.
  */
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 3e07b10..c107d0a 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -724,7 +724,6 @@ heap_page_prune_execute(Buffer buffer,
 	PageRepairFragmentation(page);
 }
 
-
 /*
  * For all items in this page, find their respective root line pointers.
  * If item k is part of a HOT-chain with root at item j, then we set
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 41d2fd4..cff766b 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -214,7 +214,7 @@ Boot_CreateStmt:
 							closerel(NULL);
 						}
 
-						boot_reldesc = heap_create($2,
+						boot_reldesc = relation_create($2,
 												   PG_CATALOG_NAMESPACE,
 												   shared_relation ? GLOBALTABLESPACE_OID : 0,
 												   $3,
@@ -231,7 +231,7 @@ Boot_CreateStmt:
 					{
 						Oid id;
 
-						id = heap_create_with_catalog($2,
+						id = relation_create_with_catalog($2,
 													  PG_CATALOG_NAMESPACE,
 													  shared_relation ? GLOBALTABLESPACE_OID : 0,
 													  $3,
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 04d7840..f6bc9f3 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1153,7 +1153,7 @@ doDeletion(const ObjectAddress *object, int flags)
 						RemoveAttributeById(object->objectId,
 											object->objectSubId);
 					else
-						heap_drop_with_catalog(object->objectId);
+						relation_drop_with_catalog(object->objectId);
 				}
 				break;
 			}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e997b57..ae8da25 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * heap.c
- *	  code to create and destroy POSTGRES heap relations
+ *	  code to create and destroy POSTGRES relations
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -12,18 +12,11 @@
  *
  *
  * INTERFACE ROUTINES
- *		heap_create()			- Create an uncataloged heap relation
- *		heap_create_with_catalog() - Create a cataloged relation
- *		heap_drop_with_catalog() - Removes named relation from catalogs
+ *		relation_create()			- Create an uncataloged relation
+ *		relation_create_with_catalog() - Create a cataloged relation
+ *		relation_drop_with_catalog() - Removes named relation from catalogs
  *
  * NOTES
- *	  this code taken from access/heap/create.c, which contains
- *	  the old heap_create_with_catalog, amcreate, and amdestroy.
- *	  those routines will soon call these routines using the function
- *	  manager,
- *	  just like the poorly named "NewXXX" routines do.  The
- *	  "New" routines are all going to die soon, once and for all!
- *		-cim 1/13/91
  *
  *-------------------------------------------------------------------------
  */
@@ -230,7 +223,7 @@ SystemAttributeByName(const char *attname, bool relhasoids)
 
 
 /* ----------------------------------------------------------------
- *		heap_create		- Create an uncataloged heap relation
+ *		relation_create		- Create an uncataloged relation
  *
  *		Note API change: the caller must now always provide the OID
  *		to use for the relation.  The relfilenode may (and, normally,
@@ -241,7 +234,7 @@ SystemAttributeByName(const char *attname, bool relhasoids)
  * ----------------------------------------------------------------
  */
 Relation
-heap_create(const char *relname,
+relation_create(const char *relname,
 			Oid relnamespace,
 			Oid reltablespace,
 			Oid relid,
@@ -361,7 +354,7 @@ heap_create(const char *relname,
 }
 
 /* ----------------------------------------------------------------
- *		heap_create_with_catalog		- Create a cataloged relation
+ *		relation_create_with_catalog		- Create a cataloged relation
  *
  *		this is done in multiple steps:
  *
@@ -372,7 +365,7 @@ heap_create(const char *relname,
  *		   performs a scan to ensure that no relation with the
  *		   same name already exists.
  *
- *		3) heap_create() is called to create the new relation on disk.
+ *		3) relation_create() is called to create the new relation on disk.
  *
  *		4) TypeCreate() is called to define a new type corresponding
  *		   to the new relation.
@@ -981,7 +974,7 @@ AddNewRelationType(const char *typeName,
 }
 
 /* --------------------------------
- *		heap_create_with_catalog
+ *		relation_create_with_catalog
  *
  *		creates a new cataloged relation.  see comments above.
  *
@@ -1015,7 +1008,7 @@ AddNewRelationType(const char *typeName,
  * --------------------------------
  */
 Oid
-heap_create_with_catalog(const char *relname,
+relation_create_with_catalog(const char *relname,
 						 Oid relnamespace,
 						 Oid reltablespace,
 						 Oid relid,
@@ -1157,7 +1150,7 @@ heap_create_with_catalog(const char *relname,
 	 * disk file.  (If we fail further down, it's the smgr's responsibility to
 	 * remove the disk file again.)
 	 */
-	new_rel_desc = heap_create(relname,
+	new_rel_desc = relation_create(relname,
 							   relnamespace,
 							   reltablespace,
 							   relid,
@@ -1354,7 +1347,7 @@ heap_create_with_catalog(const char *relname,
 	{
 		Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
 			   relkind == RELKIND_TOASTVALUE);
-		heap_create_init_fork(new_rel_desc);
+		relation_create_init_fork(new_rel_desc);
 	}
 
 	/*
@@ -1375,7 +1368,7 @@ heap_create_with_catalog(const char *relname,
  * this will hit the disk before the next checkpoint moves the redo pointer.
  */
 void
-heap_create_init_fork(Relation rel)
+relation_create_init_fork(Relation rel)
 {
 	RelationOpenSmgr(rel);
 	smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
@@ -1746,16 +1739,19 @@ RemoveAttrDefaultById(Oid attrdefId)
 }
 
 /*
- * heap_drop_with_catalog	- removes specified relation from catalogs
+ * relation_drop_with_catalog	- removes specified relation from catalogs
  *
  * Note that this routine is not responsible for dropping objects that are
  * linked to the pg_class entry via dependencies (for example, indexes and
  * constraints).  Those are deleted by the dependency-tracing logic in
  * dependency.c before control gets here.  In general, therefore, this routine
  * should never be called directly; go through performDeletion() instead.
+ *
+ * NOTE that index realtions require special threatment and must use index_drop
+ * instead.
  */
 void
-heap_drop_with_catalog(Oid relid)
+relation_drop_with_catalog(Oid relid)
 {
 	Relation	rel;
 
@@ -1793,7 +1789,7 @@ heap_drop_with_catalog(Oid relid)
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "cache lookup failed for foreign table %u", relid);
 
-		simple_heap_delete(rel, &tuple->t_self);
+		(rel, &tuple->t_self);
 
 		ReleaseSysCache(tuple);
 		heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 7b30e46..a1ff729 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -834,7 +834,7 @@ index_create(Relation heapRelation,
 	 * we fail further down, it's the smgr's responsibility to remove the disk
 	 * file again.)
 	 */
-	indexRelation = heap_create(indexRelationName,
+	indexRelation = relation_create(indexRelationName,
 								namespaceId,
 								tableSpaceId,
 								indexRelationId,
@@ -857,7 +857,7 @@ index_create(Relation heapRelation,
 
 	/*
 	 * Fill in fields of the index's pg_class entry that are not set correctly
-	 * by heap_create.
+	 * by relation_create.
 	 *
 	 * XXX should have a cleaner way to create cataloged indexes
 	 */
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 564e10e..4314f3e 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -259,7 +259,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 		binary_upgrade_next_toast_pg_type_oid = InvalidOid;
 	}
 
-	toast_relid = heap_create_with_catalog(toast_relname,
+	toast_relid = relation_create_with_catalog(toast_relname,
 										   namespaceid,
 										   rel->rd_rel->reltablespace,
 										   toastOid,
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 43bbd90..a3d1fe7 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -660,7 +660,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, char relpersistence,
 	 */
 	snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", OIDOldHeap);
 
-	OIDNewHeap = heap_create_with_catalog(NewHeapName,
+	OIDNewHeap = relation_create_with_catalog(NewHeapName,
 										  namespaceid,
 										  NewTableSpace,
 										  InvalidOid,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 86e9814..6ccc2ab 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -602,7 +602,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	/*
 	 * Find columns with default values and prepare for insertion of the
 	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
-	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
+	 * CookedConstraint structs that we'll pass to relation_create_with_catalog,
 	 * while raw defaults go into a list of RawColumnDefault structs that will
 	 * be processed by AddRelationNewConstraints.  (We can't deal with raw
 	 * expressions until we can do transformExpr.)
@@ -657,7 +657,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	 * for immediate handling --- since they don't need parsing, they can be
 	 * stored immediately.
 	 */
-	relationId = heap_create_with_catalog(relname,
+	relationId = relation_create_with_catalog(relname,
 										  namespaceId,
 										  tablespaceId,
 										  InvalidOid,
@@ -1221,7 +1221,7 @@ ExecuteTruncate(TruncateStmt *stmt)
 			RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
 									  RecentXmin, minmulti);
 			if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
-				heap_create_init_fork(rel);
+				relation_create_init_fork(rel);
 
 			heap_relid = RelationGetRelid(rel);
 			toast_relid = rel->rd_rel->reltoastrelid;
@@ -1235,7 +1235,7 @@ ExecuteTruncate(TruncateStmt *stmt)
 				RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
 										  RecentXmin, minmulti);
 				if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
-					heap_create_init_fork(rel);
+					relation_create_init_fork(rel);
 				heap_close(rel, NoLock);
 			}
 
@@ -10629,7 +10629,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 /*
  * Drop the dependency created by StoreCatalogInheritance1 (CREATE TABLE
  * INHERITS/ALTER TABLE INHERIT -- refclassid will be RelationRelationId) or
- * heap_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
+ * relation_create_with_catalog (CREATE TABLE OF/ALTER TABLE OF -- refclassid will
  * be TypeRelationId).  There's no convenient way to do this, so go trawling
  * through pg_depend.
  */
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index b3a595c..6c6ab9f 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -76,7 +76,7 @@ typedef struct HeapUpdateFailureData
 /* ----------------
  *		function prototypes for heap access method
  *
- * heap_create, heap_create_with_catalog, and heap_drop_with_catalog
+ * relation_create, relation_create_with_catalog, and relation_drop_with_catalog
  * are declared in catalog/heap.h
  * ----------------
  */
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index b80d8d8..b5bd850 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -39,7 +39,7 @@ typedef struct CookedConstraint
 								 * inherited */
 } CookedConstraint;
 
-extern Relation heap_create(const char *relname,
+extern Relation relation_create(const char *relname,
 			Oid relnamespace,
 			Oid reltablespace,
 			Oid relid,
@@ -51,7 +51,7 @@ extern Relation heap_create(const char *relname,
 			bool mapped_relation,
 			bool allow_system_table_mods);
 
-extern Oid heap_create_with_catalog(const char *relname,
+extern Oid relation_create_with_catalog(const char *relname,
 						 Oid relnamespace,
 						 Oid reltablespace,
 						 Oid relid,
@@ -73,9 +73,9 @@ extern Oid heap_create_with_catalog(const char *relname,
 						 bool is_internal,
 						 ObjectAddress *typaddress);
 
-extern void heap_create_init_fork(Relation rel);
+extern void relation_create_init_fork(Relation rel);
 
-extern void heap_drop_with_catalog(Oid relid);
+extern void relation_drop_with_catalog(Oid relid);
 
 extern void heap_truncate(List *relids);
 

