20130701_1_remove_reltoastidxid_v15_context.patch
application/octet-stream
Filename: 20130701_1_remove_reltoastidxid_v15_context.patch
Type: application/octet-stream
Part: 1
Message:
Re: Support for REINDEX CONCURRENTLY
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v15
| File | + | − |
|---|---|---|
| contrib/pg_upgrade/info.c | 11 | 0 |
| doc/src/sgml/catalogs.sgml | 0 | 9 |
| doc/src/sgml/diskusage.sgml | 13 | 7 |
| doc/src/sgml/monitoring.sgml | 2 | 0 |
| src/backend/access/heap/tuptoaster.c | 206 | 0 |
| src/backend/catalog/heap.c | 0 | 0 |
| src/backend/catalog/index.c | 4 | 0 |
| src/backend/catalog/system_views.sql | 5 | 0 |
| src/backend/commands/cluster.c | 22 | 0 |
| src/backend/commands/tablecmds.c | 15 | 0 |
| src/backend/rewrite/rewriteDefine.c | 2 | 0 |
| src/backend/utils/adt/dbsize.c | 17 | 0 |
| src/bin/pg_dump/pg_dump.c | 22 | 0 |
| src/include/access/tuptoaster.h | 9 | 0 |
| src/include/catalog/pg_class.h | 21 | 0 |
| src/test/regress/expected/oidjoins.out | 0 | 0 |
| src/test/regress/expected/rules.out | 8 | 0 |
| src/test/regress/sql/oidjoins.sql | 0 | 0 |
| src/test/regress/sql/rules.sql | 1 | 0 |
| src/tools/findoidjoins/README | 0 | 0 |
*** a/contrib/pg_upgrade/info.c
--- b/contrib/pg_upgrade/info.c
***************
*** 321,332 **** get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
"INSERT INTO info_rels "
"SELECT reltoastrelid "
"FROM info_rels i JOIN pg_catalog.pg_class c "
! " ON i.reloid = c.oid"));
PQclear(executeQueryOrDie(conn,
"INSERT INTO info_rels "
! "SELECT reltoastidxid "
! "FROM info_rels i JOIN pg_catalog.pg_class c "
! " ON i.reloid = c.oid"));
snprintf(query, sizeof(query),
"SELECT c.oid, n.nspname, c.relname, "
--- 321,339 ----
"INSERT INTO info_rels "
"SELECT reltoastrelid "
"FROM info_rels i JOIN pg_catalog.pg_class c "
! " ON i.reloid = c.oid "
! " AND c.reltoastrelid != %u", InvalidOid));
PQclear(executeQueryOrDie(conn,
"INSERT INTO info_rels "
! "SELECT indexrelid "
! "FROM pg_index "
! "WHERE indisvalid "
! " AND indrelid IN (SELECT reltoastrelid "
! " FROM info_rels i "
! " JOIN pg_catalog.pg_class c "
! " ON i.reloid = c.oid "
! " AND c.reltoastrelid != %u)",
! InvalidOid));
snprintf(query, sizeof(query),
"SELECT c.oid, n.nspname, c.relname, "
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 1745,1759 ****
</row>
<row>
- <entry><structfield>reltoastidxid</structfield></entry>
- <entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
- <entry>
- For a TOAST table, the OID of its index. 0 if not a TOAST table.
- </entry>
- </row>
-
- <row>
<entry><structfield>relhasindex</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
--- 1745,1750 ----
*** a/doc/src/sgml/diskusage.sgml
--- b/doc/src/sgml/diskusage.sgml
***************
*** 20,31 ****
stored. If the table has any columns with potentially-wide values,
there also might be a <acronym>TOAST</> file associated with the table,
which is used to store values too wide to fit comfortably in the main
! table (see <xref linkend="storage-toast">). There will be one index on the
! <acronym>TOAST</> table, if present. There also might be indexes associated
! with the base table. Each table and index is stored in a separate disk
! file — possibly more than one file, if the file would exceed one
! gigabyte. Naming conventions for these files are described in <xref
! linkend="storage-file-layout">.
</para>
<para>
--- 20,31 ----
stored. If the table has any columns with potentially-wide values,
there also might be a <acronym>TOAST</> file associated with the table,
which is used to store values too wide to fit comfortably in the main
! table (see <xref linkend="storage-toast">). There will be one valid index
! on the <acronym>TOAST</> table, if present. There also might be indexes
! associated with the base table. Each table and index is stored in a
! separate disk file — possibly more than one file, if the file would
! exceed one gigabyte. Naming conventions for these files are described
! in <xref linkend="storage-file-layout">.
</para>
<para>
***************
*** 44,50 ****
<programlisting>
SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'customer';
! pg_relation_filepath | relpages
----------------------+----------
base/16384/16806 | 60
(1 row)
--- 44,50 ----
<programlisting>
SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'customer';
! pg_relation_filepath | relpages
----------------------+----------
base/16384/16806 | 60
(1 row)
***************
*** 65,76 **** 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)
ORDER BY relname;
! relname | relpages
----------------------+----------
pg_toast_16806 | 0
pg_toast_16806_index | 1
--- 65,76 ----
FROM pg_class
WHERE relname = 'customer') AS ss
WHERE oid = ss.reltoastrelid OR
! oid = (SELECT indexrelid
! FROM pg_index
! WHERE indrelid = ss.reltoastrelid)
ORDER BY relname;
! relname | relpages
----------------------+----------
pg_toast_16806 | 0
pg_toast_16806_index | 1
***************
*** 87,93 **** WHERE c.relname = 'customer' AND
c2.oid = i.indexrelid
ORDER BY c2.relname;
! relname | relpages
----------------------+----------
customer_id_indexdex | 26
</programlisting>
--- 87,93 ----
c2.oid = i.indexrelid
ORDER BY c2.relname;
! relname | relpages
----------------------+----------
customer_id_indexdex | 26
</programlisting>
***************
*** 101,107 **** SELECT relname, relpages
FROM pg_class
ORDER BY relpages DESC;
! relname | relpages
----------------------+----------
bigtable | 3290
customer | 3144
--- 101,107 ----
FROM pg_class
ORDER BY relpages DESC;
! relname | relpages
----------------------+----------
bigtable | 3290
customer | 3144
*** a/doc/src/sgml/monitoring.sgml
--- b/doc/src/sgml/monitoring.sgml
***************
*** 1163,1174 **** postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
<row>
<entry><structfield>tidx_blks_read</></entry>
<entry><type>bigint</></entry>
! <entry>Number of disk blocks read from this table's TOAST table index (if any)</entry>
</row>
<row>
<entry><structfield>tidx_blks_hit</></entry>
<entry><type>bigint</></entry>
! <entry>Number of buffer hits in this table's TOAST table index (if any)</entry>
</row>
</tbody>
</tgroup>
--- 1163,1174 ----
<row>
<entry><structfield>tidx_blks_read</></entry>
<entry><type>bigint</></entry>
! <entry>Number of disk blocks read from this table's TOAST table indexes (if any)</entry>
</row>
<row>
<entry><structfield>tidx_blks_hit</></entry>
<entry><type>bigint</></entry>
! <entry>Number of buffer hits in this table's TOAST table indexes (if any)</entry>
</row>
</tbody>
</tgroup>
*** a/src/backend/access/heap/tuptoaster.c
--- b/src/backend/access/heap/tuptoaster.c
***************
*** 76,86 **** do { \
static void toast_delete_datum(Relation rel, Datum value);
static Datum toast_save_datum(Relation rel, Datum value,
struct varlena * oldexternal, int options);
! static bool toastrel_valueid_exists(Relation toastrel, Oid valueid);
static bool 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);
/* ----------
--- 76,93 ----
static void toast_delete_datum(Relation rel, Datum value);
static Datum toast_save_datum(Relation rel, Datum value,
struct varlena * oldexternal, int options);
! static bool toastrel_valueid_exists(Relation toastrel,
! Oid valueid, LOCKMODE lockmode);
static bool toastid_valueid_exists(Oid toastrelid, Oid valueid);
static struct varlena *toast_fetch_datum(struct varlena * attr);
static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
int32 sliceoffset, int32 length);
+ static 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);
/* ----------
***************
*** 1222,1227 **** toast_compress_datum(Datum value)
--- 1229,1269 ----
/* ----------
+ * toast_get_valid_index
+ *
+ * Get the valid index of given toast relation. A toast relation can only
+ * have one valid index at the same time. The lock taken on the index
+ * relations is released at the end of this function call.
+ */
+ Oid
+ toast_get_valid_index(Oid toastoid, LOCKMODE lock)
+ {
+ int num_indexes;
+ int validIndex;
+ Oid validIndexOid;
+ Relation *toastidxs;
+ Relation toastrel;
+
+ /* Get the index list of relation */
+ toastrel = heap_open(toastoid, lock);
+
+ /* Look for the valid index of relation */
+ validIndex = toast_open_indexes(toastrel,
+ lock,
+ &toastidxs,
+ &num_indexes);
+ validIndexOid = RelationGetRelid(toastidxs[validIndex]);
+
+ /* Close all the index relations */
+ toast_close_indexes(toastidxs, num_indexes, lock);
+
+ /* Close toast relation */
+ heap_close(toastrel, lock);
+ return validIndexOid;
+ }
+
+
+ /* ----------
* toast_save_datum -
*
* Save one single datum into the secondary relation and return
***************
*** 1238,1244 **** toast_save_datum(Relation rel, Datum value,
struct varlena * oldexternal, int options)
{
Relation toastrel;
! Relation toastidx;
HeapTuple toasttup;
TupleDesc toasttupDesc;
Datum t_values[3];
--- 1280,1286 ----
struct varlena * oldexternal, int options)
{
Relation toastrel;
! Relation *toastidxs;
HeapTuple toasttup;
TupleDesc toasttupDesc;
Datum t_values[3];
***************
*** 1257,1271 **** toast_save_datum(Relation rel, Datum value,
char *data_p;
int32 data_todo;
Pointer dval = DatumGetPointer(value);
/*
* 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.
*/
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
toasttupDesc = toastrel->rd_att;
! toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
/*
* Get the data pointer and length, and compute va_rawsize and va_extsize.
--- 1299,1321 ----
char *data_p;
int32 data_todo;
Pointer dval = DatumGetPointer(value);
+ int num_indexes;
+ int validIndex;
/*
* 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. A toast table can have multiple identical
! * indexes associated to it.
*/
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
toasttupDesc = toastrel->rd_att;
!
! /* Fetch valid index used for process */
! validIndex = toast_open_indexes(toastrel,
! RowExclusiveLock,
! &toastidxs,
! &num_indexes);
/*
* Get the data pointer and length, and compute va_rawsize and va_extsize.
***************
*** 1330,1336 **** toast_save_datum(Relation rel, Datum value,
/* normal case: just choose an unused OID */
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
! RelationGetRelid(toastidx),
(AttrNumber) 1);
}
else
--- 1380,1386 ----
/* normal case: just choose an unused OID */
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
! RelationGetRelid(toastidxs[validIndex]),
(AttrNumber) 1);
}
else
***************
*** 1367,1373 **** toast_save_datum(Relation rel, Datum value,
* be reclaimed by VACUUM.
*/
if (toastrel_valueid_exists(toastrel,
! toast_pointer.va_valueid))
{
/* Match, so short-circuit the data storage loop below */
data_todo = 0;
--- 1417,1424 ----
* be reclaimed by VACUUM.
*/
if (toastrel_valueid_exists(toastrel,
! toast_pointer.va_valueid,
! RowExclusiveLock))
{
/* Match, so short-circuit the data storage loop below */
data_todo = 0;
***************
*** 1384,1391 **** toast_save_datum(Relation rel, Datum value,
{
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
! RelationGetRelid(toastidx),
! (AttrNumber) 1);
} while (toastid_valueid_exists(rel->rd_toastoid,
toast_pointer.va_valueid));
}
--- 1435,1442 ----
{
toast_pointer.va_valueid =
GetNewOidWithIndex(toastrel,
! RelationGetRelid(toastidxs[validIndex]),
! (AttrNumber) 1);
} while (toastid_valueid_exists(rel->rd_toastoid,
toast_pointer.va_valueid));
}
***************
*** 1405,1410 **** toast_save_datum(Relation rel, Datum value,
--- 1456,1463 ----
*/
while (data_todo > 0)
{
+ int i;
+
/*
* Calculate the size of this chunk
*/
***************
*** 1423,1438 **** 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.
*
* 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);
/*
* Free memory
--- 1476,1497 ----
/*
* 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 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.
*/
! for (i = 0; i < num_indexes; i++)
! {
! /* Only index relations marked as ready can updated */
! if (toastidxs[i]->rd_index->indisready)
! index_insert(toastidxs[i], t_values, t_isnull,
! &(toasttup->t_self),
! toastrel,
! toastidxs[i]->rd_index->indisunique ?
! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
! }
/*
* Free memory
***************
*** 1447,1455 **** toast_save_datum(Relation rel, Datum value,
}
/*
! * Done - close toast relation
*/
! index_close(toastidx, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
/*
--- 1506,1514 ----
}
/*
! * Done - close toast relations
*/
! toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
/*
***************
*** 1475,1484 **** toast_delete_datum(Relation rel, Datum value)
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
struct varatt_external toast_pointer;
Relation toastrel;
! Relation toastidx;
ScanKeyData toastkey;
SysScanDesc toastscan;
HeapTuple toasttup;
if (!VARATT_IS_EXTERNAL(attr))
return;
--- 1534,1545 ----
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
struct varatt_external toast_pointer;
Relation toastrel;
! Relation *toastidxs;
ScanKeyData toastkey;
SysScanDesc toastscan;
HeapTuple toasttup;
+ int num_indexes;
+ int validIndex;
if (!VARATT_IS_EXTERNAL(attr))
return;
***************
*** 1487,1496 **** toast_delete_datum(Relation rel, Datum value)
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
/*
! * Open the toast relation and its index
*/
toastrel = heap_open(toast_pointer.va_toastrelid, RowExclusiveLock);
! toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock);
/*
* Setup a scan key to find chunks with matching va_valueid
--- 1548,1562 ----
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
/*
! * Open the toast relation and its indexes
*/
toastrel = heap_open(toast_pointer.va_toastrelid, 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
***************
*** 1505,1511 **** 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,
SnapshotToast, 1, &toastkey);
while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
--- 1571,1577 ----
* sequence or not, but since we've already locked the index we might as
* well use systable_beginscan_ordered.)
*/
! toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
SnapshotToast, 1, &toastkey);
while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
***************
*** 1519,1525 **** toast_delete_datum(Relation rel, Datum value)
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! index_close(toastidx, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
}
--- 1585,1591 ----
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
heap_close(toastrel, RowExclusiveLock);
}
***************
*** 1531,1541 **** toast_delete_datum(Relation rel, Datum value)
* ----------
*/
static bool
! toastrel_valueid_exists(Relation toastrel, Oid valueid)
{
bool result = false;
ScanKeyData toastkey;
SysScanDesc toastscan;
/*
* Setup a scan key to find chunks with matching va_valueid
--- 1597,1616 ----
* ----------
*/
static bool
! toastrel_valueid_exists(Relation toastrel, Oid valueid, LOCKMODE lockmode)
{
bool result = false;
ScanKeyData toastkey;
SysScanDesc toastscan;
+ int num_indexes;
+ int validIndex;
+ Relation *toastidxs;
+
+ /* Fetch a valid index relation */
+ validIndex = toast_open_indexes(toastrel,
+ lockmode,
+ &toastidxs,
+ &num_indexes);
/*
* Setup a scan key to find chunks with matching va_valueid
***************
*** 1548,1561 **** toastrel_valueid_exists(Relation toastrel, Oid valueid)
/*
* Is there any such chunk?
*/
! toastscan = systable_beginscan(toastrel, toastrel->rd_rel->reltoastidxid,
! true, SnapshotToast, 1, &toastkey);
if (systable_getnext(toastscan) != NULL)
result = true;
systable_endscan(toastscan);
return result;
}
--- 1623,1640 ----
/*
* Is there any such chunk?
*/
! 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, lockmode);
+
return result;
}
***************
*** 1573,1579 **** toastid_valueid_exists(Oid toastrelid, Oid valueid)
toastrel = heap_open(toastrelid, AccessShareLock);
! result = toastrel_valueid_exists(toastrel, valueid);
heap_close(toastrel, AccessShareLock);
--- 1652,1658 ----
toastrel = heap_open(toastrelid, AccessShareLock);
! result = toastrel_valueid_exists(toastrel, valueid, RowExclusiveLock);
heap_close(toastrel, AccessShareLock);
***************
*** 1592,1598 **** static struct varlena *
toast_fetch_datum(struct varlena * attr)
{
Relation toastrel;
! Relation toastidx;
ScanKeyData toastkey;
SysScanDesc toastscan;
HeapTuple ttup;
--- 1671,1677 ----
toast_fetch_datum(struct varlena * attr)
{
Relation toastrel;
! Relation *toastidxs;
ScanKeyData toastkey;
SysScanDesc toastscan;
HeapTuple ttup;
***************
*** 1607,1612 **** toast_fetch_datum(struct varlena * attr)
--- 1686,1693 ----
bool isnull;
char *chunkdata;
int32 chunksize;
+ int num_indexes;
+ int validIndex;
/* Must copy to access aligned fields */
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
***************
*** 1622,1632 **** toast_fetch_datum(struct varlena * attr)
SET_VARSIZE(result, ressize + VARHDRSZ);
/*
! * Open the toast relation and its index
*/
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
toasttupDesc = toastrel->rd_att;
! toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
/*
* Setup a scan key to fetch from the index by va_valueid
--- 1703,1718 ----
SET_VARSIZE(result, ressize + VARHDRSZ);
/*
! * Open the toast relation and its indexes
*/
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
toasttupDesc = toastrel->rd_att;
!
! /* Fetch relation used for process */
! validIndex = toast_open_indexes(toastrel,
! AccessShareLock,
! &toastidxs,
! &num_indexes);
/*
* Setup a scan key to fetch from the index by va_valueid
***************
*** 1645,1651 **** toast_fetch_datum(struct varlena * attr)
*/
nextidx = 0;
! toastscan = systable_beginscan_ordered(toastrel, toastidx,
SnapshotToast, 1, &toastkey);
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
--- 1731,1737 ----
*/
nextidx = 0;
! toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
SnapshotToast, 1, &toastkey);
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
***************
*** 1734,1740 **** toast_fetch_datum(struct varlena * attr)
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! index_close(toastidx, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
--- 1820,1826 ----
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
***************
*** 1751,1757 **** static struct varlena *
toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
{
Relation toastrel;
! Relation toastidx;
ScanKeyData toastkey[3];
int nscankeys;
SysScanDesc toastscan;
--- 1837,1843 ----
toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
{
Relation toastrel;
! Relation *toastidxs;
ScanKeyData toastkey[3];
int nscankeys;
SysScanDesc toastscan;
***************
*** 1774,1779 **** toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
--- 1860,1867 ----
int32 chunksize;
int32 chcpystrt;
int32 chcpyend;
+ int num_indexes;
+ int validIndex;
Assert(VARATT_IS_EXTERNAL(attr));
***************
*** 1816,1826 **** 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
*/
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
toasttupDesc = toastrel->rd_att;
! toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock);
/*
* Setup a scan key to fetch from the index. This is either two keys or
--- 1904,1919 ----
endoffset = (sliceoffset + length - 1) % TOAST_MAX_CHUNK_SIZE;
/*
! * Open the toast relation and its indexes
*/
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
toasttupDesc = toastrel->rd_att;
!
! /* 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
***************
*** 1861,1867 **** 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,
SnapshotToast, nscankeys, toastkey);
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
--- 1954,1960 ----
* The index is on (valueid, chunkidx) so they will come in order
*/
nextidx = startchunk;
! toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
SnapshotToast, nscankeys, toastkey);
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
{
***************
*** 1958,1965 **** toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! index_close(toastidx, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
}
--- 2051,2136 ----
* End scan and close relations
*/
systable_endscan_ordered(toastscan);
! toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
heap_close(toastrel, AccessShareLock);
return result;
}
+
+ /* ----------
+ * toast_open_indexes
+ *
+ * Get an array of index relations 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 index relations 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 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 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 index relations 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);
+ }
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 781,787 **** 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);
--- 781,786 ----
*** a/src/backend/catalog/index.c
--- b/src/backend/catalog/index.c
***************
*** 103,109 **** static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
bool isvalid);
static void index_update_stats(Relation rel,
bool hasindex, bool isprimary,
! Oid reltoastidxid, double reltuples);
static void IndexCheckExclusion(Relation heapRelation,
Relation indexRelation,
IndexInfo *indexInfo);
--- 103,109 ----
bool isvalid);
static void index_update_stats(Relation rel,
bool hasindex, bool isprimary,
! double reltuples);
static void IndexCheckExclusion(Relation heapRelation,
Relation indexRelation,
IndexInfo *indexInfo);
***************
*** 1072,1078 **** index_create(Relation heapRelation,
index_update_stats(heapRelation,
true,
isprimary,
- InvalidOid,
-1.0);
/* Make the above update visible */
CommandCounterIncrement();
--- 1072,1077 ----
***************
*** 1254,1260 **** index_constraint_create(Relation heapRelation,
index_update_stats(heapRelation,
true,
true,
- InvalidOid,
-1.0);
/*
--- 1253,1258 ----
***************
*** 1764,1771 **** 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
--- 1762,1767 ----
***************
*** 1781,1788 **** FormIndexDatum(IndexInfo *indexInfo,
*/
static void
index_update_stats(Relation rel,
! bool hasindex, bool isprimary,
! Oid reltoastidxid, double reltuples)
{
Oid relid = RelationGetRelid(rel);
Relation pg_class;
--- 1777,1785 ----
*/
static void
index_update_stats(Relation rel,
! bool hasindex,
! bool isprimary,
! double reltuples)
{
Oid relid = RelationGetRelid(rel);
Relation pg_class;
***************
*** 1876,1890 **** 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)
{
--- 1873,1878 ----
***************
*** 2072,2085 **** 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 */
--- 2060,2070 ----
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 473,488 **** 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
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_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;
CREATE VIEW pg_statio_sys_tables AS
SELECT * FROM pg_statio_all_tables
--- 473,488 ----
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,
! 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_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.indexrelid;
CREATE VIEW pg_statio_sys_tables AS
SELECT * FROM pg_statio_all_tables
*** a/src/backend/commands/cluster.c
--- b/src/backend/commands/cluster.c
***************
*** 21,26 ****
--- 21,27 ----
#include "access/relscan.h"
#include "access/rewriteheap.h"
#include "access/transam.h"
+ #include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
***************
*** 1172,1179 **** 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
--- 1173,1178 ----
***************
*** 1393,1410 **** 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 (swap_toast_by_content &&
! relform1->reltoastidxid && relform2->reltoastidxid)
! swap_relation_files(relform1->reltoastidxid,
! relform2->reltoastidxid,
target_is_pg_class,
swap_toast_by_content,
is_internal,
InvalidTransactionId,
InvalidMultiXactId,
mapped_tables);
/* Clean up. */
heap_freetuple(reltup1);
--- 1392,1421 ----
/*
* If we're swapping two toast tables by content, do the same for their
! * valid index. The swap can actually be safely done only if the relations
! * have indexes.
*/
if (swap_toast_by_content &&
! 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);
***************
*** 1528,1541 **** 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);
/* rename the toast table ... */
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
--- 1539,1550 ----
newrel = heap_open(OIDOldHeap, NoLock);
if (OidIsValid(newrel->rd_rel->reltoastrelid))
{
Oid toastidx;
char NewToastName[NAMEDATALEN];
! /* Get the associated valid index to be renamed */
! toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
! AccessShareLock);
/* rename the toast table ... */
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
***************
*** 1543,1551 **** finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
RenameRelationInternal(newrel->rd_rel->reltoastrelid,
NewToastName, true);
! /* ... and its index too */
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
OIDOldHeap);
RenameRelationInternal(toastidx,
NewToastName, true);
}
--- 1552,1561 ----
RenameRelationInternal(newrel->rd_rel->reltoastrelid,
NewToastName, true);
! /* ... and its valid index too. */
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
OIDOldHeap);
+
RenameRelationInternal(toastidx,
NewToastName, true);
}
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 8869,8875 **** ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
Relation rel;
Oid oldTableSpace;
Oid reltoastrelid;
- Oid reltoastidxid;
Oid newrelfilenode;
RelFileNode newrnode;
SMgrRelation dstrel;
--- 8869,8874 ----
***************
*** 8877,8882 **** ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
--- 8876,8883 ----
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
***************
*** 8923,8929 **** 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;
/* Get a modifiable copy of the relation's pg_class row */
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
--- 8924,8936 ----
errmsg("cannot move temporary tables of other sessions")));
reltoastrelid = rel->rd_rel->reltoastrelid;
! /* 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);
***************
*** 9001,9011 **** ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
/* Make sure the reltablespace change is visible */
CommandCounterIncrement();
! /* Move associated toast relation and/or index, too */
if (OidIsValid(reltoastrelid))
ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
! if (OidIsValid(reltoastidxid))
! ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode);
}
/*
--- 9008,9021 ----
/* Make sure the reltablespace change is visible */
CommandCounterIncrement();
! /* Move associated toast relation and/or indexes, too */
if (OidIsValid(reltoastrelid))
ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
! foreach(lc, reltoastidxids)
! ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
!
! /* Clean up */
! list_free(reltoastidxids);
}
/*
*** a/src/backend/rewrite/rewriteDefine.c
--- b/src/backend/rewrite/rewriteDefine.c
***************
*** 575,582 **** 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.
*/
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
if (!HeapTupleIsValid(classTup))
--- 575,582 ----
/*
* Fix pg_class entry to look like a normal view's, including setting
! * the correct relkind and removal of reltoastrelid of the toast table
! * we potentially removed above.
*/
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
if (!HeapTupleIsValid(classTup))
***************
*** 588,594 **** 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;
--- 588,593 ----
*** a/src/backend/utils/adt/dbsize.c
--- b/src/backend/utils/adt/dbsize.c
***************
*** 332,338 **** pg_relation_size(PG_FUNCTION_ARGS)
}
/*
! * Calculate total on-disk size of a TOAST relation, including its index.
* Must not be applied to non-TOAST relations.
*/
static int64
--- 332,338 ----
}
/*
! * Calculate total on-disk size of a TOAST relation, including its indexes.
* Must not be applied to non-TOAST relations.
*/
static int64
***************
*** 340,347 **** calculate_toast_table_size(Oid toastrelid)
{
int64 size = 0;
Relation toastRel;
- Relation toastIdxRel;
ForkNumber forkNum;
toastRel = relation_open(toastrelid, AccessShareLock);
--- 340,348 ----
{
int64 size = 0;
Relation toastRel;
ForkNumber forkNum;
+ ListCell *lc;
+ List *indexlist;
toastRel = relation_open(toastrelid, AccessShareLock);
***************
*** 351,362 **** 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);
! relation_close(toastIdxRel, AccessShareLock);
relation_close(toastRel, AccessShareLock);
return size;
--- 352,372 ----
toastRel->rd_backend, forkNum);
/* toast index size, including FSM and VM size */
! indexlist = RelationGetIndexList(toastRel);
! /* 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;
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 2778,2787 **** 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 "
"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;",
--- 2778,2786 ----
PQExpBuffer upgrade_query = createPQExpBuffer();
PGresult *upgrade_res;
Oid pg_class_reltoastrelid;
appendPQExpBuffer(upgrade_query,
! "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;",
***************
*** 2790,2796 **** 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");
--- 2789,2794 ----
***************
*** 2803,2808 **** binary_upgrade_set_pg_class_oids(Archive *fout,
--- 2801,2810 ----
/* only tables have toast tables, not indexes */
if (OidIsValid(pg_class_reltoastrelid))
{
+ PQExpBuffer index_query = createPQExpBuffer();
+ PGresult *index_res;
+ Oid indexrelid;
+
/*
* One complexity is that the table definition might not require
* the creation of a TOAST table, and the TOAST table might have
***************
*** 2816,2825 **** binary_upgrade_set_pg_class_oids(Archive *fout,
"SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
pg_class_reltoastrelid);
! /* every toast table has an index */
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
! pg_class_reltoastidxid);
}
}
else
--- 2818,2840 ----
"SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
pg_class_reltoastrelid);
! /* Every toast table has one valid index, so fetch it first... */
! appendPQExpBuffer(index_query,
! "SELECT c.indexrelid "
! "FROM pg_catalog.pg_index c "
! "WHERE c.indrelid = %u;",
! pg_class_reltoastrelid);
! index_res = ExecuteSqlQueryForSingleRow(fout, index_query->data);
! indexrelid = atooid(PQgetvalue(index_res, 0,
! PQfnumber(index_res, "indexrelid")));
!
! /* Then set it */
appendPQExpBuffer(upgrade_buffer,
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
! indexrelid);
!
! PQclear(index_res);
! destroyPQExpBuffer(index_query);
}
}
else
***************
*** 13126,13132 **** 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 ||
tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
{
for (j = 0; j < tbinfo->numatts; j++)
--- 13141,13147 ----
* 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 ||
tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
{
for (j = 0; j < tbinfo->numatts; j++)
***************
*** 13151,13157 **** 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]));
}
--- 13166,13172 ----
else
appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
fmtId(tbinfo->dobj.name));
!
appendPQExpBuffer(q, "DROP COLUMN %s;\n",
fmtId(tbinfo->attnames[j]));
}
*** a/src/include/access/tuptoaster.h
--- b/src/include/access/tuptoaster.h
***************
*** 15,20 ****
--- 15,21 ----
#include "access/htup_details.h"
#include "utils/relcache.h"
+ #include "storage/lock.h"
/*
* This enables de-toasting of index entries. Needed until VACUUM is
***************
*** 188,191 **** extern Size toast_raw_datum_size(Datum value);
--- 189,200 ----
*/
extern Size toast_datum_size(Datum value);
+ /* ----------
+ * toast_get_valid_index -
+ *
+ * Return valid index associated to a toast relation
+ * ----------
+ */
+ extern Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock);
+
#endif /* TUPTOASTER_H */
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
***************
*** 48,54 **** 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 */
--- 48,53 ----
***************
*** 94,100 **** typedef FormData_pg_class *Form_pg_class;
* ----------------
*/
! #define Natts_pg_class 29
#define Anum_pg_class_relname 1
#define Anum_pg_class_relnamespace 2
#define Anum_pg_class_reltype 3
--- 93,99 ----
* ----------------
*/
! #define Natts_pg_class 28
#define Anum_pg_class_relname 1
#define Anum_pg_class_relnamespace 2
#define Anum_pg_class_reltype 3
***************
*** 107,129 **** 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
/* ----------------
* initial contents of pg_class
--- 106,127 ----
#define Anum_pg_class_reltuples 10
#define Anum_pg_class_relallvisible 11
#define Anum_pg_class_reltoastrelid 12
! #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,150 **** 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_ ));
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_ ));
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_ ));
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_ ));
DESCR("");
--- 136,148 ----
* 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 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 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 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 f f p r 28 0 t f f f f t 3 1 _null_ _null_ ));
DESCR("");
*** a/src/test/regress/expected/oidjoins.out
--- b/src/test/regress/expected/oidjoins.out
***************
*** 353,366 **** 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
--- 353,358 ----
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
***************
*** 1852,1866 **** 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 +
| 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_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;
pg_statio_sys_indexes | SELECT pg_statio_all_indexes.relid, +
| pg_statio_all_indexes.indexrelid, +
| pg_statio_all_indexes.schemaname, +
--- 1852,1866 ----
| (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, +
! | (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_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.indexrelid;
pg_statio_sys_indexes | SELECT pg_statio_all_indexes.relid, +
| pg_statio_all_indexes.indexrelid, +
| pg_statio_all_indexes.schemaname, +
***************
*** 2347,2357 **** 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
from pg_class where oid = 'fooview'::regclass;
! reltoastrelid | reltoastidxid | relkind | relfrozenxid
! ---------------+---------------+---------+--------------
! 0 | 0 | v | 0
(1 row)
drop view fooview;
--- 2347,2357 ----
ERROR: column "xmin" does not exist
LINE 1: select xmin, * from fooview;
^
! select reltoastrelid, relkind, relfrozenxid
from pg_class where oid = 'fooview'::regclass;
! reltoastrelid | relkind | relfrozenxid
! ---------------+---------+--------------
! 0 | v | 0
(1 row)
drop view fooview;
*** a/src/test/regress/sql/oidjoins.sql
--- b/src/test/regress/sql/oidjoins.sql
***************
*** 177,186 **** 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
--- 177,182 ----
*** a/src/test/regress/sql/rules.sql
--- b/src/test/regress/sql/rules.sql
***************
*** 872,878 **** 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
from pg_class where oid = 'fooview'::regclass;
drop view fooview;
--- 872,878 ----
select * from fooview;
select xmin, * from fooview; -- fail, views don't have such a column
! select reltoastrelid, relkind, relfrozenxid
from pg_class where oid = 'fooview'::regclass;
drop view fooview;
*** a/src/tools/findoidjoins/README
--- b/src/tools/findoidjoins/README
***************
*** 86,92 **** 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
--- 86,91 ----