diff options
author | Fujii Masao <fujii@postgresql.org> | 2013-07-04 03:24:09 +0900 |
---|---|---|
committer | Fujii Masao <fujii@postgresql.org> | 2013-07-04 03:24:09 +0900 |
commit | 2ef085d0e6960f5087c97266a7211d37ddaa9f68 (patch) | |
tree | 7edac95cbc3bbe0aea721e95e8d4804486a7d0ea /src | |
parent | f71939cd1ac765ba618115f40de4d9c47955a9ef (diff) | |
download | postgresql-2ef085d0e6960f5087c97266a7211d37ddaa9f68.tar.gz postgresql-2ef085d0e6960f5087c97266a7211d37ddaa9f68.zip |
Get rid of pg_class.reltoastidxid.
Treat TOAST index just the same as normal one and get the OID
of TOAST index from pg_index but not pg_class.reltoastidxid.
This change allows us to handle multiple TOAST indexes, and
which is required infrastructure for upcoming
REINDEX CONCURRENTLY feature.
Patch by Michael Paquier, reviewed by Andres Freund and me.
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 225 | ||||
-rw-r--r-- | src/backend/catalog/heap.c | 1 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 23 | ||||
-rw-r--r-- | src/backend/catalog/system_views.sql | 10 | ||||
-rw-r--r-- | src/backend/commands/cluster.c | 34 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 20 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 5 | ||||
-rw-r--r-- | src/backend/utils/adt/dbsize.c | 24 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 14 | ||||
-rw-r--r-- | src/include/access/tuptoaster.h | 9 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_class.h | 44 | ||||
-rw-r--r-- | src/test/regress/expected/oidjoins.out | 8 | ||||
-rw-r--r-- | src/test/regress/expected/rules.out | 16 | ||||
-rw-r--r-- | src/test/regress/sql/oidjoins.sql | 4 | ||||
-rw-r--r-- | src/test/regress/sql/rules.sql | 2 | ||||
-rw-r--r-- | src/tools/findoidjoins/README | 1 |
17 files changed, 307 insertions, 135 deletions
diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 445a7ed9fbc..675bfcc81fe 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -78,6 +78,12 @@ 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 int toast_open_indexes(Relation toastrel, + LOCKMODE lock, + Relation **toastidxs, + int *num_indexes); +static void toast_close_indexes(Relation *toastidxs, int num_indexes, + LOCKMODE lock); /* ---------- @@ -1287,6 +1293,39 @@ toast_compress_datum(Datum value) /* ---------- + * toast_get_valid_index + * + * Get OID of valid index associated to given toast relation. A toast + * relation can have only one valid index at the same time. + */ +Oid +toast_get_valid_index(Oid toastoid, LOCKMODE lock) +{ + int num_indexes; + int validIndex; + Oid validIndexOid; + Relation *toastidxs; + Relation toastrel; + + /* Open the toast relation */ + toastrel = heap_open(toastoid, lock); + + /* Look for the valid index of the toast relation */ + validIndex = toast_open_indexes(toastrel, + lock, + &toastidxs, + &num_indexes); + validIndexOid = RelationGetRelid(toastidxs[validIndex]); + + /* Close the toast relation and all its indexes */ + toast_close_indexes(toastidxs, num_indexes, lock); + heap_close(toastrel, lock); + + return validIndexOid; +} + + +/* ---------- * toast_save_datum - * * Save one single datum into the secondary relation and return @@ -1303,7 +1342,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]; @@ -1322,17 +1361,24 @@ toast_save_datum(Relation rel, Datum value, char *data_p; int32 data_todo; Pointer dval = DatumGetPointer(value); + int num_indexes; + int validIndex; Assert(!VARATT_IS_EXTERNAL(value)); /* - * Open the toast relation and its index. We can use the index to check + * Open the toast relation and its indexes. 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. */ toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock); toasttupDesc = toastrel->rd_att; - toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock); + + /* Open all the toast indexes and look for the valid */ + validIndex = toast_open_indexes(toastrel, + RowExclusiveLock, + &toastidxs, + &num_indexes); /* * Get the data pointer and length, and compute va_rawsize and va_extsize. @@ -1397,7 +1443,7 @@ toast_save_datum(Relation rel, Datum value, /* normal case: just choose an unused OID */ toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, - RelationGetRelid(toastidx), + RelationGetRelid(toastidxs[validIndex]), (AttrNumber) 1); } else @@ -1451,7 +1497,7 @@ toast_save_datum(Relation rel, Datum value, { toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, - RelationGetRelid(toastidx), + RelationGetRelid(toastidxs[validIndex]), (AttrNumber) 1); } while (toastid_valueid_exists(rel->rd_toastoid, toast_pointer.va_valueid)); @@ -1472,6 +1518,8 @@ toast_save_datum(Relation rel, Datum value, */ while (data_todo > 0) { + int i; + /* * Calculate the size of this chunk */ @@ -1490,16 +1538,22 @@ 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++) + { + /* Only index relations marked as ready can updated */ + if (IndexIsReady(toastidxs[i]->rd_index)) + 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 @@ -1514,9 +1568,9 @@ toast_save_datum(Relation rel, Datum value, } /* - * Done - close toast relation + * Done - close toast relation and its indexes */ - index_close(toastidx, RowExclusiveLock); + toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); /* @@ -1542,10 +1596,12 @@ 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; + int num_indexes; + int validIndex; if (!VARATT_IS_EXTERNAL_ONDISK(attr)) return; @@ -1554,10 +1610,15 @@ 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); + + /* Fetch valid relation used for process */ + validIndex = toast_open_indexes(toastrel, + RowExclusiveLock, + &toastidxs, + &num_indexes); /* * Setup a scan key to find chunks with matching va_valueid @@ -1572,7 +1633,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[validIndex], SnapshotToast, 1, &toastkey); while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -1586,7 +1647,7 @@ toast_delete_datum(Relation rel, Datum value) * End scan and close relations */ systable_endscan_ordered(toastscan); - index_close(toastidx, RowExclusiveLock); + toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); } @@ -1603,6 +1664,15 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) bool result = false; ScanKeyData toastkey; SysScanDesc toastscan; + int num_indexes; + int validIndex; + Relation *toastidxs; + + /* Fetch a valid index relation */ + validIndex = toast_open_indexes(toastrel, + RowExclusiveLock, + &toastidxs, + &num_indexes); /* * Setup a scan key to find chunks with matching va_valueid @@ -1615,14 +1685,18 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) /* * Is there any such chunk? */ - toastscan = systable_beginscan(toastrel, toastrel->rd_rel->reltoastidxid, - true, SnapshotToast, 1, &toastkey); + toastscan = systable_beginscan(toastrel, + RelationGetRelid(toastidxs[validIndex]), + true, SnapshotToast, 1, &toastkey); if (systable_getnext(toastscan) != NULL) result = true; systable_endscan(toastscan); + /* Clean up */ + toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); + return result; } @@ -1659,7 +1733,7 @@ static struct varlena * toast_fetch_datum(struct varlena * attr) { Relation toastrel; - Relation toastidx; + Relation *toastidxs; ScanKeyData toastkey; SysScanDesc toastscan; HeapTuple ttup; @@ -1674,6 +1748,8 @@ toast_fetch_datum(struct varlena * attr) bool isnull; char *chunkdata; int32 chunksize; + int num_indexes; + int validIndex; if (VARATT_IS_EXTERNAL_INDIRECT(attr)) elog(ERROR, "shouldn't be called for indirect tuples"); @@ -1692,11 +1768,16 @@ 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); + + /* Look for the valid index of the toast relation */ + validIndex = toast_open_indexes(toastrel, + AccessShareLock, + &toastidxs, + &num_indexes); /* * Setup a scan key to fetch from the index by va_valueid @@ -1715,7 +1796,7 @@ toast_fetch_datum(struct varlena * attr) */ nextidx = 0; - toastscan = systable_beginscan_ordered(toastrel, toastidx, + toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex], SnapshotToast, 1, &toastkey); while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -1804,7 +1885,7 @@ toast_fetch_datum(struct varlena * attr) * End scan and close relations */ systable_endscan_ordered(toastscan); - index_close(toastidx, AccessShareLock); + toast_close_indexes(toastidxs, num_indexes, AccessShareLock); heap_close(toastrel, AccessShareLock); return result; @@ -1821,7 +1902,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; @@ -1844,6 +1925,8 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length) int32 chunksize; int32 chcpystrt; int32 chcpyend; + int num_indexes; + int validIndex; Assert(VARATT_IS_EXTERNAL_ONDISK(attr)); @@ -1886,11 +1969,16 @@ 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); + + /* Look for the valid index of toast relation */ + validIndex = toast_open_indexes(toastrel, + AccessShareLock, + &toastidxs, + &num_indexes); /* * Setup a scan key to fetch from the index. This is either two keys or @@ -1931,7 +2019,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[validIndex], SnapshotToast, nscankeys, toastkey); while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL) { @@ -2028,8 +2116,85 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length) * End scan and close relations */ systable_endscan_ordered(toastscan); - index_close(toastidx, AccessShareLock); + toast_close_indexes(toastidxs, num_indexes, AccessShareLock); heap_close(toastrel, AccessShareLock); return result; } + +/* ---------- + * toast_open_indexes + * + * Get an array of the indexes associated to the given toast relation + * and return as well the position of the valid index used by the toast + * relation in this array. It is the responsibility of the caller of this + * function to close the indexes as well as free them. + */ +static int +toast_open_indexes(Relation toastrel, + LOCKMODE lock, + Relation **toastidxs, + int *num_indexes) +{ + int i = 0; + int res = 0; + bool found = false; + List *indexlist; + ListCell *lc; + + /* Get index list of the toast relation */ + indexlist = RelationGetIndexList(toastrel); + Assert(indexlist != NIL); + + *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 the first valid index in list */ + for (i = 0; i < *num_indexes; i++) + { + Relation toastidx = *toastidxs[i]; + if (toastidx->rd_index->indisvalid) + { + res = i; + found = true; + break; + } + } + + /* + * Free index list, not necessary anymore as relations are opened + * and a valid index has been found. + */ + list_free(indexlist); + + /* + * The toast relation should have one valid index, so something is + * going wrong if there is nothing. + */ + if (!found) + elog(ERROR, "no valid index found for toast relation with Oid %d", + RelationGetRelid(toastrel)); + + return res; +} + +/* ---------- + * toast_close_indexes + * + * Close an array of indexes for a toast relation and free it. This should + * be called for a set of indexes opened previously with toast_open_indexes. + */ +static void +toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock) +{ + int i; + + /* Close relations and clean up things */ + for (i = 0; i < num_indexes; i++) + index_close(toastidxs[i], lock); + pfree(toastidxs); +} diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 4fd42ed1af5..f1cdef9e130 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 ca0c672c381..8525cb9ec83 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 81d7c4fec8c..d3086f43dd6 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.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 f23730c26f7..686770f881e 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" @@ -1177,8 +1178,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 @@ -1398,18 +1397,30 @@ 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, + relform1->relkind == RELKIND_TOASTVALUE && + relform2->relkind == RELKIND_TOASTVALUE) + { + Oid toastIndex1, toastIndex2; + + /* Get valid index for each relation */ + toastIndex1 = toast_get_valid_index(r1, + AccessExclusiveLock); + toastIndex2 = toast_get_valid_index(r2, + AccessExclusiveLock); + + swap_relation_files(toastIndex1, + toastIndex2, target_is_pg_class, swap_toast_by_content, is_internal, InvalidTransactionId, InvalidMultiXactId, mapped_tables); + } /* Clean up. */ heap_freetuple(reltup1); @@ -1533,14 +1544,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", @@ -1548,9 +1557,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 6a7aa44ccc6..6708725d696 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8878,7 +8878,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) Relation rel; Oid oldTableSpace; Oid reltoastrelid; - Oid reltoastidxid; Oid newrelfilenode; RelFileNode newrnode; SMgrRelation dstrel; @@ -8886,6 +8885,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 @@ -8932,7 +8933,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); @@ -9010,11 +9017,14 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) /* Make sure the reltablespace change is visible */ CommandCounterIncrement(); - /* Move associated toast relation and/or index, too */ + /* Move associated toast relation and/or indexes, too */ if (OidIsValid(reltoastrelid)) ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode); - if (OidIsValid(reltoastidxid)) - ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode); + foreach(lc, reltoastidxids) + ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode); + + /* Clean up */ + list_free(reltoastidxids); } /* diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 3157aba330d..92396b39bd3 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -579,8 +579,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)) @@ -592,7 +592,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 5ddeffe4820..34482abee3e 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 9ee9ea2bafa..f40961ffcea 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2778,19 +2778,19 @@ binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_query = createPQExpBuffer(); PGresult *upgrade_res; Oid pg_class_reltoastrelid; - Oid pg_class_reltoastidxid; + Oid pg_index_indexrelid; appendPQExpBuffer(upgrade_query, - "SELECT c.reltoastrelid, t.reltoastidxid " + "SELECT c.reltoastrelid, i.indexrelid " "FROM pg_catalog.pg_class c LEFT JOIN " - "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) " + "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) " "WHERE c.oid = '%u'::pg_catalog.oid;", 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_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid"))); appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_class oids\n"); @@ -2819,7 +2819,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout, /* 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); + pg_index_indexrelid); } } else @@ -13126,7 +13126,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) * attislocal correctly, plus fix up any inherited CHECK constraints. * Analogously, we set up typed tables using ALTER TABLE / OF here. */ - if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION || + if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_FOREIGN_TABLE) ) { for (j = 0; j < tbinfo->numatts; j++) @@ -13151,7 +13151,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) else appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ", fmtId(tbinfo->dobj.name)); - + appendPQExpBuffer(q, "DROP COLUMN %s;\n", fmtId(tbinfo->attnames[j])); } diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h index d0c17fde036..b4e0242c14e 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 @@ -193,4 +194,12 @@ extern Size toast_raw_datum_size(Datum value); */ extern Size toast_datum_size(Datum value); +/* ---------- + * toast_get_valid_index - + * + * Return OID of 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/catversion.h b/src/include/catalog/catversion.h index d46fe9ede37..9358e955475 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201306121 +#define CATALOG_VERSION_NO 201307031 #endif diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 2225787e406..49c4f6f136b 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 06ed85677ae..6c5cb5a8737 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 57ae8427ecd..4b182e7f541 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.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 6422da26ad9..9b91683ea5a 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 d5a35710875..6361297155b 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 b5c4d1b805e..e3e8a2adde7 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 |