diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c index 1905c43..f74b36b 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 9144eec..e7ad6b1 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 49f1553..1ba34c3 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -1236,7 +1236,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]; @@ -1255,15 +1255,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. @@ -1325,10 +1336,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 @@ -1382,7 +1396,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)); @@ -1421,16 +1435,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 @@ -1447,8 +1463,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 @@ -1473,10 +1491,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; @@ -1485,10 +1506,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 @@ -1503,7 +1534,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) { @@ -1517,8 +1548,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); } @@ -1535,6 +1568,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 */ @@ -1544,9 +1581,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) @@ -1590,7 +1628,7 @@ static struct varlena * toast_fetch_datum(struct varlena * attr) { Relation toastrel; - Relation toastidx; + Relation *toastidxs; ScanKeyData toastkey; SysScanDesc toastscan; HeapTuple ttup; @@ -1605,6 +1643,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); @@ -1620,11 +1661,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 @@ -1643,7 +1691,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) { @@ -1732,8 +1780,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; } @@ -1749,7 +1799,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; @@ -1772,6 +1822,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)); @@ -1814,11 +1867,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 @@ -1859,7 +1919,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) { @@ -1956,8 +2016,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 db51e0b..ba0437a 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 c479c23..2154907 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -459,16 +459,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') - 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 c0cb2f6..9fb12e4 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1151,8 +1151,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 @@ -1361,18 +1359,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); @@ -1496,12 +1529,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 ... */ @@ -1510,11 +1545,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 eeddd9a..eefadb2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8645,7 +8645,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) Relation rel; Oid oldTableSpace; Oid reltoastrelid; - Oid reltoastidxid; Oid newrelfilenode; RelFileNode newrnode; SMgrRelation dstrel; @@ -8653,6 +8652,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 @@ -8696,7 +8697,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); @@ -8775,8 +8777,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/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 89ad386..0e11ba9 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -331,7 +331,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 @@ -339,8 +339,8 @@ calculate_toast_table_size(Oid toastrelid) { int64 size = 0; Relation toastRel; - Relation toastIdxRel; ForkNumber forkNum; + ListCell *lc; toastRel = relation_open(toastrelid, AccessShareLock); @@ -350,12 +350,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 43d571c..3480e16 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2503,10 +2503,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;", @@ -2515,7 +2514,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"); @@ -2540,11 +2538,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 820552f..363c0b6 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 869ca8c..470698a 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1840,15 +1840,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"])) + - | 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, + 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/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