mirror of https://github.com/postgres/postgres
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.
This commit is contained in:
parent
f71939cd1a
commit
2ef085d0e6
|
@ -321,12 +321,19 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
|
||||||
"INSERT INTO info_rels "
|
"INSERT INTO info_rels "
|
||||||
"SELECT reltoastrelid "
|
"SELECT reltoastrelid "
|
||||||
"FROM info_rels i JOIN pg_catalog.pg_class c "
|
"FROM info_rels i JOIN pg_catalog.pg_class c "
|
||||||
" ON i.reloid = c.oid"));
|
" ON i.reloid = c.oid "
|
||||||
|
" AND c.reltoastrelid != %u", InvalidOid));
|
||||||
PQclear(executeQueryOrDie(conn,
|
PQclear(executeQueryOrDie(conn,
|
||||||
"INSERT INTO info_rels "
|
"INSERT INTO info_rels "
|
||||||
"SELECT reltoastidxid "
|
"SELECT indexrelid "
|
||||||
"FROM info_rels i JOIN pg_catalog.pg_class c "
|
"FROM pg_index "
|
||||||
" ON i.reloid = c.oid"));
|
"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),
|
snprintf(query, sizeof(query),
|
||||||
"SELECT c.oid, n.nspname, c.relname, "
|
"SELECT c.oid, n.nspname, c.relname, "
|
||||||
|
|
|
@ -1744,15 +1744,6 @@
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</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>
|
<row>
|
||||||
<entry><structfield>relhasindex</structfield></entry>
|
<entry><structfield>relhasindex</structfield></entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>bool</type></entry>
|
||||||
|
|
|
@ -20,12 +20,12 @@
|
||||||
stored. If the table has any columns with potentially-wide values,
|
stored. If the table has any columns with potentially-wide values,
|
||||||
there also might be a <acronym>TOAST</> file associated with the table,
|
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
|
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
|
table (see <xref linkend="storage-toast">). There will be one valid index
|
||||||
<acronym>TOAST</> table, if present. There also might be indexes associated
|
on the <acronym>TOAST</> table, if present. There also might be indexes
|
||||||
with the base table. Each table and index is stored in a separate disk
|
associated with the base table. Each table and index is stored in a
|
||||||
file — possibly more than one file, if the file would exceed one
|
separate disk file — possibly more than one file, if the file would
|
||||||
gigabyte. Naming conventions for these files are described in <xref
|
exceed one gigabyte. Naming conventions for these files are described
|
||||||
linkend="storage-file-layout">.
|
in <xref linkend="storage-file-layout">.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<programlisting>
|
<programlisting>
|
||||||
SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'customer';
|
SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'customer';
|
||||||
|
|
||||||
pg_relation_filepath | relpages
|
pg_relation_filepath | relpages
|
||||||
----------------------+----------
|
----------------------+----------
|
||||||
base/16384/16806 | 60
|
base/16384/16806 | 60
|
||||||
(1 row)
|
(1 row)
|
||||||
|
@ -65,12 +65,12 @@ FROM pg_class,
|
||||||
FROM pg_class
|
FROM pg_class
|
||||||
WHERE relname = 'customer') AS ss
|
WHERE relname = 'customer') AS ss
|
||||||
WHERE oid = ss.reltoastrelid OR
|
WHERE oid = ss.reltoastrelid OR
|
||||||
oid = (SELECT reltoastidxid
|
oid = (SELECT indexrelid
|
||||||
FROM pg_class
|
FROM pg_index
|
||||||
WHERE oid = ss.reltoastrelid)
|
WHERE indrelid = ss.reltoastrelid)
|
||||||
ORDER BY relname;
|
ORDER BY relname;
|
||||||
|
|
||||||
relname | relpages
|
relname | relpages
|
||||||
----------------------+----------
|
----------------------+----------
|
||||||
pg_toast_16806 | 0
|
pg_toast_16806 | 0
|
||||||
pg_toast_16806_index | 1
|
pg_toast_16806_index | 1
|
||||||
|
@ -87,7 +87,7 @@ WHERE c.relname = 'customer' AND
|
||||||
c2.oid = i.indexrelid
|
c2.oid = i.indexrelid
|
||||||
ORDER BY c2.relname;
|
ORDER BY c2.relname;
|
||||||
|
|
||||||
relname | relpages
|
relname | relpages
|
||||||
----------------------+----------
|
----------------------+----------
|
||||||
customer_id_indexdex | 26
|
customer_id_indexdex | 26
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
@ -101,7 +101,7 @@ SELECT relname, relpages
|
||||||
FROM pg_class
|
FROM pg_class
|
||||||
ORDER BY relpages DESC;
|
ORDER BY relpages DESC;
|
||||||
|
|
||||||
relname | relpages
|
relname | relpages
|
||||||
----------------------+----------
|
----------------------+----------
|
||||||
bigtable | 3290
|
bigtable | 3290
|
||||||
customer | 3144
|
customer | 3144
|
||||||
|
|
|
@ -1163,12 +1163,12 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>tidx_blks_read</></entry>
|
<entry><structfield>tidx_blks_read</></entry>
|
||||||
<entry><type>bigint</></entry>
|
<entry><type>bigint</></entry>
|
||||||
<entry>Number of disk blocks read from this table's TOAST table index (if any)</entry>
|
<entry>Number of disk blocks read from this table's TOAST table indexes (if any)</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>tidx_blks_hit</></entry>
|
<entry><structfield>tidx_blks_hit</></entry>
|
||||||
<entry><type>bigint</></entry>
|
<entry><type>bigint</></entry>
|
||||||
<entry>Number of buffer hits in this table's TOAST table index (if any)</entry>
|
<entry>Number of buffer hits in this table's TOAST table indexes (if any)</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
|
|
|
@ -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(struct varlena * attr);
|
||||||
static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
|
static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
|
||||||
int32 sliceoffset, int32 length);
|
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);
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
|
@ -1286,6 +1292,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 -
|
* toast_save_datum -
|
||||||
*
|
*
|
||||||
|
@ -1303,7 +1342,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||||
struct varlena * oldexternal, int options)
|
struct varlena * oldexternal, int options)
|
||||||
{
|
{
|
||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation *toastidxs;
|
||||||
HeapTuple toasttup;
|
HeapTuple toasttup;
|
||||||
TupleDesc toasttupDesc;
|
TupleDesc toasttupDesc;
|
||||||
Datum t_values[3];
|
Datum t_values[3];
|
||||||
|
@ -1322,17 +1361,24 @@ toast_save_datum(Relation rel, Datum value,
|
||||||
char *data_p;
|
char *data_p;
|
||||||
int32 data_todo;
|
int32 data_todo;
|
||||||
Pointer dval = DatumGetPointer(value);
|
Pointer dval = DatumGetPointer(value);
|
||||||
|
int num_indexes;
|
||||||
|
int validIndex;
|
||||||
|
|
||||||
Assert(!VARATT_IS_EXTERNAL(value));
|
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
|
* uniqueness of the OID we assign to the toasted item, even though it has
|
||||||
* additional columns besides OID.
|
* additional columns besides OID.
|
||||||
*/
|
*/
|
||||||
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
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.
|
* 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 */
|
/* normal case: just choose an unused OID */
|
||||||
toast_pointer.va_valueid =
|
toast_pointer.va_valueid =
|
||||||
GetNewOidWithIndex(toastrel,
|
GetNewOidWithIndex(toastrel,
|
||||||
RelationGetRelid(toastidx),
|
RelationGetRelid(toastidxs[validIndex]),
|
||||||
(AttrNumber) 1);
|
(AttrNumber) 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1451,7 +1497,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||||
{
|
{
|
||||||
toast_pointer.va_valueid =
|
toast_pointer.va_valueid =
|
||||||
GetNewOidWithIndex(toastrel,
|
GetNewOidWithIndex(toastrel,
|
||||||
RelationGetRelid(toastidx),
|
RelationGetRelid(toastidxs[validIndex]),
|
||||||
(AttrNumber) 1);
|
(AttrNumber) 1);
|
||||||
} while (toastid_valueid_exists(rel->rd_toastoid,
|
} while (toastid_valueid_exists(rel->rd_toastoid,
|
||||||
toast_pointer.va_valueid));
|
toast_pointer.va_valueid));
|
||||||
|
@ -1472,6 +1518,8 @@ toast_save_datum(Relation rel, Datum value,
|
||||||
*/
|
*/
|
||||||
while (data_todo > 0)
|
while (data_todo > 0)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the size of this chunk
|
* 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
|
* Create the index entry. We cheat a little here by not using
|
||||||
* FormIndexDatum: this relies on the knowledge that the index columns
|
* 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
|
* 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.
|
* the TOAST table, since we don't bother to update anything else.
|
||||||
*/
|
*/
|
||||||
index_insert(toastidx, t_values, t_isnull,
|
for (i = 0; i < num_indexes; i++)
|
||||||
&(toasttup->t_self),
|
{
|
||||||
toastrel,
|
/* Only index relations marked as ready can updated */
|
||||||
toastidx->rd_index->indisunique ?
|
if (IndexIsReady(toastidxs[i]->rd_index))
|
||||||
UNIQUE_CHECK_YES : UNIQUE_CHECK_NO);
|
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
|
* 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);
|
heap_close(toastrel, RowExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1542,10 +1596,12 @@ toast_delete_datum(Relation rel, Datum value)
|
||||||
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
|
struct varlena *attr = (struct varlena *) DatumGetPointer(value);
|
||||||
struct varatt_external toast_pointer;
|
struct varatt_external toast_pointer;
|
||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation *toastidxs;
|
||||||
ScanKeyData toastkey;
|
ScanKeyData toastkey;
|
||||||
SysScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
HeapTuple toasttup;
|
HeapTuple toasttup;
|
||||||
|
int num_indexes;
|
||||||
|
int validIndex;
|
||||||
|
|
||||||
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
|
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
|
||||||
return;
|
return;
|
||||||
|
@ -1554,10 +1610,15 @@ toast_delete_datum(Relation rel, Datum value)
|
||||||
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
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);
|
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
|
* 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
|
* sequence or not, but since we've already locked the index we might as
|
||||||
* well use systable_beginscan_ordered.)
|
* well use systable_beginscan_ordered.)
|
||||||
*/
|
*/
|
||||||
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
|
||||||
SnapshotToast, 1, &toastkey);
|
SnapshotToast, 1, &toastkey);
|
||||||
while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
while ((toasttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1586,7 +1647,7 @@ toast_delete_datum(Relation rel, Datum value)
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
systable_endscan_ordered(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, RowExclusiveLock);
|
toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
|
||||||
heap_close(toastrel, RowExclusiveLock);
|
heap_close(toastrel, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1603,6 +1664,15 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
|
||||||
bool result = false;
|
bool result = false;
|
||||||
ScanKeyData toastkey;
|
ScanKeyData toastkey;
|
||||||
SysScanDesc toastscan;
|
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
|
* 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?
|
* Is there any such chunk?
|
||||||
*/
|
*/
|
||||||
toastscan = systable_beginscan(toastrel, toastrel->rd_rel->reltoastidxid,
|
toastscan = systable_beginscan(toastrel,
|
||||||
true, SnapshotToast, 1, &toastkey);
|
RelationGetRelid(toastidxs[validIndex]),
|
||||||
|
true, SnapshotToast, 1, &toastkey);
|
||||||
|
|
||||||
if (systable_getnext(toastscan) != NULL)
|
if (systable_getnext(toastscan) != NULL)
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
systable_endscan(toastscan);
|
systable_endscan(toastscan);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1659,7 +1733,7 @@ static struct varlena *
|
||||||
toast_fetch_datum(struct varlena * attr)
|
toast_fetch_datum(struct varlena * attr)
|
||||||
{
|
{
|
||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation *toastidxs;
|
||||||
ScanKeyData toastkey;
|
ScanKeyData toastkey;
|
||||||
SysScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
HeapTuple ttup;
|
HeapTuple ttup;
|
||||||
|
@ -1674,6 +1748,8 @@ toast_fetch_datum(struct varlena * attr)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
char *chunkdata;
|
char *chunkdata;
|
||||||
int32 chunksize;
|
int32 chunksize;
|
||||||
|
int num_indexes;
|
||||||
|
int validIndex;
|
||||||
|
|
||||||
if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
||||||
elog(ERROR, "shouldn't be called for indirect tuples");
|
elog(ERROR, "shouldn't be called for indirect tuples");
|
||||||
|
@ -1692,11 +1768,16 @@ toast_fetch_datum(struct varlena * attr)
|
||||||
SET_VARSIZE(result, ressize + VARHDRSZ);
|
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);
|
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
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
|
* Setup a scan key to fetch from the index by va_valueid
|
||||||
|
@ -1715,7 +1796,7 @@ toast_fetch_datum(struct varlena * attr)
|
||||||
*/
|
*/
|
||||||
nextidx = 0;
|
nextidx = 0;
|
||||||
|
|
||||||
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
|
||||||
SnapshotToast, 1, &toastkey);
|
SnapshotToast, 1, &toastkey);
|
||||||
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1804,7 +1885,7 @@ toast_fetch_datum(struct varlena * attr)
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
systable_endscan_ordered(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, AccessShareLock);
|
toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
|
||||||
heap_close(toastrel, AccessShareLock);
|
heap_close(toastrel, AccessShareLock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1821,7 +1902,7 @@ static struct varlena *
|
||||||
toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
||||||
{
|
{
|
||||||
Relation toastrel;
|
Relation toastrel;
|
||||||
Relation toastidx;
|
Relation *toastidxs;
|
||||||
ScanKeyData toastkey[3];
|
ScanKeyData toastkey[3];
|
||||||
int nscankeys;
|
int nscankeys;
|
||||||
SysScanDesc toastscan;
|
SysScanDesc toastscan;
|
||||||
|
@ -1844,6 +1925,8 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
|
||||||
int32 chunksize;
|
int32 chunksize;
|
||||||
int32 chcpystrt;
|
int32 chcpystrt;
|
||||||
int32 chcpyend;
|
int32 chcpyend;
|
||||||
|
int num_indexes;
|
||||||
|
int validIndex;
|
||||||
|
|
||||||
Assert(VARATT_IS_EXTERNAL_ONDISK(attr));
|
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;
|
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);
|
toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
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
|
* 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
|
* The index is on (valueid, chunkidx) so they will come in order
|
||||||
*/
|
*/
|
||||||
nextidx = startchunk;
|
nextidx = startchunk;
|
||||||
toastscan = systable_beginscan_ordered(toastrel, toastidx,
|
toastscan = systable_beginscan_ordered(toastrel, toastidxs[validIndex],
|
||||||
SnapshotToast, nscankeys, toastkey);
|
SnapshotToast, nscankeys, toastkey);
|
||||||
while ((ttup = systable_getnext_ordered(toastscan, ForwardScanDirection)) != NULL)
|
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
|
* End scan and close relations
|
||||||
*/
|
*/
|
||||||
systable_endscan_ordered(toastscan);
|
systable_endscan_ordered(toastscan);
|
||||||
index_close(toastidx, AccessShareLock);
|
toast_close_indexes(toastidxs, num_indexes, AccessShareLock);
|
||||||
heap_close(toastrel, AccessShareLock);
|
heap_close(toastrel, AccessShareLock);
|
||||||
|
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -781,7 +781,6 @@ InsertPgClassTuple(Relation pg_class_desc,
|
||||||
values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
|
values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
|
||||||
values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
|
values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible);
|
||||||
values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
|
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_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
|
||||||
values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
|
values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
|
||||||
values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
|
values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
|
||||||
|
|
|
@ -103,7 +103,7 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
||||||
bool isvalid);
|
bool isvalid);
|
||||||
static void index_update_stats(Relation rel,
|
static void index_update_stats(Relation rel,
|
||||||
bool hasindex, bool isprimary,
|
bool hasindex, bool isprimary,
|
||||||
Oid reltoastidxid, double reltuples);
|
double reltuples);
|
||||||
static void IndexCheckExclusion(Relation heapRelation,
|
static void IndexCheckExclusion(Relation heapRelation,
|
||||||
Relation indexRelation,
|
Relation indexRelation,
|
||||||
IndexInfo *indexInfo);
|
IndexInfo *indexInfo);
|
||||||
|
@ -1072,7 +1072,6 @@ index_create(Relation heapRelation,
|
||||||
index_update_stats(heapRelation,
|
index_update_stats(heapRelation,
|
||||||
true,
|
true,
|
||||||
isprimary,
|
isprimary,
|
||||||
InvalidOid,
|
|
||||||
-1.0);
|
-1.0);
|
||||||
/* Make the above update visible */
|
/* Make the above update visible */
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
@ -1254,7 +1253,6 @@ index_constraint_create(Relation heapRelation,
|
||||||
index_update_stats(heapRelation,
|
index_update_stats(heapRelation,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
InvalidOid,
|
|
||||||
-1.0);
|
-1.0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1764,8 +1762,6 @@ FormIndexDatum(IndexInfo *indexInfo,
|
||||||
*
|
*
|
||||||
* hasindex: set relhasindex to this value
|
* hasindex: set relhasindex to this value
|
||||||
* isprimary: if true, set relhaspkey true; else no change
|
* 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
|
* reltuples: if >= 0, set reltuples to this value; else no change
|
||||||
*
|
*
|
||||||
* If reltuples >= 0, relpages and relallvisible are also updated (using
|
* If reltuples >= 0, relpages and relallvisible are also updated (using
|
||||||
|
@ -1781,8 +1777,9 @@ FormIndexDatum(IndexInfo *indexInfo,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
index_update_stats(Relation rel,
|
index_update_stats(Relation rel,
|
||||||
bool hasindex, bool isprimary,
|
bool hasindex,
|
||||||
Oid reltoastidxid, double reltuples)
|
bool isprimary,
|
||||||
|
double reltuples)
|
||||||
{
|
{
|
||||||
Oid relid = RelationGetRelid(rel);
|
Oid relid = RelationGetRelid(rel);
|
||||||
Relation pg_class;
|
Relation pg_class;
|
||||||
|
@ -1876,15 +1873,6 @@ index_update_stats(Relation rel,
|
||||||
dirty = true;
|
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)
|
if (reltuples >= 0)
|
||||||
{
|
{
|
||||||
|
@ -2072,14 +2060,11 @@ index_build(Relation heapRelation,
|
||||||
index_update_stats(heapRelation,
|
index_update_stats(heapRelation,
|
||||||
true,
|
true,
|
||||||
isprimary,
|
isprimary,
|
||||||
(heapRelation->rd_rel->relkind == RELKIND_TOASTVALUE) ?
|
|
||||||
RelationGetRelid(indexRelation) : InvalidOid,
|
|
||||||
stats->heap_tuples);
|
stats->heap_tuples);
|
||||||
|
|
||||||
index_update_stats(indexRelation,
|
index_update_stats(indexRelation,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
InvalidOid,
|
|
||||||
stats->index_tuples);
|
stats->index_tuples);
|
||||||
|
|
||||||
/* Make the updated catalog row versions visible */
|
/* Make the updated catalog row versions visible */
|
||||||
|
|
|
@ -473,16 +473,16 @@ CREATE VIEW pg_statio_all_tables AS
|
||||||
pg_stat_get_blocks_fetched(T.oid) -
|
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_read,
|
||||||
pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit,
|
pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit,
|
||||||
pg_stat_get_blocks_fetched(X.oid) -
|
sum(pg_stat_get_blocks_fetched(X.indexrelid) -
|
||||||
pg_stat_get_blocks_hit(X.oid) AS tidx_blks_read,
|
pg_stat_get_blocks_hit(X.indexrelid))::bigint AS tidx_blks_read,
|
||||||
pg_stat_get_blocks_hit(X.oid) AS tidx_blks_hit
|
sum(pg_stat_get_blocks_hit(X.indexrelid))::bigint AS tidx_blks_hit
|
||||||
FROM pg_class C LEFT JOIN
|
FROM pg_class C LEFT JOIN
|
||||||
pg_index I ON C.oid = I.indrelid LEFT JOIN
|
pg_index I ON C.oid = I.indrelid LEFT JOIN
|
||||||
pg_class T ON C.reltoastrelid = T.oid 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)
|
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
|
||||||
WHERE C.relkind IN ('r', 't', 'm')
|
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
|
CREATE VIEW pg_statio_sys_tables AS
|
||||||
SELECT * FROM pg_statio_all_tables
|
SELECT * FROM pg_statio_all_tables
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "access/rewriteheap.h"
|
#include "access/rewriteheap.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
|
#include "access/tuptoaster.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
|
@ -1177,8 +1178,6 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
|
||||||
swaptemp = relform1->reltoastrelid;
|
swaptemp = relform1->reltoastrelid;
|
||||||
relform1->reltoastrelid = relform2->reltoastrelid;
|
relform1->reltoastrelid = relform2->reltoastrelid;
|
||||||
relform2->reltoastrelid = swaptemp;
|
relform2->reltoastrelid = swaptemp;
|
||||||
|
|
||||||
/* we should NOT swap reltoastidxid */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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
|
* 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 &&
|
if (swap_toast_by_content &&
|
||||||
relform1->reltoastidxid && relform2->reltoastidxid)
|
relform1->relkind == RELKIND_TOASTVALUE &&
|
||||||
swap_relation_files(relform1->reltoastidxid,
|
relform2->relkind == RELKIND_TOASTVALUE)
|
||||||
relform2->reltoastidxid,
|
{
|
||||||
|
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,
|
target_is_pg_class,
|
||||||
swap_toast_by_content,
|
swap_toast_by_content,
|
||||||
is_internal,
|
is_internal,
|
||||||
InvalidTransactionId,
|
InvalidTransactionId,
|
||||||
InvalidMultiXactId,
|
InvalidMultiXactId,
|
||||||
mapped_tables);
|
mapped_tables);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
heap_freetuple(reltup1);
|
heap_freetuple(reltup1);
|
||||||
|
@ -1533,14 +1544,12 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
|
||||||
newrel = heap_open(OIDOldHeap, NoLock);
|
newrel = heap_open(OIDOldHeap, NoLock);
|
||||||
if (OidIsValid(newrel->rd_rel->reltoastrelid))
|
if (OidIsValid(newrel->rd_rel->reltoastrelid))
|
||||||
{
|
{
|
||||||
Relation toastrel;
|
|
||||||
Oid toastidx;
|
Oid toastidx;
|
||||||
char NewToastName[NAMEDATALEN];
|
char NewToastName[NAMEDATALEN];
|
||||||
|
|
||||||
toastrel = relation_open(newrel->rd_rel->reltoastrelid,
|
/* Get the associated valid index to be renamed */
|
||||||
AccessShareLock);
|
toastidx = toast_get_valid_index(newrel->rd_rel->reltoastrelid,
|
||||||
toastidx = toastrel->rd_rel->reltoastidxid;
|
AccessShareLock);
|
||||||
relation_close(toastrel, AccessShareLock);
|
|
||||||
|
|
||||||
/* rename the toast table ... */
|
/* rename the toast table ... */
|
||||||
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
|
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
|
||||||
|
@ -1548,9 +1557,10 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
|
||||||
RenameRelationInternal(newrel->rd_rel->reltoastrelid,
|
RenameRelationInternal(newrel->rd_rel->reltoastrelid,
|
||||||
NewToastName, true);
|
NewToastName, true);
|
||||||
|
|
||||||
/* ... and its index too */
|
/* ... and its valid index too. */
|
||||||
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
|
snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
|
||||||
OIDOldHeap);
|
OIDOldHeap);
|
||||||
|
|
||||||
RenameRelationInternal(toastidx,
|
RenameRelationInternal(toastidx,
|
||||||
NewToastName, true);
|
NewToastName, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8878,7 +8878,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
|
||||||
Relation rel;
|
Relation rel;
|
||||||
Oid oldTableSpace;
|
Oid oldTableSpace;
|
||||||
Oid reltoastrelid;
|
Oid reltoastrelid;
|
||||||
Oid reltoastidxid;
|
|
||||||
Oid newrelfilenode;
|
Oid newrelfilenode;
|
||||||
RelFileNode newrnode;
|
RelFileNode newrnode;
|
||||||
SMgrRelation dstrel;
|
SMgrRelation dstrel;
|
||||||
|
@ -8886,6 +8885,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_class rd_rel;
|
Form_pg_class rd_rel;
|
||||||
ForkNumber forkNum;
|
ForkNumber forkNum;
|
||||||
|
List *reltoastidxids = NIL;
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need lock here in case we are recursing to toast table or index
|
* 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")));
|
errmsg("cannot move temporary tables of other sessions")));
|
||||||
|
|
||||||
reltoastrelid = rel->rd_rel->reltoastrelid;
|
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 */
|
/* Get a modifiable copy of the relation's pg_class row */
|
||||||
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
||||||
|
@ -9010,11 +9017,14 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
|
||||||
/* Make sure the reltablespace change is visible */
|
/* Make sure the reltablespace change is visible */
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
/* Move associated toast relation and/or index, too */
|
/* Move associated toast relation and/or indexes, too */
|
||||||
if (OidIsValid(reltoastrelid))
|
if (OidIsValid(reltoastrelid))
|
||||||
ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
|
ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
|
||||||
if (OidIsValid(reltoastidxid))
|
foreach(lc, reltoastidxids)
|
||||||
ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode);
|
ATExecSetTableSpace(lfirst_oid(lc), newTableSpace, lockmode);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
list_free(reltoastidxids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -579,8 +579,8 @@ DefineQueryRewrite(char *rulename,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix pg_class entry to look like a normal view's, including setting
|
* Fix pg_class entry to look like a normal view's, including setting
|
||||||
* the correct relkind and removal of reltoastrelid/reltoastidxid of
|
* the correct relkind and removal of reltoastrelid of the toast table
|
||||||
* the toast table we potentially removed above.
|
* we potentially removed above.
|
||||||
*/
|
*/
|
||||||
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
|
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(event_relid));
|
||||||
if (!HeapTupleIsValid(classTup))
|
if (!HeapTupleIsValid(classTup))
|
||||||
|
@ -592,7 +592,6 @@ DefineQueryRewrite(char *rulename,
|
||||||
classForm->reltuples = 0;
|
classForm->reltuples = 0;
|
||||||
classForm->relallvisible = 0;
|
classForm->relallvisible = 0;
|
||||||
classForm->reltoastrelid = InvalidOid;
|
classForm->reltoastrelid = InvalidOid;
|
||||||
classForm->reltoastidxid = InvalidOid;
|
|
||||||
classForm->relhasindex = false;
|
classForm->relhasindex = false;
|
||||||
classForm->relkind = RELKIND_VIEW;
|
classForm->relkind = RELKIND_VIEW;
|
||||||
classForm->relhasoids = false;
|
classForm->relhasoids = false;
|
||||||
|
|
|
@ -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.
|
* Must not be applied to non-TOAST relations.
|
||||||
*/
|
*/
|
||||||
static int64
|
static int64
|
||||||
|
@ -340,8 +340,9 @@ calculate_toast_table_size(Oid toastrelid)
|
||||||
{
|
{
|
||||||
int64 size = 0;
|
int64 size = 0;
|
||||||
Relation toastRel;
|
Relation toastRel;
|
||||||
Relation toastIdxRel;
|
|
||||||
ForkNumber forkNum;
|
ForkNumber forkNum;
|
||||||
|
ListCell *lc;
|
||||||
|
List *indexlist;
|
||||||
|
|
||||||
toastRel = relation_open(toastrelid, AccessShareLock);
|
toastRel = relation_open(toastrelid, AccessShareLock);
|
||||||
|
|
||||||
|
@ -351,12 +352,21 @@ calculate_toast_table_size(Oid toastrelid)
|
||||||
toastRel->rd_backend, forkNum);
|
toastRel->rd_backend, forkNum);
|
||||||
|
|
||||||
/* toast index size, including FSM and VM size */
|
/* toast index size, including FSM and VM size */
|
||||||
toastIdxRel = relation_open(toastRel->rd_rel->reltoastidxid, AccessShareLock);
|
indexlist = RelationGetIndexList(toastRel);
|
||||||
for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
|
|
||||||
size += calculate_relation_size(&(toastIdxRel->rd_node),
|
|
||||||
toastIdxRel->rd_backend, forkNum);
|
|
||||||
|
|
||||||
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);
|
relation_close(toastRel, AccessShareLock);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
|
|
@ -2778,19 +2778,19 @@ binary_upgrade_set_pg_class_oids(Archive *fout,
|
||||||
PQExpBuffer upgrade_query = createPQExpBuffer();
|
PQExpBuffer upgrade_query = createPQExpBuffer();
|
||||||
PGresult *upgrade_res;
|
PGresult *upgrade_res;
|
||||||
Oid pg_class_reltoastrelid;
|
Oid pg_class_reltoastrelid;
|
||||||
Oid pg_class_reltoastidxid;
|
Oid pg_index_indexrelid;
|
||||||
|
|
||||||
appendPQExpBuffer(upgrade_query,
|
appendPQExpBuffer(upgrade_query,
|
||||||
"SELECT c.reltoastrelid, t.reltoastidxid "
|
"SELECT c.reltoastrelid, i.indexrelid "
|
||||||
"FROM pg_catalog.pg_class c LEFT JOIN "
|
"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;",
|
"WHERE c.oid = '%u'::pg_catalog.oid;",
|
||||||
pg_class_oid);
|
pg_class_oid);
|
||||||
|
|
||||||
upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
|
upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
|
||||||
|
|
||||||
pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
|
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,
|
appendPQExpBuffer(upgrade_buffer,
|
||||||
"\n-- For binary upgrade, must preserve pg_class oids\n");
|
"\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 */
|
/* every toast table has an index */
|
||||||
appendPQExpBuffer(upgrade_buffer,
|
appendPQExpBuffer(upgrade_buffer,
|
||||||
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
|
"SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
|
||||||
pg_class_reltoastidxid);
|
pg_index_indexrelid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -13126,7 +13126,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
||||||
* attislocal correctly, plus fix up any inherited CHECK constraints.
|
* attislocal correctly, plus fix up any inherited CHECK constraints.
|
||||||
* Analogously, we set up typed tables using ALTER TABLE / OF here.
|
* 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) )
|
tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
|
||||||
{
|
{
|
||||||
for (j = 0; j < tbinfo->numatts; j++)
|
for (j = 0; j < tbinfo->numatts; j++)
|
||||||
|
@ -13151,7 +13151,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
||||||
else
|
else
|
||||||
appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
|
appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
|
||||||
fmtId(tbinfo->dobj.name));
|
fmtId(tbinfo->dobj.name));
|
||||||
|
|
||||||
appendPQExpBuffer(q, "DROP COLUMN %s;\n",
|
appendPQExpBuffer(q, "DROP COLUMN %s;\n",
|
||||||
fmtId(tbinfo->attnames[j]));
|
fmtId(tbinfo->attnames[j]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
|
#include "storage/lock.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This enables de-toasting of index entries. Needed until VACUUM is
|
* 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);
|
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 */
|
#endif /* TUPTOASTER_H */
|
||||||
|
|
|
@ -53,6 +53,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201306121
|
#define CATALOG_VERSION_NO 201307031
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
int32 relallvisible; /* # of all-visible blocks (not always
|
||||||
* up-to-date) */
|
* up-to-date) */
|
||||||
Oid reltoastrelid; /* OID of toast table; 0 if none */
|
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 relhasindex; /* T if has (or has had) any indexes */
|
||||||
bool relisshared; /* T if shared across databases */
|
bool relisshared; /* T if shared across databases */
|
||||||
char relpersistence; /* see RELPERSISTENCE_xxx constants below */
|
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_relname 1
|
||||||
#define Anum_pg_class_relnamespace 2
|
#define Anum_pg_class_relnamespace 2
|
||||||
#define Anum_pg_class_reltype 3
|
#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_reltuples 10
|
||||||
#define Anum_pg_class_relallvisible 11
|
#define Anum_pg_class_relallvisible 11
|
||||||
#define Anum_pg_class_reltoastrelid 12
|
#define Anum_pg_class_reltoastrelid 12
|
||||||
#define Anum_pg_class_reltoastidxid 13
|
#define Anum_pg_class_relhasindex 13
|
||||||
#define Anum_pg_class_relhasindex 14
|
#define Anum_pg_class_relisshared 14
|
||||||
#define Anum_pg_class_relisshared 15
|
#define Anum_pg_class_relpersistence 15
|
||||||
#define Anum_pg_class_relpersistence 16
|
#define Anum_pg_class_relkind 16
|
||||||
#define Anum_pg_class_relkind 17
|
#define Anum_pg_class_relnatts 17
|
||||||
#define Anum_pg_class_relnatts 18
|
#define Anum_pg_class_relchecks 18
|
||||||
#define Anum_pg_class_relchecks 19
|
#define Anum_pg_class_relhasoids 19
|
||||||
#define Anum_pg_class_relhasoids 20
|
#define Anum_pg_class_relhaspkey 20
|
||||||
#define Anum_pg_class_relhaspkey 21
|
#define Anum_pg_class_relhasrules 21
|
||||||
#define Anum_pg_class_relhasrules 22
|
#define Anum_pg_class_relhastriggers 22
|
||||||
#define Anum_pg_class_relhastriggers 23
|
#define Anum_pg_class_relhassubclass 23
|
||||||
#define Anum_pg_class_relhassubclass 24
|
#define Anum_pg_class_relispopulated 24
|
||||||
#define Anum_pg_class_relispopulated 25
|
#define Anum_pg_class_relfrozenxid 25
|
||||||
#define Anum_pg_class_relfrozenxid 26
|
#define Anum_pg_class_relminmxid 26
|
||||||
#define Anum_pg_class_relminmxid 27
|
#define Anum_pg_class_relacl 27
|
||||||
#define Anum_pg_class_relacl 28
|
#define Anum_pg_class_reloptions 28
|
||||||
#define Anum_pg_class_reloptions 29
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initial contents of pg_class
|
* 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;
|
* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId;
|
||||||
* similarly, "1" in relminmxid stands for FirstMultiXactId
|
* 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("");
|
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("");
|
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("");
|
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("");
|
DESCR("");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -353,14 +353,6 @@ WHERE reltoastrelid != 0 AND
|
||||||
------+---------------
|
------+---------------
|
||||||
(0 rows)
|
(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
|
SELECT ctid, collnamespace
|
||||||
FROM pg_catalog.pg_collation fk
|
FROM pg_catalog.pg_collation fk
|
||||||
WHERE collnamespace != 0 AND
|
WHERE collnamespace != 0 AND
|
||||||
|
|
|
@ -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, +
|
| (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_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_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, +
|
| (sum((pg_stat_get_blocks_fetched(x.indexrelid) - pg_stat_get_blocks_hit(x.indexrelid))))::bigint AS tidx_blks_read, +
|
||||||
| pg_stat_get_blocks_hit(x.oid) AS tidx_blks_hit +
|
| (sum(pg_stat_get_blocks_hit(x.indexrelid)))::bigint AS tidx_blks_hit +
|
||||||
| FROM ((((pg_class c +
|
| FROM ((((pg_class c +
|
||||||
| LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) +
|
| LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) +
|
||||||
| LEFT JOIN pg_class t ON ((c.reltoastrelid = t.oid))) +
|
| 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))) +
|
| LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) +
|
||||||
| WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])) +
|
| 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_sys_indexes | SELECT pg_statio_all_indexes.relid, +
|
||||||
| pg_statio_all_indexes.indexrelid, +
|
| pg_statio_all_indexes.indexrelid, +
|
||||||
| pg_statio_all_indexes.schemaname, +
|
| 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
|
ERROR: column "xmin" does not exist
|
||||||
LINE 1: select xmin, * from fooview;
|
LINE 1: select xmin, * from fooview;
|
||||||
^
|
^
|
||||||
select reltoastrelid, reltoastidxid, relkind, relfrozenxid
|
select reltoastrelid, relkind, relfrozenxid
|
||||||
from pg_class where oid = 'fooview'::regclass;
|
from pg_class where oid = 'fooview'::regclass;
|
||||||
reltoastrelid | reltoastidxid | relkind | relfrozenxid
|
reltoastrelid | relkind | relfrozenxid
|
||||||
---------------+---------------+---------+--------------
|
---------------+---------+--------------
|
||||||
0 | 0 | v | 0
|
0 | v | 0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
drop view fooview;
|
drop view fooview;
|
||||||
|
|
|
@ -177,10 +177,6 @@ SELECT ctid, reltoastrelid
|
||||||
FROM pg_catalog.pg_class fk
|
FROM pg_catalog.pg_class fk
|
||||||
WHERE reltoastrelid != 0 AND
|
WHERE reltoastrelid != 0 AND
|
||||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
|
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
|
SELECT ctid, collnamespace
|
||||||
FROM pg_catalog.pg_collation fk
|
FROM pg_catalog.pg_collation fk
|
||||||
WHERE collnamespace != 0 AND
|
WHERE collnamespace != 0 AND
|
||||||
|
|
|
@ -872,7 +872,7 @@ create rule "_RETURN" as on select to fooview do instead
|
||||||
select * from fooview;
|
select * from fooview;
|
||||||
select xmin, * from fooview; -- fail, views don't have such a column
|
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;
|
from pg_class where oid = 'fooview'::regclass;
|
||||||
|
|
||||||
drop view fooview;
|
drop view fooview;
|
||||||
|
|
|
@ -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.relam => pg_catalog.pg_am.oid
|
||||||
Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.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.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.collnamespace => pg_catalog.pg_namespace.oid
|
||||||
Join pg_catalog.pg_collation.collowner => pg_catalog.pg_authid.oid
|
Join pg_catalog.pg_collation.collowner => pg_catalog.pg_authid.oid
|
||||||
Join pg_catalog.pg_constraint.connamespace => pg_catalog.pg_namespace.oid
|
Join pg_catalog.pg_constraint.connamespace => pg_catalog.pg_namespace.oid
|
||||||
|
|
Loading…
Reference in New Issue