Commit 807ae415 authored by Alvaro Herrera's avatar Alvaro Herrera

Don't create relfilenode for relations without storage

Some relation kinds had relfilenode set to some non-zero value, but
apparently the actual files did not really exist because creation was
prevented elsewhere.  Get rid of the phony pg_class.relfilenode values.

Catversion bumped, but only because the sanity_test check will fail if
run in a system initdb'd with the previous version.

Reviewed-by: Kyotaro HORIGUCHI, Michael Paquier
Discussion: https://postgr.es/m/20181206215552.fm2ypuxq6nhpwjuc@alvherre.pgsql
parent df5be637
...@@ -324,35 +324,25 @@ heap_create(const char *relname, ...@@ -324,35 +324,25 @@ heap_create(const char *relname,
get_namespace_name(relnamespace), relname), get_namespace_name(relnamespace), relname),
errdetail("System catalog modifications are currently disallowed."))); errdetail("System catalog modifications are currently disallowed.")));
/* /* Handle reltablespace for specific relkinds. */
* Decide if we need storage or not, and handle a couple other special
* cases for particular relkinds.
*/
switch (relkind) switch (relkind)
{ {
case RELKIND_VIEW: case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE: case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE: case RELKIND_FOREIGN_TABLE:
create_storage = false;
/* /*
* Force reltablespace to zero if the relation has no physical * Force reltablespace to zero if the relation has no physical
* storage. This is mainly just for cleanliness' sake. * storage. This is mainly just for cleanliness' sake.
*
* Partitioned tables and indexes don't have physical storage
* either, but we want to keep their tablespace settings so that
* their children can inherit it.
*/ */
reltablespace = InvalidOid; reltablespace = InvalidOid;
break; break;
case RELKIND_PARTITIONED_TABLE:
case RELKIND_PARTITIONED_INDEX:
/*
* For partitioned tables and indexes, preserve tablespace so that
* it's used as the tablespace for future partitions.
*/
create_storage = false;
break;
case RELKIND_SEQUENCE: case RELKIND_SEQUENCE:
create_storage = true;
/* /*
* Force reltablespace to zero for sequences, since we don't * Force reltablespace to zero for sequences, since we don't
...@@ -361,19 +351,21 @@ heap_create(const char *relname, ...@@ -361,19 +351,21 @@ heap_create(const char *relname,
reltablespace = InvalidOid; reltablespace = InvalidOid;
break; break;
default: default:
create_storage = true;
break; break;
} }
/* /*
* Unless otherwise requested, the physical ID (relfilenode) is initially * Decide whether to create storage. If caller passed a valid relfilenode,
* the same as the logical ID (OID). When the caller did specify a * storage is already created, so don't do it here. Also don't create it
* relfilenode, it already exists; do not attempt to create it. * for relkinds without physical storage.
*/ */
if (OidIsValid(relfilenode)) if (!RELKIND_HAS_STORAGE(relkind) || OidIsValid(relfilenode))
create_storage = false; create_storage = false;
else else
{
create_storage = true;
relfilenode = relid; relfilenode = relid;
}
/* /*
* Never allow a pg_class entry to explicitly specify the database's * Never allow a pg_class entry to explicitly specify the database's
......
...@@ -1253,6 +1253,10 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) ...@@ -1253,6 +1253,10 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
static void static void
RelationInitPhysicalAddr(Relation relation) RelationInitPhysicalAddr(Relation relation)
{ {
/* these relations kinds never have storage */
if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
return;
if (relation->rd_rel->reltablespace) if (relation->rd_rel->reltablespace)
relation->rd_node.spcNode = relation->rd_rel->reltablespace; relation->rd_node.spcNode = relation->rd_rel->reltablespace;
else else
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201901031 #define CATALOG_VERSION_NO 201901041
#endif #endif
...@@ -450,13 +450,12 @@ typedef struct ViewOptions ...@@ -450,13 +450,12 @@ typedef struct ViewOptions
/* /*
* RelationIsMapped * RelationIsMapped
* True if the relation uses the relfilenode map. * True if the relation uses the relfilenode map. Note multiple eval
* * of argument!
* NB: this is only meaningful for relkinds that have storage, else it
* will misleadingly say "true".
*/ */
#define RelationIsMapped(relation) \ #define RelationIsMapped(relation) \
((relation)->rd_rel->relfilenode == InvalidOid) (RELKIND_HAS_STORAGE((relation)->rd_rel->relkind) && \
((relation)->rd_rel->relfilenode == InvalidOid))
/* /*
* RelationOpenSmgr * RelationOpenSmgr
......
...@@ -224,3 +224,12 @@ SELECT relname, nspname ...@@ -224,3 +224,12 @@ SELECT relname, nspname
---------+--------- ---------+---------
(0 rows) (0 rows)
-- check that relations without storage don't have relfilenode
SELECT relname, relkind
FROM pg_class
WHERE relkind IN ('v', 'c', 'f', 'p', 'I')
AND relfilenode <> 0;
relname | relkind
---------+---------
(0 rows)
...@@ -31,3 +31,9 @@ SELECT relname, nspname ...@@ -31,3 +31,9 @@ SELECT relname, nspname
AND NOT EXISTS (SELECT 1 FROM pg_index i WHERE indrelid = c.oid AND NOT EXISTS (SELECT 1 FROM pg_index i WHERE indrelid = c.oid
AND indkey[0] = a.attnum AND indnatts = 1 AND indkey[0] = a.attnum AND indnatts = 1
AND indisunique AND indimmediate); AND indisunique AND indimmediate);
-- check that relations without storage don't have relfilenode
SELECT relname, relkind
FROM pg_class
WHERE relkind IN ('v', 'c', 'f', 'p', 'I')
AND relfilenode <> 0;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment