diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c index a5aa40f..6db6851 100644 --- a/contrib/pg_upgrade/info.c +++ b/contrib/pg_upgrade/info.c @@ -313,9 +313,13 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo) " ON i.reloid = c.oid")); 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 info_rels i " + " JOIN pg_catalog.pg_class c " + " ON i.reloid = c.oid " + " JOIN pg_catalog.pg_index p " + " ON i.reloid = p.indrelid " + "WHERE p.indexrelid >= %u ", FirstNormalObjectId)); 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 81c1be3..e1475e6 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1745,15 +1745,6 @@ - reltoastidxid - oid - pg_class.oid - - For a TOAST table, the OID of its index. 0 if not a TOAST table. - - - - relhasindex bool diff --git a/doc/src/sgml/diskusage.sgml b/doc/src/sgml/diskusage.sgml index de1d0b4..e12d1c1 100644 --- a/doc/src/sgml/diskusage.sgml +++ b/doc/src/sgml/diskusage.sgml @@ -44,7 +44,7 @@ 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 @@ -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/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index fc37ceb..be27211 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -1238,7 +1238,7 @@ toast_save_datum(Relation rel, Datum value, struct varlena * oldexternal, int options) { Relation toastrel; - Relation toastidx; + Relation *toastidxs; HeapTuple toasttup; TupleDesc toasttupDesc; Datum t_values[3]; @@ -1257,15 +1257,26 @@ toast_save_datum(Relation rel, Datum value, char *data_p; int32 data_todo; Pointer dval = DatumGetPointer(value); + ListCell *lc; + int count = 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); + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); + num_indexes = list_length(toastrel->rd_indexlist); + + toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation)); + + foreach(lc, toastrel->rd_indexlist) + toastidxs[count++] = index_open(lfirst_oid(lc), RowExclusiveLock); /* * Get the data pointer and length, and compute va_rawsize and va_extsize. @@ -1327,10 +1338,13 @@ toast_save_datum(Relation rel, Datum value, */ if (!OidIsValid(rel->rd_toastoid)) { - /* normal case: just choose an unused OID */ + /* + * normal case: just choose an unused OID. Simply use the first + * index relation. + */ toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, - RelationGetRelid(toastidx), + RelationGetRelid(toastidxs[0]), (AttrNumber) 1); } else @@ -1384,7 +1398,7 @@ toast_save_datum(Relation rel, Datum value, { toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, - RelationGetRelid(toastidx), + RelationGetRelid(toastidxs[0]), (AttrNumber) 1); } while (toastid_valueid_exists(rel->rd_toastoid, toast_pointer.va_valueid)); @@ -1423,16 +1437,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 (count = 0; count < num_indexes; count++) + index_insert(toastidxs[count], t_values, t_isnull, + &(toasttup->t_self), + toastrel, + toastidxs[count]->rd_index->indisunique ? + UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); /* * Free memory @@ -1449,8 +1465,10 @@ toast_save_datum(Relation rel, Datum value, /* * Done - close toast relation */ - index_close(toastidx, RowExclusiveLock); + for (count = 0; count < num_indexes; count++) + index_close(toastidxs[count], RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); + pfree(toastidxs); /* * Create the TOAST pointer value that we'll return @@ -1475,10 +1493,13 @@ toast_delete_datum(Relation rel, Datum value) struct varlena *attr = (struct varlena *) DatumGetPointer(value); struct varatt_external toast_pointer; Relation toastrel; - Relation toastidx; + Relation *toastidxs; ScanKeyData toastkey; SysScanDesc toastscan; HeapTuple toasttup; + ListCell *lc; + int num_indexes; + int count = 0; if (!VARATT_IS_EXTERNAL(attr)) return; @@ -1487,10 +1508,20 @@ 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); + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); + num_indexes = list_length(toastrel->rd_indexlist); + toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation)); + + /* + * We actually use only the first index but taking a lock on all is + * necessary. + */ + foreach(lc, toastrel->rd_indexlist) + toastidxs[count++] = index_open(lfirst_oid(lc), RowExclusiveLock); /* * Setup a scan key to find chunks with matching va_valueid @@ -1505,7 +1536,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, toastidxs[0], SnapshotToast, 1, &toastkey); while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -1519,8 +1550,10 @@ toast_delete_datum(Relation rel, Datum value) * End scan and close relations */ systable_endscan_ordered(toastscan); - index_close(toastidx, RowExclusiveLock); + for (count = 0; count < num_indexes; count++) + index_close(toastidxs[count], RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); + pfree(toastidxs); } @@ -1537,6 +1570,10 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) ScanKeyData toastkey; SysScanDesc toastscan; + /* Ensure that the list of indexes of toast relation is computed */ + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); + /* * Setup a scan key to find chunks with matching va_valueid */ @@ -1546,9 +1583,10 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) ObjectIdGetDatum(valueid)); /* - * Is there any such chunk? + * Is there any such chunk? Use the first index available for scan */ - toastscan = systable_beginscan(toastrel, toastrel->rd_rel->reltoastidxid, + toastscan = systable_beginscan(toastrel, + linitial_oid(toastrel->rd_indexlist), true, SnapshotToast, 1, &toastkey); if (systable_getnext(toastscan) != NULL) @@ -1592,7 +1630,7 @@ static struct varlena * toast_fetch_datum(struct varlena * attr) { Relation toastrel; - Relation toastidx; + Relation *toastidxs; ScanKeyData toastkey; SysScanDesc toastscan; HeapTuple ttup; @@ -1607,6 +1645,9 @@ toast_fetch_datum(struct varlena * attr) bool isnull; char *chunkdata; int32 chunksize; + ListCell *lc; + int num_indexes; + int count = 0; /* Must copy to access aligned fields */ VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); @@ -1622,11 +1663,18 @@ 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); + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); + num_indexes = list_length(toastrel->rd_indexlist); + + toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation)); + + foreach(lc, toastrel->rd_indexlist) + toastidxs[count++] = index_open(lfirst_oid(lc), AccessShareLock); /* * Setup a scan key to fetch from the index by va_valueid @@ -1645,7 +1693,7 @@ toast_fetch_datum(struct varlena * attr) */ nextidx = 0; - toastscan = systable_beginscan_ordered(toastrel, toastidx, + toastscan = systable_beginscan_ordered(toastrel, toastidxs[0], SnapshotToast, 1, &toastkey); while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -1734,8 +1782,10 @@ toast_fetch_datum(struct varlena * attr) * End scan and close relations */ systable_endscan_ordered(toastscan); - index_close(toastidx, AccessShareLock); + for (count = 0; count < num_indexes; count++) + index_close(toastidxs[count], AccessShareLock); heap_close(toastrel, AccessShareLock); + pfree(toastidxs); return result; } @@ -1751,7 +1801,7 @@ static struct varlena * toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length) { Relation toastrel; - Relation toastidx; + Relation *toastidxs; ScanKeyData toastkey[3]; int nscankeys; SysScanDesc toastscan; @@ -1774,6 +1824,9 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length) int32 chunksize; int32 chcpystrt; int32 chcpyend; + int num_indexes; + int count = 0; + ListCell *lc; Assert(VARATT_IS_EXTERNAL(attr)); @@ -1816,11 +1869,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); + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); + num_indexes = list_length(toastrel->rd_indexlist); + + toastidxs = (Relation *) palloc(num_indexes * sizeof(Relation)); + + foreach(lc, toastrel->rd_indexlist) + toastidxs[count++] = index_open(lfirst_oid(lc), AccessShareLock); /* * Setup a scan key to fetch from the index. This is either two keys or @@ -1861,7 +1921,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, toastidxs[0], SnapshotToast, nscankeys, toastkey); while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -1958,8 +2018,10 @@ 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 (count = 0; count < num_indexes; count++) + index_close(toastidxs[count], AccessShareLock); heap_close(toastrel, AccessShareLock); + pfree(toastidxs); return result; } diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 0ecfc78..043b279 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -767,7 +767,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 9b33929..0f3b45f 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); @@ -1077,7 +1077,6 @@ index_create(Relation heapRelation, index_update_stats(heapRelation, true, isprimary, - InvalidOid, -1.0); /* Make the above update visible */ CommandCounterIncrement(); @@ -1256,7 +1255,6 @@ index_constraint_create(Relation heapRelation, index_update_stats(heapRelation, true, true, - InvalidOid, -1.0); /* @@ -1763,8 +1761,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 @@ -1780,8 +1776,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; @@ -1875,15 +1872,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) { @@ -2071,14 +2059,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 f727acd..01d58d9 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 + pg_stat_get_blocks_fetched(X.indrelid) - + pg_stat_get_blocks_hit(X.indrelid) AS tidx_blks_read, + pg_stat_get_blocks_hit(X.indrelid) 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.indrelid; 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 8ab8c17..c5f6a0a 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1169,8 +1169,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 @@ -1379,18 +1377,53 @@ 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. + * If we're swapping two toast tables by content, do the same for all of + * their indexes. The swap can actually be safely done only if all the indexes + * have valid Oids. */ if (swap_toast_by_content && - relform1->reltoastidxid && relform2->reltoastidxid) - swap_relation_files(relform1->reltoastidxid, - relform2->reltoastidxid, - target_is_pg_class, - swap_toast_by_content, - InvalidTransactionId, - InvalidMultiXactId, - mapped_tables); + relform1->reltoastrelid && + relform2->reltoastrelid) + { + Relation toastRel1, toastRel2; + + /* Open relations */ + toastRel1 = heap_open(relform1->reltoastrelid, RowExclusiveLock); + toastRel2 = heap_open(relform2->reltoastrelid, RowExclusiveLock); + + /* Obtain index list if necessary */ + if (toastRel1->rd_indexvalid == 0) + RelationGetIndexList(toastRel1); + if (toastRel2->rd_indexvalid == 0) + RelationGetIndexList(toastRel2); + + /* Check if the swap is possible for all the toast indexes */ + if (!list_member_oid(toastRel1->rd_indexlist, InvalidOid) && + !list_member_oid(toastRel2->rd_indexlist, InvalidOid) && + list_length(toastRel1->rd_indexlist) == list_length(toastRel2->rd_indexlist)) + { + ListCell *lc1, *lc2; + + /* Now swap each couple */ + lc2 = list_head(toastRel2->rd_indexlist); + foreach(lc1, toastRel1->rd_indexlist) + { + Oid indexOid1 = lfirst_oid(lc1); + Oid indexOid2 = lfirst_oid(lc2); + swap_relation_files(indexOid1, + indexOid2, + target_is_pg_class, + swap_toast_by_content, + InvalidTransactionId, + InvalidMultiXactId, + mapped_tables); + lc2 = lnext(lc2); + } + } + + heap_close(toastRel1, RowExclusiveLock); + heap_close(toastRel2, RowExclusiveLock); + } /* Clean up. */ heap_freetuple(reltup1); @@ -1514,12 +1547,14 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, if (OidIsValid(newrel->rd_rel->reltoastrelid)) { Relation toastrel; - Oid toastidx; char NewToastName[NAMEDATALEN]; + ListCell *lc; + int count = 0; toastrel = relation_open(newrel->rd_rel->reltoastrelid, AccessShareLock); - toastidx = toastrel->rd_rel->reltoastidxid; + if (toastrel->rd_indexvalid == 0) + RelationGetIndexList(toastrel); relation_close(toastrel, AccessShareLock); /* rename the toast table ... */ @@ -1528,11 +1563,23 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, RenameRelationInternal(newrel->rd_rel->reltoastrelid, NewToastName); - /* ... and its index too */ - snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index", - OIDOldHeap); - RenameRelationInternal(toastidx, - NewToastName); + /* ... and its indexes too */ + foreach(lc, toastrel->rd_indexlist) + { + /* + * The first index keeps the former toast name and the + * following entries are thought as being concurrent indexes. + */ + if (count == 0) + snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index", + OIDOldHeap); + else + snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index_cct%d", + OIDOldHeap, count); + RenameRelationInternal(lfirst_oid(lc), + NewToastName); + count++; + } } relation_close(newrel, NoLock); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 2a55e02..0d6f5c0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8678,7 +8678,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) Relation rel; Oid oldTableSpace; Oid reltoastrelid; - Oid reltoastidxid; Oid newrelfilenode; RelFileNode newrnode; SMgrRelation dstrel; @@ -8686,6 +8685,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) HeapTuple tuple; Form_pg_class rd_rel; ForkNumber forkNum; + List *reltoastidxids; + ListCell *lc; /* * Need lock here in case we are recursing to toast table or index @@ -8729,7 +8730,8 @@ 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; + RelationGetIndexList(rel); + reltoastidxids = list_copy(rel->rd_indexlist); /* Get a modifiable copy of the relation's pg_class row */ pg_class = heap_open(RelationRelationId, RowExclusiveLock); @@ -8808,8 +8810,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 idxid = lfirst_oid(lc); + if (OidIsValid(idxid)) + ATExecSetTableSpace(idxid, newTableSpace, lockmode); + } + + /* Clean up */ + list_free(reltoastidxids); } /* diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 8963266..3dd2fda 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -577,8 +577,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)) @@ -590,7 +590,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 d589d26..11921ac 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,8 @@ calculate_toast_table_size(Oid toastrelid) { int64 size = 0; Relation toastRel; - Relation toastIdxRel; ForkNumber forkNum; + ListCell *lc; toastRel = relation_open(toastrelid, AccessShareLock); @@ -351,12 +351,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); + if (toastRel->rd_indexvalid == 0) + RelationGetIndexList(toastRel); - relation_close(toastIdxRel, AccessShareLock); + /* Size is evaluated based on the first index available */ + foreach(lc, toastRel->rd_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); + } 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 e6c85ac..f15e6a2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2669,10 +2669,9 @@ binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_query = createPQExpBuffer(); PGresult *upgrade_res; Oid pg_class_reltoastrelid; - Oid pg_class_reltoastidxid; appendPQExpBuffer(upgrade_query, - "SELECT c.reltoastrelid, t.reltoastidxid " + "SELECT c.reltoastrelid " "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;", @@ -2681,7 +2680,6 @@ binary_upgrade_set_pg_class_oids(Archive *fout, 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"))); appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_class oids\n"); @@ -2706,11 +2704,6 @@ binary_upgrade_set_pg_class_oids(Archive *fout, appendPQExpBuffer(upgrade_buffer, "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n", pg_class_reltoastrelid); - - /* every toast table has an index */ - appendPQExpBuffer(upgrade_buffer, - "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n", - pg_class_reltoastidxid); } } else diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index ab91ab0..7d137b4 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201302181 +#define CATALOG_VERSION_NO 20130219 #endif diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index fd97141..ea46e38 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 */ @@ -93,7 +92,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -#define Natts_pg_class 28 +#define Natts_pg_class 27 #define Anum_pg_class_relname 1 #define Anum_pg_class_relnamespace 2 #define Anum_pg_class_reltype 3 @@ -106,22 +105,21 @@ 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_relfrozenxid 25 -#define Anum_pg_class_relminmxid 26 -#define Anum_pg_class_relacl 27 -#define Anum_pg_class_reloptions 28 +#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_relfrozenxid 24 +#define Anum_pg_class_relminmxid 25 +#define Anum_pg_class_relacl 26 +#define Anum_pg_class_reloptions 27 /* ---------------- * initial contents of pg_class @@ -136,13 +134,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 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 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 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 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 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 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 28 0 t f f f f 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 27 0 t f f f f 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 a4ecfd2..7a68fb9 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 + + | (pg_stat_get_blocks_fetched(x.indrelid) - pg_stat_get_blocks_hit(x.indrelid)) AS tidx_blks_read, + + | pg_stat_get_blocks_hit(x.indrelid) 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.indrelid; 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 4f49a0d..2d24961 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