diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 0152e31f0c..ea053209a1 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -27,9 +27,8 @@ OBJS = execAmi.o execCurrent.o execExpr.o execExprInterp.o \
        nodeSamplescan.o nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
        nodeValuesscan.o \
        nodeCtescan.o nodeNamedtuplestorescan.o nodeWorktablescan.o \
-       nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \
-       nodeTidrangescan.o \
-       nodeForeignscan.o nodeWindowAgg.o tstoreReceiver.o tqueue.o spi.o \
-       nodeTableFuncscan.o
+       nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidrangescan.o \
+       nodeTidscan.o nodeForeignscan.o nodeWindowAgg.o tstoreReceiver.o \
+       tqueue.o spi.o nodeTableFuncscan.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index d64771a097..58e4d8555a 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -536,10 +536,6 @@ ExecSupportsBackwardScan(Plan *node)
 			/* Simplify life for tablesample methods by disallowing this */
 			return false;
 
-		case T_TidRangeScan:
-			/* Keep TidRangeScan as simple as possible. */
-			return false;
-
 		case T_Gather:
 			return false;
 
diff --git a/src/backend/executor/nodeTidrangescan.c b/src/backend/executor/nodeTidrangescan.c
index c4706e3677..8a72f52074 100644
--- a/src/backend/executor/nodeTidrangescan.c
+++ b/src/backend/executor/nodeTidrangescan.c
@@ -12,14 +12,6 @@
  *
  *-------------------------------------------------------------------------
  */
-/*
- * INTERFACE ROUTINES
- *
- *		ExecTidRangeScan		scans a relation using a range of tids
- *		ExecInitTidRangeScan	creates and initializes state info.
- *		ExecReScanTidRangeScan	rescans the tid relation.
- *		ExecEndTidRangeScan		releases all storage.
- */
 #include "postgres.h"
 
 #include "access/relscan.h"
@@ -45,7 +37,7 @@ typedef enum
 	TIDEXPR_LOWER_BOUND
 } TidExprType;
 
-/* one element in TidExpr's opexprs */
+/* Upper or lower range bound for scan */
 typedef struct TidOpExpr
 {
 	TidExprType exprtype;		/* type of op */
@@ -93,7 +85,7 @@ MakeTidOpExpr(OpExpr *expr, TidRangeScanState *tidstate)
 			tidopexpr->exprtype = invert ? TIDEXPR_UPPER_BOUND : TIDEXPR_LOWER_BOUND;
 			break;
 		default:
-			elog(ERROR, "could not identify CTID expression");
+			elog(ERROR, "could not identify CTID operator");
 	}
 
 	tidopexpr->exprstate = exprstate;
@@ -115,8 +107,12 @@ TidExprListCreate(TidRangeScanState *tidrangestate)
 	foreach(l, node->tidrangequals)
 	{
 		OpExpr	   *opexpr = lfirst(l);
-		TidOpExpr  *tidopexpr = MakeTidOpExpr(opexpr, tidrangestate);
+		TidOpExpr  *tidopexpr;
 
+		if (!IsA(opexpr, OpExpr))
+			elog(ERROR, "could not identify CTID expression");
+
+		tidopexpr = MakeTidOpExpr(opexpr, tidrangestate);
 		tidexprs = lappend(tidexprs, tidopexpr);
 	}
 
@@ -124,8 +120,10 @@ TidExprListCreate(TidRangeScanState *tidrangestate)
 }
 
 /*
- * Set a lower bound tid, taking into account the inclusivity of the bound.
- * Return true if the bound is valid.
+ * Set 'lowerBound' based on 'tid'.  If 'inclusive' is false then the
+ * lowerBound is incremented to the next tid value so that it becomes
+ * inclusive.  If there is no valid next tid value then we return false,
+ * otherwise we return true.
  */
 static bool
 SetTidLowerBound(ItemPointer tid, bool inclusive, ItemPointer lowerBound)
@@ -144,11 +142,12 @@ SetTidLowerBound(ItemPointer tid, bool inclusive, ItemPointer lowerBound)
 
 			/*
 			 * If the lower bound was already at or above the maximum block
-			 * number, then there is no valid range.
+			 * number, then there is no valid value for it be set to.
 			 */
 			if (block >= MaxBlockNumber)
 				return false;
 
+			/* Set the lowerBound to the first offset in the next block */
 			ItemPointerSet(lowerBound, block + 1, 1);
 		}
 		else
@@ -161,8 +160,10 @@ SetTidLowerBound(ItemPointer tid, bool inclusive, ItemPointer lowerBound)
 }
 
 /*
- * Set an upper bound tid, taking into account the inclusivity of the bound.
- * Return true if the bound is valid.
+ * Set 'upperBound' based on 'tid'.  If 'inclusive' is false then the
+ * upperBound is decremented to the previous tid value so that it becomes
+ * inclusive.  If there is no valid previous tid value then we return false,
+ * otherwise we return true.
  */
 static bool
 SetTidUpperBound(ItemPointer tid, bool inclusive, ItemPointer upperBound)
@@ -189,7 +190,7 @@ SetTidUpperBound(ItemPointer tid, bool inclusive, ItemPointer upperBound)
 
 			/*
 			 * If the upper bound was already in block 0, then there is no
-			 * valid range.
+			 * valid value for it to be set to.
 			 */
 			if (block == 0)
 				return false;
@@ -206,8 +207,9 @@ SetTidUpperBound(ItemPointer tid, bool inclusive, ItemPointer upperBound)
 /* ----------------------------------------------------------------
  *		TidRangeEval
  *
- *		Compute the range of TIDs to scan, by evaluating the
- *		expressions for them.
+ *		Compute and set node's block and offset range to scan by evaluating
+ *		the trss_tidexprs.  If we detect an invalid range that cannot yield
+ *		any rows, the range is left unset.
  * ----------------------------------------------------------------
  */
 static void
@@ -227,7 +229,6 @@ TidRangeEval(TidRangeScanState *node)
 	 */
 	nblocks = RelationGetNumberOfBlocks(node->ss.ss_currentRelation);
 
-
 	/* The biggest range on an empty table is empty; just skip it. */
 	if (nblocks == 0)
 		return;
@@ -256,6 +257,10 @@ TidRangeEval(TidRangeScanState *node)
 		{
 			ItemPointerData lb;
 
+			/*
+			 * If the lower bound is beyond the maximum value for ctid, then
+			 * just bail without setting the range.  No rows can match.
+			 */
 			if (!SetTidLowerBound(itemptr, tidopexpr->inclusive, &lb))
 				return;
 
@@ -267,6 +272,10 @@ TidRangeEval(TidRangeScanState *node)
 		{
 			ItemPointerData ub;
 
+			/*
+			 * If the upper bound is below the minimum value for ctid, then
+			 * just bail without setting the range.  No rows can match.
+			 */
 			if (!SetTidUpperBound(itemptr, tidopexpr->inclusive, &ub))
 				return;
 
@@ -275,7 +284,7 @@ TidRangeEval(TidRangeScanState *node)
 		}
 	}
 
-	/* If the resulting range is not empty, use it. */
+	/* If the resulting range is not empty, set it. */
 	if (ItemPointerCompare(&lowerBound, &upperBound) <= 0)
 	{
 		node->trss_startBlock = ItemPointerGetBlockNumberNoCheck(&lowerBound);
@@ -290,7 +299,7 @@ TidRangeEval(TidRangeScanState *node)
  *
  *		Fetch the next tuple when scanning a range of TIDs.
  *
- *		Since the heap access method may return tuples that are in the scan
+ *		Since the table access method may return tuples that are in the scan
  *		limit, but not within the required TID range, this function will
  *		check for such tuples and skip over them.
  * ----------------------------------------------------------------
@@ -399,7 +408,7 @@ TidRangeNext(TidRangeScanState *node)
 	foundTuple = NextInTidRange(node, scandesc, slot);
 
 	/*
-	 * If we've exhuasted all the tuples in the range, reset the inScan flag.
+	 * If we've exhausted all the tuples in the range, reset the inScan flag.
 	 * This will cause the heap to be rescanned for any subsequent fetches,
 	 * which is important for some cursor operations: for instance, FETCH LAST
 	 * fetches all the tuples in order and then fetches one tuple in reverse.
@@ -460,8 +469,7 @@ ExecReScanTidRangeScan(TidRangeScanState *node)
 	TableScanDesc scan = node->ss.ss_currentScanDesc;
 
 	if (scan != NULL)
-		table_rescan(scan,		/* scan desc */
-					 NULL);		/* new scan keys */
+		table_rescan(scan, NULL);
 
 	/* mark scan as not in progress, and tid range list as not computed yet */
 	node->trss_inScan = false;
@@ -482,6 +490,9 @@ ExecEndTidRangeScan(TidRangeScanState *node)
 {
 	TableScanDesc scan = node->ss.ss_currentScanDesc;
 
+	if (scan != NULL)
+		table_endscan(scan);
+
 	/*
 	 * Free the exprcontext
 	 */
@@ -493,10 +504,6 @@ ExecEndTidRangeScan(TidRangeScanState *node)
 	if (node->ss.ps.ps_ResultTupleSlot)
 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
-	/* close heap scan */
-	if (scan != NULL)
-		table_endscan(scan);
 }
 
 /* ----------------------------------------------------------------
@@ -532,7 +539,7 @@ ExecInitTidRangeScan(TidRangeScan *node, EState *estate, int eflags)
 	ExecAssignExprContext(estate, &tidrangestate->ss.ps);
 
 	/*
-	 * mark scan as not in progress, and tid range list as not computed yet
+	 * mark scan as not in progress, and tid range as not computed yet
 	 */
 	tidrangestate->trss_inScan = false;
 	tidrangestate->trss_startBlock = InvalidBlockNumber;
@@ -543,7 +550,7 @@ ExecInitTidRangeScan(TidRangeScan *node, EState *estate, int eflags)
 	currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
 
 	tidrangestate->ss.ss_currentRelation = currentRelation;
-	tidrangestate->ss.ss_currentScanDesc = NULL;	/* no heap scan here */
+	tidrangestate->ss.ss_currentScanDesc = NULL;	/* no table scan here */
 
 	/*
 	 * get the scan type from the relation descriptor.
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index a67111ee6b..616fe75749 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -1273,8 +1273,8 @@ cost_tidscan(Path *path, PlannerInfo *root,
 
 /*
  * cost_tidrangescan
- *	  Determines and returns the cost of scanning a relation using a range of
- *	  TIDs.
+ *	  Determines and sets the costs of scanning a relation using a range of
+ *	  TIDs for 'path'
  *
  * 'baserel' is the relation to be scanned
  * 'tidrangequals' is the list of TID-checkable range quals
@@ -1282,7 +1282,8 @@ cost_tidscan(Path *path, PlannerInfo *root,
  */
 void
 cost_tidrangescan(Path *path, PlannerInfo *root,
-				  RelOptInfo *baserel, List *tidrangequals, ParamPathInfo *param_info)
+				  RelOptInfo *baserel, List *tidrangequals,
+				  ParamPathInfo *param_info)
 {
 	Selectivity selectivity;
 	double		pages;
@@ -1292,7 +1293,6 @@ cost_tidrangescan(Path *path, PlannerInfo *root,
 	Cost		cpu_per_tuple;
 	QualCost	tid_qual_cost;
 	double		ntuples;
-	double		nrandompages;
 	double		nseqpages;
 	double		spc_random_page_cost;
 	double		spc_seq_page_cost;
@@ -1325,7 +1325,6 @@ cost_tidrangescan(Path *path, PlannerInfo *root,
 	 */
 	ntuples = selectivity * baserel->tuples;
 	nseqpages = pages - 1.0;
-	nrandompages = 1.0;
 
 	if (!enable_tidscan)
 		startup_cost += disable_cost;
@@ -1341,8 +1340,8 @@ cost_tidrangescan(Path *path, PlannerInfo *root,
 							  &spc_random_page_cost,
 							  &spc_seq_page_cost);
 
-	/* disk costs */
-	run_cost += spc_random_page_cost * nrandompages + spc_seq_page_cost * nseqpages;
+	/* disk costs; 1 random page and the remainder as seq pages */
+	run_cost += spc_random_page_cost + spc_seq_page_cost * nseqpages;
 
 	/* Add scanning CPU costs */
 	get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c
index 3f8533c8d8..2e8535fa14 100644
--- a/src/backend/optimizer/path/tidpath.c
+++ b/src/backend/optimizer/path/tidpath.c
@@ -73,7 +73,7 @@ IsCTIDVar(Var *var, RelOptInfo *rel)
  * and nothing on the other side of the clause does.
  */
 static bool
-IsTidBinaryClause(RestrictInfo *rinfo, RelOptInfo *rel)
+IsBinaryTidClause(RestrictInfo *rinfo, RelOptInfo *rel)
 {
 	OpExpr	   *node;
 	Node	   *arg1,
@@ -86,7 +86,7 @@ IsTidBinaryClause(RestrictInfo *rinfo, RelOptInfo *rel)
 		return false;
 	node = (OpExpr *) rinfo->clause;
 
-	/* Operator must take two arguments */
+	/* OpExpr must have two arguments */
 	if (list_length(node->args) != 2)
 		return false;
 	arg1 = linitial(node->args);
@@ -129,9 +129,13 @@ IsTidBinaryClause(RestrictInfo *rinfo, RelOptInfo *rel)
 static bool
 IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
 {
-	if (!IsTidBinaryClause(rinfo, rel))
+	if (!IsBinaryTidClause(rinfo, rel))
 		return false;
-	return ((OpExpr *) rinfo->clause)->opno == TIDEqualOperator;
+
+	if (((OpExpr *) rinfo->clause)->opno == TIDEqualOperator)
+		return true;
+
+	return false;
 }
 
 /*
@@ -147,13 +151,15 @@ IsTidRangeClause(RestrictInfo *rinfo, RelOptInfo *rel)
 {
 	Oid			opno;
 
-	if (!IsTidBinaryClause(rinfo, rel))
+	if (!IsBinaryTidClause(rinfo, rel))
 		return false;
 	opno = ((OpExpr *) rinfo->clause)->opno;
-	return opno == TIDLessOperator ||
-		opno == TIDLessEqOperator ||
-		opno == TIDGreaterOperator ||
-		opno == TIDGreaterEqOperator;
+
+	if (opno == TIDLessOperator || opno == TIDLessEqOperator ||
+		opno == TIDGreaterOperator || opno == TIDGreaterEqOperator)
+		return true;
+
+	return false;
 }
 
 /*
@@ -262,7 +268,7 @@ TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel)
  *
  * Returns a List of CTID qual RestrictInfos for the specified rel (with
  * implicit OR semantics across the list), or NIL if there are no usable
- * conditions.
+ * equality conditions.
  *
  * This function is just concerned with handling AND/OR recursion.
  */
@@ -346,7 +352,7 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
  *
  * Returns a List of CTID range qual RestrictInfos for the specified rel
  * (with implicit AND semantics across the list), or NIL if there are no
- * usable conditions.
+ * usable range conditions.
  */
 static List *
 TidRangeQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
@@ -362,9 +368,7 @@ TidRangeQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
 		RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
 
 		if (IsTidRangeClause(rinfo, rel))
-		{
 			rlst = lappend(rlst, rinfo);
-		}
 	}
 
 	return rlst;
@@ -478,7 +482,8 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
 	 * If there are range quals in the baserestrict list, generate a
 	 * TidRangePath.
 	 */
-	tidrangequals = TidRangeQualFromRestrictInfoList(rel->baserestrictinfo, rel);
+	tidrangequals = TidRangeQualFromRestrictInfoList(rel->baserestrictinfo,
+													 rel);
 
 	if (tidrangequals)
 	{
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 018da82719..104be4082d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -127,8 +127,10 @@ static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
 static void bitmap_subplan_mark_shared(Plan *plan);
 static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
 									List *tlist, List *scan_clauses);
-static TidRangeScan *create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path,
-											  List *tlist, List *scan_clauses);
+static TidRangeScan *create_tidrangescan_plan(PlannerInfo *root,
+											  TidRangePath *best_path,
+											  List *tlist,
+											  List *scan_clauses);
 static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root,
 											  SubqueryScanPath *best_path,
 											  List *tlist, List *scan_clauses);
@@ -3386,7 +3388,7 @@ create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path,
 
 	/*
 	 * The qpqual list must contain all restrictions not enforced by the
-	 * tidrangequals list.  tidquals has AND semantics, so we can simply
+	 * tidrangequals list.  tidrangequals has AND semantics, so we can simply
 	 * remove any qual that appears in it.
 	 */
 	{
@@ -3401,8 +3403,6 @@ create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path,
 				continue;		/* we may drop pseudoconstants here */
 			if (list_member_ptr(tidrangequals, rinfo))
 				continue;		/* simple duplicate */
-			if (is_redundant_derived_clause(rinfo, tidrangequals))
-				continue;		/* derived from same EquivalenceClass */
 			qpqual = lappend(qpqual, rinfo);
 		}
 		scan_clauses = qpqual;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index c06a053ca9..5c7a3a04d0 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1178,8 +1178,8 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
  *	  the pathnode.
  */
 TidRangePath *
-create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel, List *tidrangequals,
-						 Relids required_outer)
+create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel,
+						 List *tidrangequals, Relids required_outer)
 {
 	TidRangePath *pathnode = makeNode(TidRangePath);
 
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 162a369655..77e4ba6726 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -445,7 +445,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	get_relation_foreign_keys(root, rel, relation, inhparent);
 
 	/* Collect info about functions implemented by the rel's table AM. */
-	rel->has_scan_setlimits = relation->rd_tableam && relation->rd_tableam->scan_bitmap_next_block != NULL;
+	rel->has_scan_setlimits = relation->rd_tableam &&
+							  relation->rd_tableam->scan_setlimits != NULL;
 
 	/*
 	 * Collect info about relation's partitioning scheme, if any. Only
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 109741b52e..fa47119213 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -859,7 +859,6 @@ static inline void
 table_scan_setlimits(TableScanDesc scan,
 					 BlockNumber startBlk, BlockNumber numBlks)
 {
-	Assert(scan->rs_rd->rd_tableam->scan_setlimits != NULL);
 	scan->rs_rd->rd_tableam->scan_setlimits(scan, startBlk, numBlks);
 }
 
diff --git a/src/include/executor/nodeTidrangescan.h b/src/include/executor/nodeTidrangescan.h
index cff87907fa..f0bbcc6a04 100644
--- a/src/include/executor/nodeTidrangescan.h
+++ b/src/include/executor/nodeTidrangescan.h
@@ -16,7 +16,8 @@
 
 #include "nodes/execnodes.h"
 
-extern TidRangeScanState *ExecInitTidRangeScan(TidRangeScan *node, EState *estate, int eflags);
+extern TidRangeScanState *ExecInitTidRangeScan(TidRangeScan *node,
+											   EState *estate, int eflags);
 extern void ExecEndTidRangeScan(TidRangeScanState *node);
 extern void ExecReScanTidRangeScan(TidRangeScanState *node);
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index fdf37b0bc9..6a1328481d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1580,7 +1580,8 @@ typedef struct TidScanState
  *		trss_tidexprs		list of TidOpExpr structs (see nodeTidrangescan.c)
  *		trss_startBlock		first block to scan
  *		trss_endBlock		last block to scan (inclusive)
- *		trss_startOffset	first offset in first block to scan
+ *		trss_startOffset	first offset in first block to scan or InvalidBlockNumber
+ *							when the range is not set
  *		trss_endOffset		last offset in last block to scan (inclusive)
  *		trss_inScan			is a scan currently in progress?
  * ----------------
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 9d90a996df..c352a7c1a7 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -83,7 +83,8 @@ extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec);
 extern void cost_tidscan(Path *path, PlannerInfo *root,
 						 RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info);
 extern void cost_tidrangescan(Path *path, PlannerInfo *root,
-							  RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info);
+							  RelOptInfo *baserel, List *tidquals,
+							  ParamPathInfo *param_info);
 extern void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
 							  RelOptInfo *baserel, ParamPathInfo *param_info);
 extern void cost_functionscan(Path *path, PlannerInfo *root,
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 23b6bc4d3d..dff8fdd126 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -63,8 +63,10 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
 										   List *bitmapquals);
 extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
 									List *tidquals, Relids required_outer);
-extern TidRangePath *create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel,
-											  List *tidrangequals, Relids required_outer);
+extern TidRangePath *create_tidrangescan_path(PlannerInfo *root,
+											  RelOptInfo *rel,
+											  List *tidrangequals,
+											  Relids required_outer);
 extern AppendPath *create_append_path(PlannerInfo *root, RelOptInfo *rel,
 									  List *subpaths, List *partial_subpaths,
 									  List *pathkeys, Relids required_outer,
diff --git a/src/test/regress/expected/tidrangescan.out b/src/test/regress/expected/tidrangescan.out
index 6a1d08686c..fc11894c8e 100644
--- a/src/test/regress/expected/tidrangescan.out
+++ b/src/test/regress/expected/tidrangescan.out
@@ -1,7 +1,13 @@
 -- tests for tidrangescans
+SET enable_seqscan TO off;
 CREATE TABLE tidrangescan(id integer, data text);
-INSERT INTO tidrangescan SELECT i,repeat('x', 100) FROM generate_series(1,1000) AS s(i);
-DELETE FROM tidrangescan WHERE substring(ctid::text from ',(\d+)\)')::integer > 10 OR substring(ctid::text from '\((\d+),')::integer >= 10;;
+-- insert enough tuples to fill at least two pages
+INSERT INTO tidrangescan SELECT i,repeat('x', 100) FROM generate_series(1,200) AS s(i);
+-- remove all tuples after the 10th tuple on each page.  Trying to ensure
+-- we get the same layout with all CPU architectures and smaller than standard
+-- page sizes.
+DELETE FROM tidrangescan
+WHERE substring(ctid::text from ',(\d+)\)')::integer > 10 OR substring(ctid::text from '\((\d+),')::integer > 2;
 VACUUM tidrangescan;
 -- range scans with upper bound
 EXPLAIN (COSTS OFF)
@@ -70,49 +76,49 @@ SELECT ctid FROM tidrangescan WHERE ctid < '(0,0)';
 
 -- range scans with lower bound
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid > '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid > '(2,8)';
             QUERY PLAN             
 -----------------------------------
  Tid Range Scan on tidrangescan
-   TID Cond: (ctid > '(9,8)'::tid)
+   TID Cond: (ctid > '(2,8)'::tid)
 (2 rows)
 
-SELECT ctid FROM tidrangescan WHERE ctid > '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid > '(2,8)';
   ctid  
 --------
- (9,9)
- (9,10)
+ (2,9)
+ (2,10)
 (2 rows)
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE '(9,8)' < ctid;
+SELECT ctid FROM tidrangescan WHERE '(2,8)' < ctid;
             QUERY PLAN             
 -----------------------------------
  Tid Range Scan on tidrangescan
-   TID Cond: ('(9,8)'::tid < ctid)
+   TID Cond: ('(2,8)'::tid < ctid)
 (2 rows)
 
-SELECT ctid FROM tidrangescan WHERE '(9,8)' < ctid;
+SELECT ctid FROM tidrangescan WHERE '(2,8)' < ctid;
   ctid  
 --------
- (9,9)
- (9,10)
+ (2,9)
+ (2,10)
 (2 rows)
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid >= '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid >= '(2,8)';
              QUERY PLAN             
 ------------------------------------
  Tid Range Scan on tidrangescan
-   TID Cond: (ctid >= '(9,8)'::tid)
+   TID Cond: (ctid >= '(2,8)'::tid)
 (2 rows)
 
-SELECT ctid FROM tidrangescan WHERE ctid >= '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid >= '(2,8)';
   ctid  
 --------
- (9,8)
- (9,9)
- (9,10)
+ (2,8)
+ (2,9)
+ (2,10)
 (3 rows)
 
 EXPLAIN (COSTS OFF)
@@ -130,35 +136,35 @@ SELECT ctid FROM tidrangescan WHERE ctid >= '(100,0)';
 
 -- range scans with both bounds
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid > '(4,4)' AND '(4,7)' >= ctid;
+SELECT ctid FROM tidrangescan WHERE ctid > '(1,4)' AND '(1,7)' >= ctid;
                            QUERY PLAN                           
 ----------------------------------------------------------------
  Tid Range Scan on tidrangescan
-   TID Cond: ((ctid > '(4,4)'::tid) AND ('(4,7)'::tid >= ctid))
+   TID Cond: ((ctid > '(1,4)'::tid) AND ('(1,7)'::tid >= ctid))
 (2 rows)
 
-SELECT ctid FROM tidrangescan WHERE ctid > '(4,4)' AND '(4,7)' >= ctid;
+SELECT ctid FROM tidrangescan WHERE ctid > '(1,4)' AND '(1,7)' >= ctid;
  ctid  
 -------
- (4,5)
- (4,6)
- (4,7)
+ (1,5)
+ (1,6)
+ (1,7)
 (3 rows)
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE '(4,7)' >= ctid AND ctid > '(4,4)';
+SELECT ctid FROM tidrangescan WHERE '(1,7)' >= ctid AND ctid > '(1,4)';
                            QUERY PLAN                           
 ----------------------------------------------------------------
  Tid Range Scan on tidrangescan
-   TID Cond: (('(4,7)'::tid >= ctid) AND (ctid > '(4,4)'::tid))
+   TID Cond: (('(1,7)'::tid >= ctid) AND (ctid > '(1,4)'::tid))
 (2 rows)
 
-SELECT ctid FROM tidrangescan WHERE '(4,7)' >= ctid AND ctid > '(4,4)';
+SELECT ctid FROM tidrangescan WHERE '(1,7)' >= ctid AND ctid > '(1,4)';
  ctid  
 -------
- (4,5)
- (4,6)
- (4,7)
+ (1,5)
+ (1,6)
+ (1,7)
 (3 rows)
 
 -- extreme offsets
@@ -236,3 +242,4 @@ FETCH LAST c;
 COMMIT;
 DROP TABLE tidrangescan;
 DROP TABLE tidrangescan_empty;
+RESET enable_seqscan;
diff --git a/src/test/regress/sql/tidrangescan.sql b/src/test/regress/sql/tidrangescan.sql
index 1baf584937..d60439d56c 100644
--- a/src/test/regress/sql/tidrangescan.sql
+++ b/src/test/regress/sql/tidrangescan.sql
@@ -1,9 +1,16 @@
 -- tests for tidrangescans
 
+SET enable_seqscan TO off;
 CREATE TABLE tidrangescan(id integer, data text);
 
-INSERT INTO tidrangescan SELECT i,repeat('x', 100) FROM generate_series(1,1000) AS s(i);
-DELETE FROM tidrangescan WHERE substring(ctid::text from ',(\d+)\)')::integer > 10 OR substring(ctid::text from '\((\d+),')::integer >= 10;;
+-- insert enough tuples to fill at least two pages
+INSERT INTO tidrangescan SELECT i,repeat('x', 100) FROM generate_series(1,200) AS s(i);
+
+-- remove all tuples after the 10th tuple on each page.  Trying to ensure
+-- we get the same layout with all CPU architectures and smaller than standard
+-- page sizes.
+DELETE FROM tidrangescan
+WHERE substring(ctid::text from ',(\d+)\)')::integer > 10 OR substring(ctid::text from '\((\d+),')::integer > 2;
 VACUUM tidrangescan;
 
 -- range scans with upper bound
@@ -21,16 +28,16 @@ SELECT ctid FROM tidrangescan WHERE ctid < '(0,0)';
 
 -- range scans with lower bound
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid > '(9,8)';
-SELECT ctid FROM tidrangescan WHERE ctid > '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid > '(2,8)';
+SELECT ctid FROM tidrangescan WHERE ctid > '(2,8)';
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE '(9,8)' < ctid;
-SELECT ctid FROM tidrangescan WHERE '(9,8)' < ctid;
+SELECT ctid FROM tidrangescan WHERE '(2,8)' < ctid;
+SELECT ctid FROM tidrangescan WHERE '(2,8)' < ctid;
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid >= '(9,8)';
-SELECT ctid FROM tidrangescan WHERE ctid >= '(9,8)';
+SELECT ctid FROM tidrangescan WHERE ctid >= '(2,8)';
+SELECT ctid FROM tidrangescan WHERE ctid >= '(2,8)';
 
 EXPLAIN (COSTS OFF)
 SELECT ctid FROM tidrangescan WHERE ctid >= '(100,0)';
@@ -38,12 +45,12 @@ SELECT ctid FROM tidrangescan WHERE ctid >= '(100,0)';
 
 -- range scans with both bounds
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE ctid > '(4,4)' AND '(4,7)' >= ctid;
-SELECT ctid FROM tidrangescan WHERE ctid > '(4,4)' AND '(4,7)' >= ctid;
+SELECT ctid FROM tidrangescan WHERE ctid > '(1,4)' AND '(1,7)' >= ctid;
+SELECT ctid FROM tidrangescan WHERE ctid > '(1,4)' AND '(1,7)' >= ctid;
 
 EXPLAIN (COSTS OFF)
-SELECT ctid FROM tidrangescan WHERE '(4,7)' >= ctid AND ctid > '(4,4)';
-SELECT ctid FROM tidrangescan WHERE '(4,7)' >= ctid AND ctid > '(4,4)';
+SELECT ctid FROM tidrangescan WHERE '(1,7)' >= ctid AND ctid > '(1,4)';
+SELECT ctid FROM tidrangescan WHERE '(1,7)' >= ctid AND ctid > '(1,4)';
 
 -- extreme offsets
 SELECT ctid FROM tidrangescan where ctid > '(0,65535)' AND ctid < '(1,0)' LIMIT 1;
@@ -72,3 +79,5 @@ COMMIT;
 
 DROP TABLE tidrangescan;
 DROP TABLE tidrangescan_empty;
+
+RESET enable_seqscan;
