diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index bd92b9adfbb245256248736c919a33c233895eec..cf2edbf31ee503ffd959ff8ef8b13ce04fbe8055 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.85 2008/03/26 21:10:37 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.86 2008/04/12 23:14:21 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1184,7 +1184,9 @@ toast_save_datum(Relation rel, Datum value,
 		toast_pointer.va_extsize = data_todo;
 	}
 
-	toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, toastidx);
+	toast_pointer.va_valueid = GetNewOidWithIndex(toastrel,
+												  RelationGetRelid(toastidx),
+												  (AttrNumber) 1);
 	toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid;
 
 	/*
@@ -1273,7 +1275,7 @@ toast_delete_datum(Relation rel, Datum value)
 	Relation	toastrel;
 	Relation	toastidx;
 	ScanKeyData toastkey;
-	IndexScanDesc toastscan;
+	SysScanDesc toastscan;
 	HeapTuple	toasttup;
 
 	if (!VARATT_IS_EXTERNAL(attr))
@@ -1289,8 +1291,7 @@ toast_delete_datum(Relation rel, Datum value)
 	toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
 
 	/*
-	 * Setup a scan key to fetch from the index by va_valueid (we don't
-	 * particularly care whether we see them in sequence or not)
+	 * Setup a scan key to find chunks with matching va_valueid
 	 */
 	ScanKeyInit(&toastkey,
 				(AttrNumber) 1,
@@ -1298,11 +1299,13 @@ toast_delete_datum(Relation rel, Datum value)
 				ObjectIdGetDatum(toast_pointer.va_valueid));
 
 	/*
-	 * Find the chunks by index
+	 * Find all the chunks.  (We don't actually care whether we see them in
+	 * sequence or not, but since we've already locked the index we might
+	 * as well use systable_beginscan_ordered.)
 	 */
-	toastscan = index_beginscan(toastrel, toastidx,
-								SnapshotToast, 1, &toastkey);
-	while ((toasttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
+	toastscan = systable_beginscan_ordered(toastrel, toastidx,
+										   SnapshotToast, 1, &toastkey);
+	while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
 		/*
 		 * Have a chunk, delete it
@@ -1313,7 +1316,7 @@ toast_delete_datum(Relation rel, Datum value)
 	/*
 	 * End scan and close relations
 	 */
-	index_endscan(toastscan);
+	systable_endscan_ordered(toastscan);
 	index_close(toastidx, RowExclusiveLock);
 	heap_close(toastrel, RowExclusiveLock);
 }
@@ -1332,7 +1335,7 @@ toast_fetch_datum(struct varlena * attr)
 	Relation	toastrel;
 	Relation	toastidx;
 	ScanKeyData toastkey;
-	IndexScanDesc toastscan;
+	SysScanDesc toastscan;
 	HeapTuple	ttup;
 	TupleDesc	toasttupDesc;
 	struct varlena *result;
@@ -1383,9 +1386,9 @@ toast_fetch_datum(struct varlena * attr)
 	 */
 	nextidx = 0;
 
-	toastscan = index_beginscan(toastrel, toastidx,
-								SnapshotToast, 1, &toastkey);
-	while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
+	toastscan = systable_beginscan_ordered(toastrel, toastidx,
+										   SnapshotToast, 1, &toastkey);
+	while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
 		/*
 		 * Have a chunk, extract the sequence number and the data
@@ -1464,7 +1467,7 @@ toast_fetch_datum(struct varlena * attr)
 	/*
 	 * End scan and close relations
 	 */
-	index_endscan(toastscan);
+	systable_endscan_ordered(toastscan);
 	index_close(toastidx, AccessShareLock);
 	heap_close(toastrel, AccessShareLock);
 
@@ -1485,7 +1488,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	Relation	toastidx;
 	ScanKeyData toastkey[3];
 	int			nscankeys;
-	IndexScanDesc toastscan;
+	SysScanDesc toastscan;
 	HeapTuple	ttup;
 	TupleDesc	toasttupDesc;
 	struct varlena *result;
@@ -1592,9 +1595,9 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	 * The index is on (valueid, chunkidx) so they will come in order
 	 */
 	nextidx = startchunk;
-	toastscan = index_beginscan(toastrel, toastidx,
-								SnapshotToast, nscankeys, toastkey);
-	while ((ttup = index_getnext(toastscan, ForwardScanDirection)) != NULL)
+	toastscan = systable_beginscan_ordered(toastrel, toastidx,
+										   SnapshotToast, nscankeys, toastkey);
+	while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
 		/*
 		 * Have a chunk, extract the sequence number and the data
@@ -1681,7 +1684,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	/*
 	 * End scan and close relations
 	 */
-	index_endscan(toastscan);
+	systable_endscan_ordered(toastscan);
 	index_close(toastidx, AccessShareLock);
 	heap_close(toastrel, AccessShareLock);
 
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 8877938322d5c83b8be4a4b4c38f7a02a5b04026..cafb1e6867aa1bcade2849c801c65370cc7dbf0c 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.66 2008/04/10 22:25:25 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.67 2008/04/12 23:14:21 tgl Exp $
  *
  * NOTES
  *	  many of the old access method routines have been turned into
@@ -258,3 +258,87 @@ systable_endscan(SysScanDesc sysscan)
 
 	pfree(sysscan);
 }
+
+
+/*
+ * systable_beginscan_ordered --- set up for ordered catalog scan
+ *
+ * These routines have essentially the same API as systable_beginscan etc,
+ * except that they guarantee to return multiple matching tuples in
+ * index order.  Also, for largely historical reasons, the index to use
+ * is opened and locked by the caller, not here.
+ *
+ * Currently we do not support non-index-based scans here.  (In principle
+ * we could do a heapscan and sort, but the uses are in places that
+ * probably don't need to still work with corrupted catalog indexes.)
+ * For the moment, therefore, these functions are merely the thinnest of
+ * wrappers around index_beginscan/index_getnext.  The main reason for their
+ * existence is to centralize possible future support of lossy operators
+ * in catalog scans.
+ */
+SysScanDesc
+systable_beginscan_ordered(Relation heapRelation,
+						   Relation indexRelation,
+						   Snapshot snapshot,
+						   int nkeys, ScanKey key)
+{
+	SysScanDesc sysscan;
+	int			i;
+
+	/* REINDEX can probably be a hard error here ... */
+	if (ReindexIsProcessingIndex(RelationGetRelid(indexRelation)))
+		elog(ERROR, "cannot do ordered scan on index \"%s\", because it is the current REINDEX target",
+			 RelationGetRelationName(indexRelation));
+	/* ... but we only throw a warning about violating IgnoreSystemIndexes */
+	if (IgnoreSystemIndexes)
+		elog(WARNING, "using index \"%s\" despite IgnoreSystemIndexes",
+			 RelationGetRelationName(indexRelation));
+
+	sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
+
+	sysscan->heap_rel = heapRelation;
+	sysscan->irel = indexRelation;
+
+	/*
+	 * Change attribute numbers to be index column numbers.
+	 *
+	 * This code could be generalized to search for the index key numbers
+	 * to substitute, but for now there's no need.
+	 */
+	for (i = 0; i < nkeys; i++)
+	{
+		Assert(key[i].sk_attno == indexRelation->rd_index->indkey.values[i]);
+		key[i].sk_attno = i + 1;
+	}
+
+	sysscan->iscan = index_beginscan(heapRelation, indexRelation,
+									 snapshot, nkeys, key);
+	sysscan->scan = NULL;
+
+	return sysscan;
+}
+
+/*
+ * systable_getnext_ordered --- get next tuple in an ordered catalog scan
+ */
+HeapTuple
+systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
+{
+	HeapTuple	htup;
+
+	Assert(sysscan->irel);
+	htup = index_getnext(sysscan->iscan, direction);
+
+	return htup;
+}
+
+/*
+ * systable_endscan_ordered --- close scan, release resources
+ */
+void
+systable_endscan_ordered(SysScanDesc sysscan)
+{
+	Assert(sysscan->irel);
+	index_endscan(sysscan->iscan);
+	pfree(sysscan);
+}
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index d59f1529db1c7033a5ccc6a7f8f99da6a9140f35..7a06d0074e8516b89e8a03ef8df675be18c02f99 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.105 2008/04/10 22:25:25 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.106 2008/04/12 23:14:21 tgl Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relation OID
@@ -206,12 +206,7 @@ index_insert(Relation indexRelation,
 /*
  * index_beginscan - start a scan of an index with amgettuple
  *
- * Note: heapRelation may be NULL if there is no intention of calling
- * index_getnext on this scan; index_getnext_indexitem will not use the
- * heapRelation link (nor the snapshot).  However, the caller had better
- * be holding some kind of lock on the heap relation in any case, to ensure
- * no one deletes it (or the index) out from under us.	Caller must also
- * be holding a lock on the index.
+ * Caller must be holding suitable locks on the heap and the index.
  */
 IndexScanDesc
 index_beginscan(Relation heapRelation,
@@ -634,45 +629,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
 	return NULL;				/* failure exit */
 }
 
-/* ----------------
- *		index_getnext_indexitem - get the next index tuple from a scan
- *
- * Finds the next index tuple satisfying the scan keys.  Note that the
- * corresponding heap tuple is not accessed, and thus no time qual (snapshot)
- * check is done, other than the index AM's internal check for killed tuples
- * (which most callers of this routine will probably want to suppress by
- * setting scan->ignore_killed_tuples = false).
- *
- * On success (TRUE return), the heap TID of the found index entry is in
- * scan->xs_ctup.t_self.  scan->xs_cbuf is untouched.
- * ----------------
- */
-bool
-index_getnext_indexitem(IndexScanDesc scan,
-						ScanDirection direction)
-{
-	FmgrInfo   *procedure;
-	bool		found;
-
-	SCAN_CHECKS;
-	GET_SCAN_PROCEDURE(amgettuple);
-
-	/* just make sure this is false... */
-	scan->kill_prior_tuple = false;
-
-	/*
-	 * have the am's gettuple proc do all the work.
-	 */
-	found = DatumGetBool(FunctionCall2(procedure,
-									   PointerGetDatum(scan),
-									   Int32GetDatum(direction)));
-
-	if (found)
-		pgstat_count_index_tuples(scan->indexRelation, 1);
-
-	return found;
-}
-
 /* ----------------
  *		index_getbitmap - get all tuples at once from an index scan
  *
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index b23c8b36ab361fd6b5617d353b8430af2d310d48..314b75a7b07d1631a343fd66cc1533c4471cf5b1 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.74 2008/03/26 16:20:46 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.75 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -312,9 +312,7 @@ IsSharedRelation(Oid relationId)
 Oid
 GetNewOid(Relation relation)
 {
-	Oid			newOid;
 	Oid			oidIndex;
-	Relation	indexrel;
 
 	/* If relation doesn't have OIDs at all, caller is confused */
 	Assert(relation->rd_rel->relhasoids);
@@ -342,11 +340,7 @@ GetNewOid(Relation relation)
 	}
 
 	/* Otherwise, use the index to find a nonconflicting OID */
-	indexrel = index_open(oidIndex, AccessShareLock);
-	newOid = GetNewOidWithIndex(relation, indexrel);
-	index_close(indexrel, AccessShareLock);
-
-	return newOid;
+	return GetNewOidWithIndex(relation, oidIndex, ObjectIdAttributeNumber);
 }
 
 /*
@@ -357,16 +351,17 @@ GetNewOid(Relation relation)
  * an index that will not be recognized by RelationGetOidIndex: TOAST tables
  * and pg_largeobject have indexes that are usable, but have multiple columns
  * and are on ordinary columns rather than a true OID column.  This code
- * will work anyway, so long as the OID is the index's first column.
+ * will work anyway, so long as the OID is the index's first column.  The
+ * caller must pass in the actual heap attnum of the OID column, however.
  *
  * Caller must have a suitable lock on the relation.
  */
 Oid
-GetNewOidWithIndex(Relation relation, Relation indexrel)
+GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
 {
 	Oid			newOid;
 	SnapshotData SnapshotDirty;
-	IndexScanDesc scan;
+	SysScanDesc	scan;
 	ScanKeyData key;
 	bool		collides;
 
@@ -380,17 +375,17 @@ GetNewOidWithIndex(Relation relation, Relation indexrel)
 		newOid = GetNewObjectId();
 
 		ScanKeyInit(&key,
-					(AttrNumber) 1,
+					oidcolumn,
 					BTEqualStrategyNumber, F_OIDEQ,
 					ObjectIdGetDatum(newOid));
 
 		/* see notes above about using SnapshotDirty */
-		scan = index_beginscan(relation, indexrel,
-							   &SnapshotDirty, 1, &key);
+		scan = systable_beginscan(relation, indexId, true,
+								  &SnapshotDirty, 1, &key);
 
-		collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
+		collides = HeapTupleIsValid(systable_getnext(scan));
 
-		index_endscan(scan);
+		systable_endscan(scan);
 	} while (collides);
 
 	return newOid;
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 16ad2b0349524fcf5ba0c8d1c11098938c58a5fa..00fbfd89ed6d801f5d09fe0ff1c99edb8bfbf18a 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -24,7 +24,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.131 2008/03/26 21:10:38 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.132 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -201,7 +201,8 @@ inv_create(Oid lobjId)
 	{
 		open_lo_relation();
 
-		lobjId = GetNewOidWithIndex(lo_heap_r, lo_index_r);
+		lobjId = GetNewOidWithIndex(lo_heap_r, LargeObjectLOidPNIndexId,
+									Anum_pg_largeobject_loid);
 	}
 
 	/*
@@ -311,7 +312,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
 	bool		found = false;
 	uint32		lastbyte = 0;
 	ScanKeyData skey[1];
-	IndexScanDesc sd;
+	SysScanDesc sd;
 	HeapTuple	tuple;
 
 	Assert(PointerIsValid(obj_desc));
@@ -323,8 +324,8 @@ inv_getsize(LargeObjectDesc *obj_desc)
 				BTEqualStrategyNumber, F_OIDEQ,
 				ObjectIdGetDatum(obj_desc->id));
 
-	sd = index_beginscan(lo_heap_r, lo_index_r,
-						 obj_desc->snapshot, 1, skey);
+	sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
+									obj_desc->snapshot, 1, skey);
 
 	/*
 	 * Because the pg_largeobject index is on both loid and pageno, but we
@@ -332,7 +333,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
 	 * large object in reverse pageno order.  So, it's sufficient to examine
 	 * the first valid tuple (== last valid page).
 	 */
-	while ((tuple = index_getnext(sd, BackwardScanDirection)) != NULL)
+	while ((tuple = systable_getnext_ordered(sd, BackwardScanDirection)) != NULL)
 	{
 		Form_pg_largeobject data;
 		bytea	   *datafield;
@@ -356,7 +357,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
 		break;
 	}
 
-	index_endscan(sd);
+	systable_endscan_ordered(sd);
 
 	if (!found)
 		ereport(ERROR,
@@ -415,7 +416,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 	int32		pageno = (int32) (obj_desc->offset / LOBLKSIZE);
 	uint32		pageoff;
 	ScanKeyData skey[2];
-	IndexScanDesc sd;
+	SysScanDesc sd;
 	HeapTuple	tuple;
 
 	Assert(PointerIsValid(obj_desc));
@@ -436,10 +437,10 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 				BTGreaterEqualStrategyNumber, F_INT4GE,
 				Int32GetDatum(pageno));
 
-	sd = index_beginscan(lo_heap_r, lo_index_r,
-						 obj_desc->snapshot, 2, skey);
+	sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
+									obj_desc->snapshot, 2, skey);
 
-	while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+	while ((tuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
 	{
 		Form_pg_largeobject data;
 		bytea	   *datafield;
@@ -450,7 +451,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 		data = (Form_pg_largeobject) GETSTRUCT(tuple);
 
 		/*
-		 * We assume the indexscan will deliver pages in order.  However,
+		 * We expect the indexscan will deliver pages in order.  However,
 		 * there may be missing pages if the LO contains unwritten "holes". We
 		 * want missing sections to read out as zeroes.
 		 */
@@ -495,7 +496,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
 			break;
 	}
 
-	index_endscan(sd);
+	systable_endscan_ordered(sd);
 
 	return nread;
 }
@@ -509,7 +510,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 	int			len;
 	int32		pageno = (int32) (obj_desc->offset / LOBLKSIZE);
 	ScanKeyData skey[2];
-	IndexScanDesc sd;
+	SysScanDesc sd;
 	HeapTuple	oldtuple;
 	Form_pg_largeobject olddata;
 	bool		neednextpage;
@@ -555,8 +556,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 				BTGreaterEqualStrategyNumber, F_INT4GE,
 				Int32GetDatum(pageno));
 
-	sd = index_beginscan(lo_heap_r, lo_index_r,
-						 obj_desc->snapshot, 2, skey);
+	sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
+									obj_desc->snapshot, 2, skey);
 
 	oldtuple = NULL;
 	olddata = NULL;
@@ -565,12 +566,12 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 	while (nwritten < nbytes)
 	{
 		/*
-		 * If possible, get next pre-existing page of the LO.  We assume the
+		 * If possible, get next pre-existing page of the LO.  We expect the
 		 * indexscan will deliver these in order --- but there may be holes.
 		 */
 		if (neednextpage)
 		{
-			if ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+			if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
 			{
 				if (HeapTupleHasNulls(oldtuple))		/* paranoia */
 					elog(ERROR, "null field found in pg_largeobject");
@@ -685,7 +686,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 		pageno++;
 	}
 
-	index_endscan(sd);
+	systable_endscan_ordered(sd);
 
 	CatalogCloseIndexes(indstate);
 
@@ -704,7 +705,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 	int32		pageno = (int32) (len / LOBLKSIZE);
 	int			off;
 	ScanKeyData skey[2];
-	IndexScanDesc sd;
+	SysScanDesc sd;
 	HeapTuple	oldtuple;
 	Form_pg_largeobject olddata;
 	struct
@@ -743,15 +744,15 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 				BTGreaterEqualStrategyNumber, F_INT4GE,
 				Int32GetDatum(pageno));
 
-	sd = index_beginscan(lo_heap_r, lo_index_r,
-						 obj_desc->snapshot, 2, skey);
+	sd = systable_beginscan_ordered(lo_heap_r, lo_index_r,
+									obj_desc->snapshot, 2, skey);
 
 	/*
 	 * If possible, get the page the truncation point is in. The truncation
 	 * point may be beyond the end of the LO or in a hole.
 	 */
 	olddata = NULL;
-	if ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+	if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
 	{
 		if (HeapTupleHasNulls(oldtuple))		/* paranoia */
 			elog(ERROR, "null field found in pg_largeobject");
@@ -846,12 +847,12 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
 	/*
 	 * Delete any pages after the truncation point
 	 */
-	while ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
+	while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
 	{
 		simple_heap_delete(lo_heap_r, &oldtuple->t_self);
 	}
 
-	index_endscan(sd);
+	systable_endscan_ordered(sd);
 
 	CatalogCloseIndexes(indstate);
 
diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c
index 08ae22528a42d8a29280011aa922175de14518d6..81ff577125eb607d684f179024ec7358e6c4a88f 100644
--- a/src/backend/utils/cache/ts_cache.c
+++ b/src/backend/utils/cache/ts_cache.c
@@ -20,7 +20,7 @@
  * Copyright (c) 2006-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.6 2008/03/26 21:10:39 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/ts_cache.c,v 1.7 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -419,7 +419,7 @@ lookup_ts_config_cache(Oid cfgId)
 		Relation	maprel;
 		Relation	mapidx;
 		ScanKeyData mapskey;
-		IndexScanDesc mapscan;
+		SysScanDesc mapscan;
 		HeapTuple	maptup;
 		ListDictionary maplists[MAXTOKENTYPE + 1];
 		Oid			mapdicts[MAXDICTSPERTT];
@@ -488,9 +488,10 @@ lookup_ts_config_cache(Oid cfgId)
 
 		maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
 		mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
-		mapscan = index_beginscan(maprel, mapidx, SnapshotNow, 1, &mapskey);
+		mapscan = systable_beginscan_ordered(maprel, mapidx,
+											 SnapshotNow, 1, &mapskey);
 
-		while ((maptup = index_getnext(mapscan, ForwardScanDirection)) != NULL)
+		while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
 		{
 			Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
 			int			toktype = cfgmap->maptokentype;
@@ -524,7 +525,7 @@ lookup_ts_config_cache(Oid cfgId)
 			}
 		}
 
-		index_endscan(mapscan);
+		systable_endscan_ordered(mapscan);
 		index_close(mapidx, AccessShareLock);
 		heap_close(maprel, AccessShareLock);
 
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 57785913394b07398119ca5a2cbda69e77454a38..51ce605766554a5810c8ed151a013249edd82e13 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.70 2008/04/10 22:25:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.71 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -108,8 +108,6 @@ extern void index_endscan(IndexScanDesc scan);
 extern void index_markpos(IndexScanDesc scan);
 extern void index_restrpos(IndexScanDesc scan);
 extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction);
-extern bool index_getnext_indexitem(IndexScanDesc scan,
-						ScanDirection direction);
 extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
 
 extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
@@ -140,5 +138,12 @@ extern SysScanDesc systable_beginscan(Relation heapRelation,
 				   int nkeys, ScanKey key);
 extern HeapTuple systable_getnext(SysScanDesc sysscan);
 extern void systable_endscan(SysScanDesc sysscan);
+extern SysScanDesc systable_beginscan_ordered(Relation heapRelation,
+											  Relation indexRelation,
+											  Snapshot snapshot,
+											  int nkeys, ScanKey key);
+extern HeapTuple systable_getnext_ordered(SysScanDesc sysscan,
+										  ScanDirection direction);
+extern void systable_endscan_ordered(SysScanDesc sysscan);
 
 #endif   /* GENAM_H */
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index 677fd04e2c2d94c300d11dd46e0f0186350c5031..637b363f52855beb3750224a28a1d331237fef18 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.62 2008/04/10 22:25:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.63 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,14 +76,12 @@ typedef struct IndexScanDescData
 	/* index access method's private state */
 	void	   *opaque;			/* access-method-specific info */
 
-	/*
-	 * xs_ctup/xs_cbuf are valid after a successful index_getnext. After
-	 * index_getnext_indexitem, xs_ctup.t_self contains the heap tuple TID
-	 * from the index entry, but its other fields are not valid.
-	 */
+	/* xs_ctup/xs_cbuf are valid after a successful index_getnext */
 	HeapTupleData xs_ctup;		/* current heap tuple, if any */
 	Buffer		xs_cbuf;		/* current heap buffer in scan, if any */
 	/* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
+
+	/* state data for traversing HOT chains in index_getnext */
 	TransactionId xs_prev_xmax; /* previous HOT chain member's XMAX, if any */
 	OffsetNumber xs_next_hot;	/* next member of HOT chain, if any */
 	bool		xs_hot_dead;	/* T if all members of HOT chain are dead */
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index 8ab902563e951420ce31919d446f52172c5d6eb8..753926f14ea5d485fa9b93624b450b27778f0a3f 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.38 2008/01/01 19:45:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.39 2008/04/12 23:14:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,8 @@ extern bool IsReservedName(const char *name);
 extern bool IsSharedRelation(Oid relationId);
 
 extern Oid	GetNewOid(Relation relation);
-extern Oid	GetNewOidWithIndex(Relation relation, Relation indexrel);
+extern Oid	GetNewOidWithIndex(Relation relation, Oid indexId,
+							   AttrNumber oidcolumn);
 extern Oid GetNewRelFileNode(Oid reltablespace, bool relisshared,
 				  Relation pg_class);