20130624_1_remove_reltoastidxid_v12.patch

application/octet-stream

Filename: 20130624_1_remove_reltoastidxid_v12.patch
Type: application/octet-stream
Part: 0
Message: Re: Support for REINDEX CONCURRENTLY

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v12
File+
contrib/pg_upgrade/info.c 11 4
doc/src/sgml/catalogs.sgml 0 9
doc/src/sgml/diskusage.sgml 13 13
doc/src/sgml/monitoring.sgml 2 2
src/backend/access/heap/tuptoaster.c 204 37
src/backend/catalog/heap.c 0 1
src/backend/catalog/index.c 4 19
src/backend/catalog/system_views.sql 5 5
src/backend/commands/cluster.c 29 18
src/backend/commands/tablecmds.c 18 4
src/backend/rewrite/rewriteDefine.c 2 3
src/backend/utils/adt/dbsize.c 17 7
src/bin/pg_dump/pg_dump.c 5 5
src/include/access/tuptoaster.h 9 0
src/include/catalog/pg_class.h 21 23
src/test/regress/expected/oidjoins.out 0 8
src/test/regress/expected/rules.out 8 8
src/test/regress/sql/oidjoins.sql 0 4
src/test/regress/sql/rules.sql 1 1
src/tools/findoidjoins/README 0 1
diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c
index c381f11..18daf1c 100644
--- a/contrib/pg_upgrade/info.c
+++ b/contrib/pg_upgrade/info.c
@@ -321,12 +321,19 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 							  "INSERT INTO info_rels "
 							  "SELECT reltoastrelid "
 							  "FROM info_rels i JOIN pg_catalog.pg_class c "
-							  "		ON i.reloid = c.oid"));
+							  "		ON i.reloid = c.oid "
+							  "		AND c.reltoastrelid != %u", InvalidOid));
 	PQclear(executeQueryOrDie(conn,
 							  "INSERT INTO info_rels "
-							  "SELECT reltoastidxid "
-							  "FROM info_rels i JOIN pg_catalog.pg_class c "
-							  "		ON i.reloid = c.oid"));
+							  "SELECT indexrelid "
+							  "FROM pg_index "
+							  "WHERE indisvalid "
+							  "    AND indrelid IN (SELECT reltoastrelid "
+							  "        FROM info_rels i "
+							  "            JOIN pg_catalog.pg_class c "
+							  "            ON i.reloid = c.oid "
+							  "            AND c.reltoastrelid != %u)",
+							  InvalidOid));
 
 	snprintf(query, sizeof(query),
 			 "SELECT c.oid, n.nspname, c.relname, "
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index e638a8f..f3d1d9e 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1745,15 +1745,6 @@
      </row>
 
      <row>
-      <entry><structfield>reltoastidxid</structfield></entry>
-      <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
-      <entry>
-       For a TOAST table, the OID of its index.  0 if not a TOAST table.
-      </entry>
-     </row>
-
-     <row>
       <entry><structfield>relhasindex</structfield></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
diff --git a/doc/src/sgml/diskusage.sgml b/doc/src/sgml/diskusage.sgml
index de1d0b4..461deb9 100644
--- a/doc/src/sgml/diskusage.sgml
+++ b/doc/src/sgml/diskusage.sgml
@@ -20,12 +20,12 @@
    stored. If the table has any columns with potentially-wide values,
    there also might be a <acronym>TOAST</> file associated with the table,
    which is used to store values too wide to fit comfortably in the main
-   table (see <xref linkend="storage-toast">).  There will be one index on the
-   <acronym>TOAST</> table, if present. There also might be indexes associated
-   with the base table.  Each table and index is stored in a separate disk
-   file &mdash; possibly more than one file, if the file would exceed one
-   gigabyte.  Naming conventions for these files are described in <xref
-   linkend="storage-file-layout">.
+   table (see <xref linkend="storage-toast">).  There will be one valid index
+   on the <acronym>TOAST</> table, if present. There also might be indexes
+   associated with the base table.  Each table and index is stored in a
+   separate disk file &mdash; possibly more than one file, if the file would
+   exceed one gigabyte.  Naming conventions for these files are described
+   in <xref linkend="storage-file-layout">.
   </para>
 
   <para>
@@ -44,7 +44,7 @@
 <programlisting>
 SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'customer';
 
- pg_relation_filepath | relpages 
+ pg_relation_filepath | relpages
 ----------------------+----------
  base/16384/16806     |       60
 (1 row)
@@ -65,12 +65,12 @@ FROM pg_class,
       FROM pg_class
       WHERE relname = 'customer') AS ss
 WHERE oid = ss.reltoastrelid OR
-      oid = (SELECT reltoastidxid
-             FROM pg_class
-             WHERE oid = ss.reltoastrelid)
+      oid = (SELECT indexrelid
+             FROM pg_index
+             WHERE indrelid = ss.reltoastrelid)
 ORDER BY relname;
 
-       relname        | relpages 
+       relname        | relpages
 ----------------------+----------
  pg_toast_16806       |        0
  pg_toast_16806_index |        1
@@ -87,7 +87,7 @@ WHERE c.relname = 'customer' AND
       c2.oid = i.indexrelid
 ORDER BY c2.relname;
 
-       relname        | relpages 
+       relname        | relpages
 ----------------------+----------
  customer_id_indexdex |       26
 </programlisting>
@@ -101,7 +101,7 @@ SELECT relname, relpages
 FROM pg_class
 ORDER BY relpages DESC;
 
-       relname        | relpages 
+       relname        | relpages
 ----------------------+----------
  bigtable             |     3290
  customer             |     3144
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index b37b6c3..d38c009 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -1163,12 +1163,12 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
     <row>
      <entry><structfield>tidx_blks_read</></entry>
      <entry><type>bigint</></entry>
-     <entry>Number of disk blocks read from this table's TOAST table index (if any)</entry>
+     <entry>Number of disk blocks read from this table's TOAST table indexes (if any)</entry>
     </row>
     <row>
      <entry><structfield>tidx_blks_hit</></entry>
      <entry><type>bigint</></entry>
-     <entry>Number of buffer hits in this table's TOAST table index (if any)</entry>
+     <entry>Number of buffer hits in this table's TOAST table indexes (if any)</entry>
     </row>
    </tbody>
    </tgroup>
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index fc37ceb..8457777 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -76,11 +76,13 @@ do { \
 static void toast_delete_datum(Relation rel, Datum value);
 static Datum toast_save_datum(Relation rel, Datum value,
 				 struct varlena * oldexternal, int options);
-static bool toastrel_valueid_exists(Relation toastrel, Oid valueid);
+static bool toastrel_valueid_exists(Relation toastrel,
+						Oid valueid, LOCKMODE lockmode);
 static bool toastid_valueid_exists(Oid toastrelid, Oid valueid);
 static struct varlena *toast_fetch_datum(struct varlena * attr);
 static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
 						int32 sliceoffset, int32 length);
+static Relation toast_index_fetch_valid(Relation *toastidxs, int num_indexes);
 
 
 /* ----------
@@ -1222,6 +1224,49 @@ toast_compress_datum(Datum value)
 
 
 /* ----------
+ * toast_get_valid_index
+ *
+ *	Get the valid index of given toast relation. A toast relation can only
+ *	have one valid index at the same time. The lock taken on the index
+ *	relations is released at the end of this function call.
+ */
+Oid
+toast_get_valid_index(Oid toastoid, LOCKMODE lock)
+{
+	ListCell   *lc;
+	List	   *indexlist;
+	int			num_indexes, i = 0;
+	Oid			validIndexOid;
+	Relation	validIndexRel;
+	Relation   *toastidxs;
+	Relation	toastrel;
+
+	/* Get the index list of relation */
+	toastrel = heap_open(toastoid, lock);
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+
+	/* Open all the index relations */
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), lock);
+
+	/* Fetch valid toast index */
+	validIndexRel = toast_index_fetch_valid(toastidxs, num_indexes);
+	validIndexOid = RelationGetRelid(validIndexRel);
+
+	/* Close all the index relations */
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], lock);
+	pfree(toastidxs);
+	list_free(indexlist);
+
+	heap_close(toastrel, lock);
+	return validIndexOid;
+}
+
+
+/* ----------
  * toast_save_datum -
  *
  *	Save one single datum into the secondary relation and return
@@ -1237,8 +1282,8 @@ static Datum
 toast_save_datum(Relation rel, Datum value,
 				 struct varlena * oldexternal, int options)
 {
-	Relation	toastrel;
-	Relation	toastidx;
+	Relation	toastrel, validtoastidx;
+	Relation   *toastidxs;
 	HeapTuple	toasttup;
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
@@ -1257,15 +1302,30 @@ toast_save_datum(Relation rel, Datum value,
 	char	   *data_p;
 	int32		data_todo;
 	Pointer		dval = DatumGetPointer(value);
+	ListCell   *lc;
+	List	   *indexlist;
+	int			i = 0;
+	int			num_indexes;
 
 	/*
 	 * Open the toast relation and its index.  We can use the index to check
 	 * uniqueness of the OID we assign to the toasted item, even though it has
-	 * additional columns besides OID.
+	 * additional columns besides OID. A toast table can have multiple identical
+	 * indexes associated to it.
 	 */
 	toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
 	toasttupDesc = toastrel->rd_att;
-	toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+
+	/* Open all the indexes of toast relation with similar lock */
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), RowExclusiveLock);
+
+	/* Fetch relation used for process */
+	validtoastidx = toast_index_fetch_valid(toastidxs, num_indexes);
 
 	/*
 	 * Get the data pointer and length, and compute va_rawsize and va_extsize.
@@ -1330,7 +1390,7 @@ toast_save_datum(Relation rel, Datum value,
 		/* normal case: just choose an unused OID */
 		toast_pointer.va_valueid =
 			GetNewOidWithIndex(toastrel,
-							   RelationGetRelid(toastidx),
+							   RelationGetRelid(validtoastidx),
 							   (AttrNumber) 1);
 	}
 	else
@@ -1367,7 +1427,8 @@ toast_save_datum(Relation rel, Datum value,
 				 * be reclaimed by VACUUM.
 				 */
 				if (toastrel_valueid_exists(toastrel,
-											toast_pointer.va_valueid))
+											toast_pointer.va_valueid,
+											RowExclusiveLock))
 				{
 					/* Match, so short-circuit the data storage loop below */
 					data_todo = 0;
@@ -1384,7 +1445,7 @@ toast_save_datum(Relation rel, Datum value,
 			{
 				toast_pointer.va_valueid =
 					GetNewOidWithIndex(toastrel,
-									   RelationGetRelid(toastidx),
+									   RelationGetRelid(validtoastidx),
 									   (AttrNumber) 1);
 			} while (toastid_valueid_exists(rel->rd_toastoid,
 											toast_pointer.va_valueid));
@@ -1423,16 +1484,18 @@ toast_save_datum(Relation rel, Datum value,
 		/*
 		 * Create the index entry.	We cheat a little here by not using
 		 * FormIndexDatum: this relies on the knowledge that the index columns
-		 * are the same as the initial columns of the table.
+		 * are the same as the initial columns of the table for all the
+		 * indexes.
 		 *
 		 * Note also that there had better not be any user-created index on
 		 * the TOAST table, since we don't bother to update anything else.
 		 */
-		index_insert(toastidx, t_values, t_isnull,
-					 &(toasttup->t_self),
-					 toastrel,
-					 toastidx->rd_index->indisunique ?
-					 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
+		for (i = 0; i < num_indexes; i++)
+			index_insert(toastidxs[i], t_values, t_isnull,
+						 &(toasttup->t_self),
+						 toastrel,
+						 toastidxs[i]->rd_index->indisunique ?
+						 UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
 
 		/*
 		 * Free memory
@@ -1447,10 +1510,13 @@ toast_save_datum(Relation rel, Datum value,
 	}
 
 	/*
-	 * Done - close toast relation
+	 * Done - close toast relations
 	 */
-	index_close(toastidx, RowExclusiveLock);
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], RowExclusiveLock);
+	list_free(indexlist);
 	heap_close(toastrel, RowExclusiveLock);
+	pfree(toastidxs);
 
 	/*
 	 * Create the TOAST pointer value that we'll return
@@ -1474,11 +1540,15 @@ toast_delete_datum(Relation rel, Datum value)
 {
 	struct varlena *attr = (struct varlena *) DatumGetPointer(value);
 	struct varatt_external toast_pointer;
-	Relation	toastrel;
-	Relation	toastidx;
+	Relation	toastrel, validtoastidx;
+	Relation   *toastidxs;
 	ScanKeyData toastkey;
 	SysScanDesc toastscan;
 	HeapTuple	toasttup;
+	ListCell   *lc;
+	List	   *indexlist;
+	int			num_indexes;
+	int			i = 0;
 
 	if (!VARATT_IS_EXTERNAL(attr))
 		return;
@@ -1487,10 +1557,22 @@ toast_delete_datum(Relation rel, Datum value)
 	VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
 
 	/*
-	 * Open the toast relation and its index
+	 * Open the toast relation and its indexes
 	 */
 	toastrel = heap_open(toast_pointer.va_toastrelid, RowExclusiveLock);
-	toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+
+	/*
+	 * We actually use only the first valid index but taking a lock on all is
+	 * necessary.
+	 */
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), RowExclusiveLock);
+
+	/* Fetch relation used for process */
+	validtoastidx = toast_index_fetch_valid(toastidxs, num_indexes);
 
 	/*
 	 * Setup a scan key to find chunks with matching va_valueid
@@ -1505,7 +1587,7 @@ toast_delete_datum(Relation rel, Datum value)
 	 * sequence or not, but since we've already locked the index we might as
 	 * well use systable_beginscan_ordered.)
 	 */
-	toastscan = systable_beginscan_ordered(toastrel, toastidx,
+	toastscan = systable_beginscan_ordered(toastrel, validtoastidx,
 										   SnapshotToast, 1, &toastkey);
 	while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
@@ -1519,8 +1601,11 @@ toast_delete_datum(Relation rel, Datum value)
 	 * End scan and close relations
 	 */
 	systable_endscan_ordered(toastscan);
-	index_close(toastidx, RowExclusiveLock);
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], RowExclusiveLock);
+	list_free(indexlist);
 	heap_close(toastrel, RowExclusiveLock);
+	pfree(toastidxs);
 }
 
 
@@ -1531,11 +1616,29 @@ toast_delete_datum(Relation rel, Datum value)
  * ----------
  */
 static bool
-toastrel_valueid_exists(Relation toastrel, Oid valueid)
+toastrel_valueid_exists(Relation toastrel, Oid valueid, LOCKMODE lockmode)
 {
 	bool		result = false;
 	ScanKeyData toastkey;
 	SysScanDesc toastscan;
+	int			i = 0;
+	int			num_indexes;
+	Relation   *toastidxs;
+	Relation	validtoastidx;
+	ListCell   *lc;
+	List	   *indexlist;
+
+	/* Ensure that the list of indexes of toast relation is computed */
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+
+	/* Open each index relation necessary */
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), lockmode);
+
+	/* Fetch a valid index relation */
+	validtoastidx = toast_index_fetch_valid(toastidxs, num_indexes);
 
 	/*
 	 * Setup a scan key to find chunks with matching va_valueid
@@ -1548,7 +1651,8 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
 	/*
 	 * Is there any such chunk?
 	 */
-	toastscan = systable_beginscan(toastrel, toastrel->rd_rel->reltoastidxid,
+	toastscan = systable_beginscan(toastrel,
+								   RelationGetRelid(validtoastidx),
 								   true, SnapshotToast, 1, &toastkey);
 
 	if (systable_getnext(toastscan) != NULL)
@@ -1556,6 +1660,12 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
 
 	systable_endscan(toastscan);
 
+	/* Clean up */
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], lockmode);
+	list_free(indexlist);
+	pfree(toastidxs);
+
 	return result;
 }
 
@@ -1573,7 +1683,7 @@ toastid_valueid_exists(Oid toastrelid, Oid valueid)
 
 	toastrel = heap_open(toastrelid, AccessShareLock);
 
-	result = toastrel_valueid_exists(toastrel, valueid);
+	result = toastrel_valueid_exists(toastrel, valueid, AccessShareLock);
 
 	heap_close(toastrel, AccessShareLock);
 
@@ -1591,8 +1701,8 @@ toastid_valueid_exists(Oid toastrelid, Oid valueid)
 static struct varlena *
 toast_fetch_datum(struct varlena * attr)
 {
-	Relation	toastrel;
-	Relation	toastidx;
+	Relation	toastrel, validtoastidx;
+	Relation   *toastidxs;
 	ScanKeyData toastkey;
 	SysScanDesc toastscan;
 	HeapTuple	ttup;
@@ -1607,6 +1717,10 @@ toast_fetch_datum(struct varlena * attr)
 	bool		isnull;
 	char	   *chunkdata;
 	int32		chunksize;
+	ListCell   *lc;
+	List	   *indexlist;
+	int			num_indexes;
+	int			i = 0;
 
 	/* Must copy to access aligned fields */
 	VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
@@ -1622,11 +1736,21 @@ toast_fetch_datum(struct varlena * attr)
 		SET_VARSIZE(result, ressize + VARHDRSZ);
 
 	/*
-	 * Open the toast relation and its index
+	 * Open the toast relation and its indexes
 	 */
 	toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
 	toasttupDesc = toastrel->rd_att;
-	toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+
+	/* Open all the indexes of toast relation with similar lock */
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), AccessShareLock);
+
+	/* Fetch relation used for process */
+	validtoastidx = toast_index_fetch_valid(toastidxs, num_indexes);
 
 	/*
 	 * Setup a scan key to fetch from the index by va_valueid
@@ -1645,7 +1769,7 @@ toast_fetch_datum(struct varlena * attr)
 	 */
 	nextidx = 0;
 
-	toastscan = systable_beginscan_ordered(toastrel, toastidx,
+	toastscan = systable_beginscan_ordered(toastrel, validtoastidx,
 										   SnapshotToast, 1, &toastkey);
 	while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
@@ -1734,8 +1858,11 @@ toast_fetch_datum(struct varlena * attr)
 	 * End scan and close relations
 	 */
 	systable_endscan_ordered(toastscan);
-	index_close(toastidx, AccessShareLock);
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], AccessShareLock);
+	list_free(indexlist);
 	heap_close(toastrel, AccessShareLock);
+	pfree(toastidxs);
 
 	return result;
 }
@@ -1750,8 +1877,8 @@ toast_fetch_datum(struct varlena * attr)
 static struct varlena *
 toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 {
-	Relation	toastrel;
-	Relation	toastidx;
+	Relation	toastrel, validtoastidx;
+	Relation   *toastidxs;
 	ScanKeyData toastkey[3];
 	int			nscankeys;
 	SysScanDesc toastscan;
@@ -1774,6 +1901,10 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	int32		chunksize;
 	int32		chcpystrt;
 	int32		chcpyend;
+	int			num_indexes;
+	int			i = 0;
+	ListCell   *lc;
+	List	   *indexlist;
 
 	Assert(VARATT_IS_EXTERNAL(attr));
 
@@ -1816,11 +1947,18 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	endoffset = (sliceoffset + length - 1) % TOAST_MAX_CHUNK_SIZE;
 
 	/*
-	 * Open the toast relation and its index
+	 * Open the toast relation and its indexes
 	 */
 	toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
 	toasttupDesc = toastrel->rd_att;
-	toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
+	indexlist = RelationGetIndexList(toastrel);
+	num_indexes = list_length(indexlist);
+
+	toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation));
+
+	foreach(lc, indexlist)
+		toastidxs[i++] = index_open(lfirst_oid(lc), AccessShareLock);
+	validtoastidx = toast_index_fetch_valid(toastidxs, num_indexes);
 
 	/*
 	 * Setup a scan key to fetch from the index. This is either two keys or
@@ -1861,7 +1999,7 @@ 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 = systable_beginscan_ordered(toastrel, toastidx,
+	toastscan = systable_beginscan_ordered(toastrel, validtoastidx,
 										 SnapshotToast, nscankeys, toastkey);
 	while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
 	{
@@ -1958,8 +2096,37 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
 	 * End scan and close relations
 	 */
 	systable_endscan_ordered(toastscan);
-	index_close(toastidx, AccessShareLock);
+	for (i = 0; i < num_indexes; i++)
+		index_close(toastidxs[i], AccessShareLock);
+	list_free(indexlist);
 	heap_close(toastrel, AccessShareLock);
+	pfree(toastidxs);
 
 	return result;
 }
+
+/* ----------
+ * toast_index_fetch_valid
+ *
+ *	Get a valid index in list of indexes for a toast relation. Those relations
+ *	need to be already open prior calling this routine.
+ */
+static Relation
+toast_index_fetch_valid(Relation *toastidxs, int num_indexes)
+{
+	int			i;
+	Relation	res = NULL;
+
+	/* Fetch the first valid index in list */
+	for (i = 0; i < num_indexes; i++)
+	{
+		if (toastidxs[i]->rd_index->indisvalid)
+		{
+			res = toastidxs[i];
+			break;
+		}
+	}
+
+	Assert(res);
+	return res;
+}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 45a84e4..e08954e 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -781,7 +781,6 @@ InsertPgClassTuple(Relation pg_class_desc,
 	values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
 	values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
 	values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
-	values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
 	values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
 	values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
 	values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 5f61ecb..e196a0c 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -103,7 +103,7 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
 					bool isvalid);
 static void index_update_stats(Relation rel,
 				   bool hasindex, bool isprimary,
-				   Oid reltoastidxid, double reltuples);
+				   double reltuples);
 static void IndexCheckExclusion(Relation heapRelation,
 					Relation indexRelation,
 					IndexInfo *indexInfo);
@@ -1072,7 +1072,6 @@ index_create(Relation heapRelation,
 		index_update_stats(heapRelation,
 						   true,
 						   isprimary,
-						   InvalidOid,
 						   -1.0);
 		/* Make the above update visible */
 		CommandCounterIncrement();
@@ -1254,7 +1253,6 @@ index_constraint_create(Relation heapRelation,
 		index_update_stats(heapRelation,
 						   true,
 						   true,
-						   InvalidOid,
 						   -1.0);
 
 	/*
@@ -1764,8 +1762,6 @@ FormIndexDatum(IndexInfo *indexInfo,
  *
  * hasindex: set relhasindex to this value
  * isprimary: if true, set relhaspkey true; else no change
- * reltoastidxid: if not InvalidOid, set reltoastidxid to this value;
- *		else no change
  * reltuples: if >= 0, set reltuples to this value; else no change
  *
  * If reltuples >= 0, relpages and relallvisible are also updated (using
@@ -1781,8 +1777,9 @@ FormIndexDatum(IndexInfo *indexInfo,
  */
 static void
 index_update_stats(Relation rel,
-				   bool hasindex, bool isprimary,
-				   Oid reltoastidxid, double reltuples)
+				   bool hasindex,
+				   bool isprimary,
+				   double reltuples)
 {
 	Oid			relid = RelationGetRelid(rel);
 	Relation	pg_class;
@@ -1876,15 +1873,6 @@ index_update_stats(Relation rel,
 			dirty = true;
 		}
 	}
-	if (OidIsValid(reltoastidxid))
-	{
-		Assert(rd_rel->relkind == RELKIND_TOASTVALUE);
-		if (rd_rel->reltoastidxid != reltoastidxid)
-		{
-			rd_rel->reltoastidxid = reltoastidxid;
-			dirty = true;
-		}
-	}
 
 	if (reltuples >= 0)
 	{
@@ -2072,14 +2060,11 @@ index_build(Relation heapRelation,
 	index_update_stats(heapRelation,
 					   true,
 					   isprimary,
-					   (heapRelation->rd_rel->relkind == RELKIND_TOASTVALUE) ?
-					   RelationGetRelid(indexRelation) : InvalidOid,
 					   stats->heap_tuples);
 
 	index_update_stats(indexRelation,
 					   false,
 					   false,
-					   InvalidOid,
 					   stats->index_tuples);
 
 	/* Make the updated catalog row versions visible */
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 81d7c4f..3c2a474 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -473,16 +473,16 @@ CREATE VIEW pg_statio_all_tables AS
             pg_stat_get_blocks_fetched(T.oid) -
                     pg_stat_get_blocks_hit(T.oid) AS toast_blks_read,
             pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit,
-            pg_stat_get_blocks_fetched(X.oid) -
-                    pg_stat_get_blocks_hit(X.oid) AS tidx_blks_read,
-            pg_stat_get_blocks_hit(X.oid) AS tidx_blks_hit
+            sum(pg_stat_get_blocks_fetched(X.indexrelid) -
+                    pg_stat_get_blocks_hit(X.indexrelid))::bigint AS tidx_blks_read,
+            sum(pg_stat_get_blocks_hit(X.indexrelid))::bigint AS tidx_blks_hit
     FROM pg_class C LEFT JOIN
             pg_index I ON C.oid = I.indrelid LEFT JOIN
             pg_class T ON C.reltoastrelid = T.oid LEFT JOIN
-            pg_class X ON T.reltoastidxid = X.oid
+            pg_index X ON T.oid = X.indrelid
             LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
     WHERE C.relkind IN ('r', 't', 'm')
-    GROUP BY C.oid, N.nspname, C.relname, T.oid, X.oid;
+    GROUP BY C.oid, N.nspname, C.relname, T.oid, X.indexrelid;
 
 CREATE VIEW pg_statio_sys_tables AS
     SELECT * FROM pg_statio_all_tables
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 095d5e4..e4747a9 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -21,6 +21,7 @@
 #include "access/relscan.h"
 #include "access/rewriteheap.h"
 #include "access/transam.h"
+#include "access/tuptoaster.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
@@ -1172,8 +1173,6 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			swaptemp = relform1->reltoastrelid;
 			relform1->reltoastrelid = relform2->reltoastrelid;
 			relform2->reltoastrelid = swaptemp;
-
-			/* we should NOT swap reltoastidxid */
 		}
 	}
 	else
@@ -1393,18 +1392,31 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 
 	/*
 	 * If we're swapping two toast tables by content, do the same for their
-	 * indexes.
+	 * valid index. The swap can actually be safely done only if the relations
+	 * have indexes.
 	 */
 	if (swap_toast_by_content &&
-		relform1->reltoastidxid && relform2->reltoastidxid)
-		swap_relation_files(relform1->reltoastidxid,
-							relform2->reltoastidxid,
-							target_is_pg_class,
-							swap_toast_by_content,
-							is_internal,
-							InvalidTransactionId,
-							InvalidMultiXactId,
-							mapped_tables);
+		relform1->reltoastrelid &&
+		relform2->reltoastrelid)
+	{
+		Oid			toastIndex1, toastIndex2;
+
+		/* Get valid index for each relation */
+		toastIndex1 = toast_get_valid_index(relform1->reltoastrelid,
+											AccessExclusiveLock);
+		toastIndex2 = toast_get_valid_index(relform2->reltoastrelid,
+											AccessExclusiveLock);
+
+		if (toastIndex1 && toastIndex2)
+			swap_relation_files(toastIndex1,
+								toastIndex2,
+								target_is_pg_class,
+								swap_toast_by_content,
+								is_internal,
+								InvalidTransactionId,
+								InvalidMultiXactId,
+								mapped_tables);
+	}
 
 	/* Clean up. */
 	heap_freetuple(reltup1);
@@ -1528,14 +1540,12 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 		newrel = heap_open(OIDOldHeap, NoLock);
 		if (OidIsValid(newrel->rd_rel->reltoastrelid))
 		{
-			Relation	toastrel;
 			Oid			toastidx;
 			char		NewToastName[NAMEDATALEN];
 
-			toastrel = relation_open(newrel->rd_rel->reltoastrelid,
-									 AccessShareLock);
-			toastidx = toastrel->rd_rel->reltoastidxid;
-			relation_close(toastrel, AccessShareLock);
+			/* Get the associated valid index to be renamed */
+			toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
+											 AccessShareLock);
 
 			/* rename the toast table ... */
 			snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
@@ -1543,9 +1553,10 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 			RenameRelationInternal(newrel->rd_rel->reltoastrelid,
 								   NewToastName, true);
 
-			/* ... and its index too */
+			/* ... and its valid index too. */
 			snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
 					 OIDOldHeap);
+
 			RenameRelationInternal(toastidx,
 								   NewToastName, true);
 		}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 8294b29..2b777da 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8728,7 +8728,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	Relation	rel;
 	Oid			oldTableSpace;
 	Oid			reltoastrelid;
-	Oid			reltoastidxid;
 	Oid			newrelfilenode;
 	RelFileNode newrnode;
 	SMgrRelation dstrel;
@@ -8736,6 +8735,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	HeapTuple	tuple;
 	Form_pg_class rd_rel;
 	ForkNumber	forkNum;
+	List	   *reltoastidxids = NIL;
+	ListCell   *lc;
 
 	/*
 	 * Need lock here in case we are recursing to toast table or index
@@ -8782,7 +8783,13 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 				 errmsg("cannot move temporary tables of other sessions")));
 
 	reltoastrelid = rel->rd_rel->reltoastrelid;
-	reltoastidxid = rel->rd_rel->reltoastidxid;
+	/* Fetch the list of indexes on toast relation if necessary */
+	if (OidIsValid(reltoastrelid))
+	{
+		Relation toastRel = relation_open(reltoastrelid, lockmode);
+		reltoastidxids = RelationGetIndexList(toastRel);
+		relation_close(toastRel, lockmode);
+	}
 
 	/* Get a modifiable copy of the relation's pg_class row */
 	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
@@ -8863,8 +8870,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	/* Move associated toast relation and/or index, too */
 	if (OidIsValid(reltoastrelid))
 		ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
-	if (OidIsValid(reltoastidxid))
-		ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode);
+	foreach(lc, reltoastidxids)
+	{
+		Oid toastidxid = lfirst_oid(lc);
+		if (OidIsValid(toastidxid))
+			ATExecSetTableSpace(toastidxid, newTableSpace, lockmode);
+	}
+
+	/* Clean up */
+	list_free(reltoastidxids);
 }
 
 /*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index fb57621..f721dbb 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -575,8 +575,8 @@ DefineQueryRewrite(char *rulename,
 
 		/*
 		 * Fix pg_class entry to look like a normal view's, including setting
-		 * the correct relkind and removal of reltoastrelid/reltoastidxid of
-		 * the toast table we potentially removed above.
+		 * the correct relkind and removal of reltoastrelid of the toast table
+		 * we potentially removed above.
 		 */
 		classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
 		if (!HeapTupleIsValid(classTup))
@@ -588,7 +588,6 @@ DefineQueryRewrite(char *rulename,
 		classForm->reltuples = 0;
 		classForm->relallvisible = 0;
 		classForm->reltoastrelid = InvalidOid;
-		classForm->reltoastidxid = InvalidOid;
 		classForm->relhasindex = false;
 		classForm->relkind = RELKIND_VIEW;
 		classForm->relhasoids = false;
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 4c4e1ed..bdef79b 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -332,7 +332,7 @@ pg_relation_size(PG_FUNCTION_ARGS)
 }
 
 /*
- * Calculate total on-disk size of a TOAST relation, including its index.
+ * Calculate total on-disk size of a TOAST relation, including its indexes.
  * Must not be applied to non-TOAST relations.
  */
 static int64
@@ -340,8 +340,9 @@ calculate_toast_table_size(Oid toastrelid)
 {
 	int64		size = 0;
 	Relation	toastRel;
-	Relation	toastIdxRel;
 	ForkNumber	forkNum;
+	ListCell   *lc;
+	List	   *indexlist;
 
 	toastRel = relation_open(toastrelid, AccessShareLock);
 
@@ -351,12 +352,21 @@ calculate_toast_table_size(Oid toastrelid)
 										toastRel->rd_backend, forkNum);
 
 	/* toast index size, including FSM and VM size */
-	toastIdxRel = relation_open(toastRel->rd_rel->reltoastidxid, AccessShareLock);
-	for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
-		size += calculate_relation_size(&(toastIdxRel->rd_node),
-										toastIdxRel->rd_backend, forkNum);
+	indexlist = RelationGetIndexList(toastRel);
 
-	relation_close(toastIdxRel, AccessShareLock);
+	/* Size is calculated using all the indexes available */
+	foreach(lc, indexlist)
+	{
+		Relation	toastIdxRel;
+		toastIdxRel = relation_open(lfirst_oid(lc),
+									AccessShareLock);
+		for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
+			size += calculate_relation_size(&(toastIdxRel->rd_node),
+											toastIdxRel->rd_backend, forkNum);
+
+		relation_close(toastIdxRel, AccessShareLock);
+	}
+	list_free(indexlist);
 	relation_close(toastRel, AccessShareLock);
 
 	return size;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ec956ad..ccd5663 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2781,16 +2781,16 @@ binary_upgrade_set_pg_class_oids(Archive *fout,
 	Oid			pg_class_reltoastidxid;
 
 	appendPQExpBuffer(upgrade_query,
-					  "SELECT c.reltoastrelid, t.reltoastidxid "
+					  "SELECT c.reltoastrelid, t.indexrelid "
 					  "FROM pg_catalog.pg_class c LEFT JOIN "
-					  "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
-					  "WHERE c.oid = '%u'::pg_catalog.oid;",
+					  "pg_catalog.pg_index t ON (c.reltoastrelid = t.indrelid) "
+					  "WHERE c.oid = '%u'::pg_catalog.oid AND t.indisvalid;",
 					  pg_class_oid);
 
 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
 
 	pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
-	pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
+	pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
 
 	appendPQExpBuffer(upgrade_buffer,
 				   "\n-- For binary upgrade, must preserve pg_class oids\n");
@@ -2816,7 +2816,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout,
 							  "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
 							  pg_class_reltoastrelid);
 
-			/* every toast table has an index */
+			/* every toast table has one valid index */
 			appendPQExpBuffer(upgrade_buffer,
 							  "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
 							  pg_class_reltoastidxid);
diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h
index 6f4fc45..5890290 100644
--- a/src/include/access/tuptoaster.h
+++ b/src/include/access/tuptoaster.h
@@ -15,6 +15,7 @@
 
 #include "access/htup_details.h"
 #include "utils/relcache.h"
+#include "storage/lock.h"
 
 /*
  * This enables de-toasting of index entries.  Needed until VACUUM is
@@ -188,4 +189,12 @@ extern Size toast_raw_datum_size(Datum value);
  */
 extern Size toast_datum_size(Datum value);
 
+/* ----------
+ * toast_get_valid_index -
+ *
+ *	Return valid index associated to a toast relation
+ * ----------
+ */
+extern Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock);
+
 #endif   /* TUPTOASTER_H */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 2225787..49c4f6f 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -48,7 +48,6 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO
 	int32		relallvisible;	/* # of all-visible blocks (not always
 								 * up-to-date) */
 	Oid			reltoastrelid;	/* OID of toast table; 0 if none */
-	Oid			reltoastidxid;	/* if toast table, OID of chunk_id index */
 	bool		relhasindex;	/* T if has (or has had) any indexes */
 	bool		relisshared;	/* T if shared across databases */
 	char		relpersistence; /* see RELPERSISTENCE_xxx constants below */
@@ -94,7 +93,7 @@ typedef FormData_pg_class *Form_pg_class;
  * ----------------
  */
 
-#define Natts_pg_class					29
+#define Natts_pg_class					28
 #define Anum_pg_class_relname			1
 #define Anum_pg_class_relnamespace		2
 #define Anum_pg_class_reltype			3
@@ -107,23 +106,22 @@ typedef FormData_pg_class *Form_pg_class;
 #define Anum_pg_class_reltuples			10
 #define Anum_pg_class_relallvisible		11
 #define Anum_pg_class_reltoastrelid		12
-#define Anum_pg_class_reltoastidxid		13
-#define Anum_pg_class_relhasindex		14
-#define Anum_pg_class_relisshared		15
-#define Anum_pg_class_relpersistence	16
-#define Anum_pg_class_relkind			17
-#define Anum_pg_class_relnatts			18
-#define Anum_pg_class_relchecks			19
-#define Anum_pg_class_relhasoids		20
-#define Anum_pg_class_relhaspkey		21
-#define Anum_pg_class_relhasrules		22
-#define Anum_pg_class_relhastriggers	23
-#define Anum_pg_class_relhassubclass	24
-#define Anum_pg_class_relispopulated	25
-#define Anum_pg_class_relfrozenxid		26
-#define Anum_pg_class_relminmxid		27
-#define Anum_pg_class_relacl			28
-#define Anum_pg_class_reloptions		29
+#define Anum_pg_class_relhasindex		13
+#define Anum_pg_class_relisshared		14
+#define Anum_pg_class_relpersistence	15
+#define Anum_pg_class_relkind			16
+#define Anum_pg_class_relnatts			17
+#define Anum_pg_class_relchecks			18
+#define Anum_pg_class_relhasoids		19
+#define Anum_pg_class_relhaspkey		20
+#define Anum_pg_class_relhasrules		21
+#define Anum_pg_class_relhastriggers	22
+#define Anum_pg_class_relhassubclass	23
+#define Anum_pg_class_relispopulated	24
+#define Anum_pg_class_relfrozenxid		25
+#define Anum_pg_class_relminmxid		26
+#define Anum_pg_class_relacl			27
+#define Anum_pg_class_reloptions		28
 
 /* ----------------
  *		initial contents of pg_class
@@ -138,13 +136,13 @@ typedef FormData_pg_class *Form_pg_class;
  * Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId;
  * similarly, "1" in relminmxid stands for FirstMultiXactId
  */
-DATA(insert OID = 1247 (  pg_type		PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f t 3 1 _null_ _null_ ));
+DATA(insert OID = 1247 (  pg_type		PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f t 3 1 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f t 3 1 _null_ _null_ ));
+DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f t 3 1 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1255 (  pg_proc		PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 27 0 t f f f f t 3 1 _null_ _null_ ));
+DATA(insert OID = 1255 (  pg_proc		PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 27 0 t f f f f t 3 1 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1259 (  pg_class		PGNSP 83 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f t 3 1 _null_ _null_ ));
+DATA(insert OID = 1259 (  pg_class		PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 28 0 t f f f f t 3 1 _null_ _null_ ));
 DESCR("");
 
 
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index 06ed856..6c5cb5a 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -353,14 +353,6 @@ WHERE	reltoastrelid != 0 AND
 ------+---------------
 (0 rows)
 
-SELECT	ctid, reltoastidxid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastidxid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastidxid);
- ctid | reltoastidxid 
-------+---------------
-(0 rows)
-
 SELECT	ctid, collnamespace
 FROM	pg_catalog.pg_collation fk
 WHERE	collnamespace != 0 AND
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 57ae842..a6444a0 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1852,15 +1852,15 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
                                  |     (sum(pg_stat_get_blocks_hit(i.indexrelid)))::bigint AS idx_blks_hit,                                                                                                                                       +
                                  |     (pg_stat_get_blocks_fetched(t.oid) - pg_stat_get_blocks_hit(t.oid)) AS toast_blks_read,                                                                                                                    +
                                  |     pg_stat_get_blocks_hit(t.oid) AS toast_blks_hit,                                                                                                                                                           +
-                                 |     (pg_stat_get_blocks_fetched(x.oid) - pg_stat_get_blocks_hit(x.oid)) AS tidx_blks_read,                                                                                                                     +
-                                 |     pg_stat_get_blocks_hit(x.oid) AS tidx_blks_hit                                                                                                                                                             +
+                                 |     (sum((pg_stat_get_blocks_fetched(x.indexrelid) - pg_stat_get_blocks_hit(x.indexrelid))))::bigint AS tidx_blks_read,                                                                                        +
+                                 |     (sum(pg_stat_get_blocks_hit(x.indexrelid)))::bigint AS tidx_blks_hit                                                                                                                                       +
                                  |    FROM ((((pg_class c                                                                                                                                                                                         +
                                  |    LEFT JOIN pg_index i ON ((c.oid = i.indrelid)))                                                                                                                                                             +
                                  |    LEFT JOIN pg_class t ON ((c.reltoastrelid = t.oid)))                                                                                                                                                        +
-                                 |    LEFT JOIN pg_class x ON ((t.reltoastidxid = x.oid)))                                                                                                                                                        +
+                                 |    LEFT JOIN pg_index x ON ((t.oid = x.indrelid)))                                                                                                                                                             +
                                  |    LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))                                                                                                                                                     +
                                  |   WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))                                                                                                                                       +
-                                 |   GROUP BY c.oid, n.nspname, c.relname, t.oid, x.oid;
+                                 |   GROUP BY c.oid, n.nspname, c.relname, t.oid, x.indexrelid;
  pg_statio_sys_indexes           |  SELECT pg_statio_all_indexes.relid,                                                                                                                                                                           +
                                  |     pg_statio_all_indexes.indexrelid,                                                                                                                                                                          +
                                  |     pg_statio_all_indexes.schemaname,                                                                                                                                                                          +
@@ -2347,11 +2347,11 @@ select xmin, * from fooview;  -- fail, views don't have such a column
 ERROR:  column "xmin" does not exist
 LINE 1: select xmin, * from fooview;
                ^
-select reltoastrelid, reltoastidxid, relkind, relfrozenxid
+select reltoastrelid, relkind, relfrozenxid
   from pg_class where oid = 'fooview'::regclass;
- reltoastrelid | reltoastidxid | relkind | relfrozenxid 
----------------+---------------+---------+--------------
-             0 |             0 | v       |            0
+ reltoastrelid | relkind | relfrozenxid 
+---------------+---------+--------------
+             0 | v       |            0
 (1 row)
 
 drop view fooview;
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index 6422da2..9b91683 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -177,10 +177,6 @@ SELECT	ctid, reltoastrelid
 FROM	pg_catalog.pg_class fk
 WHERE	reltoastrelid != 0 AND
 	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
-SELECT	ctid, reltoastidxid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastidxid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastidxid);
 SELECT	ctid, collnamespace
 FROM	pg_catalog.pg_collation fk
 WHERE	collnamespace != 0 AND
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index d5a3571..6361297 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -872,7 +872,7 @@ create rule "_RETURN" as on select to fooview do instead
 select * from fooview;
 select xmin, * from fooview;  -- fail, views don't have such a column
 
-select reltoastrelid, reltoastidxid, relkind, relfrozenxid
+select reltoastrelid, relkind, relfrozenxid
   from pg_class where oid = 'fooview'::regclass;
 
 drop view fooview;
diff --git a/src/tools/findoidjoins/README b/src/tools/findoidjoins/README
index b5c4d1b..e3e8a2a 100644
--- a/src/tools/findoidjoins/README
+++ b/src/tools/findoidjoins/README
@@ -86,7 +86,6 @@ Join pg_catalog.pg_class.relowner => pg_catalog.pg_authid.oid
 Join pg_catalog.pg_class.relam => pg_catalog.pg_am.oid
 Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.oid
 Join pg_catalog.pg_class.reltoastrelid => pg_catalog.pg_class.oid
-Join pg_catalog.pg_class.reltoastidxid => pg_catalog.pg_class.oid
 Join pg_catalog.pg_collation.collnamespace => pg_catalog.pg_namespace.oid
 Join pg_catalog.pg_collation.collowner => pg_catalog.pg_authid.oid
 Join pg_catalog.pg_constraint.connamespace => pg_catalog.pg_namespace.oid