aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/sepgsql/dml.c8
-rw-r--r--src/backend/access/transam/varsup.c2
-rw-r--r--src/backend/catalog/catalog.c102
-rw-r--r--src/backend/catalog/heap.c2
-rw-r--r--src/backend/catalog/pg_publication.c8
-rw-r--r--src/backend/commands/indexcmds.c12
-rw-r--r--src/backend/commands/tablecmds.c5
-rw-r--r--src/backend/utils/cache/relcache.c4
-rw-r--r--src/include/catalog/catalog.h5
9 files changed, 81 insertions, 67 deletions
diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c
index cc934b54afb..2892346f800 100644
--- a/contrib/sepgsql/dml.c
+++ b/contrib/sepgsql/dml.c
@@ -161,12 +161,10 @@ check_relation_privileges(Oid relOid,
*/
if (sepgsql_getenforce() > 0)
{
- Oid relnamespace = get_rel_namespace(relOid);
-
- if (IsSystemNamespace(relnamespace) &&
- (required & (SEPG_DB_TABLE__UPDATE |
+ if ((required & (SEPG_DB_TABLE__UPDATE |
SEPG_DB_TABLE__INSERT |
- SEPG_DB_TABLE__DELETE)) != 0)
+ SEPG_DB_TABLE__DELETE)) != 0 &&
+ IsCatalogRelationOid(relOid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("SELinux: hardwired security policy violation")));
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 788b961ef0e..5b759ec7f3f 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -520,7 +520,7 @@ GetNewObjectId(void)
* Check for wraparound of the OID counter. We *must* not return 0
* (InvalidOid), and in normal operation we mustn't return anything below
* FirstNormalObjectId since that range is reserved for initdb (see
- * IsCatalogClass()). Note we are relying on unsigned comparison.
+ * IsCatalogRelationOid()). Note we are relying on unsigned comparison.
*
* During initdb, we start the OID generator at FirstBootstrapObjectId, so
* we only wrap if before that point when in bootstrap or standalone mode.
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 6d8c7460572..2878e6a5b03 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -53,15 +53,18 @@
/*
* IsSystemRelation
- * True iff the relation is either a system catalog or toast table.
- * By a system catalog, we mean one that created in the pg_catalog schema
- * during initdb. User-created relations in pg_catalog don't count as
- * system catalogs.
+ * True iff the relation is either a system catalog or a toast table.
+ * See IsCatalogRelation for the exact definition of a system catalog.
*
- * NB: TOAST relations are considered system relations by this test
- * for compatibility with the old IsSystemRelationName function.
- * This is appropriate in many places but not all. Where it's not,
- * also check IsToastRelation or use IsCatalogRelation().
+ * We treat toast tables of user relations as "system relations" for
+ * protection purposes, e.g. you can't change their schemas without
+ * special permissions. Therefore, most uses of this function are
+ * checking whether allow_system_table_mods restrictions apply.
+ * For other purposes, consider whether you shouldn't be using
+ * IsCatalogRelation instead.
+ *
+ * This function does not perform any catalog accesses.
+ * Some callers rely on that!
*/
bool
IsSystemRelation(Relation relation)
@@ -78,67 +81,74 @@ IsSystemRelation(Relation relation)
bool
IsSystemClass(Oid relid, Form_pg_class reltuple)
{
- return IsToastClass(reltuple) || IsCatalogClass(relid, reltuple);
+ /* IsCatalogRelationOid is a bit faster, so test that first */
+ return (IsCatalogRelationOid(relid) || IsToastClass(reltuple));
}
/*
* IsCatalogRelation
- * True iff the relation is a system catalog, or the toast table for
- * a system catalog. By a system catalog, we mean one that created
- * in the pg_catalog schema during initdb. As with IsSystemRelation(),
- * user-created relations in pg_catalog don't count as system catalogs.
+ * True iff the relation is a system catalog.
+ *
+ * By a system catalog, we mean one that is created during the bootstrap
+ * phase of initdb. That includes not just the catalogs per se, but
+ * also their indexes, and TOAST tables and indexes if any.
*
- * Note that IsSystemRelation() returns true for ALL toast relations,
- * but this function returns true only for toast relations of system
- * catalogs.
+ * This function does not perform any catalog accesses.
+ * Some callers rely on that!
*/
bool
IsCatalogRelation(Relation relation)
{
- return IsCatalogClass(RelationGetRelid(relation), relation->rd_rel);
+ return IsCatalogRelationOid(RelationGetRelid(relation));
}
/*
- * IsCatalogClass
- * True iff the relation is a system catalog relation.
+ * IsCatalogRelationOid
+ * True iff the relation identified by this OID is a system catalog.
+ *
+ * By a system catalog, we mean one that is created during the bootstrap
+ * phase of initdb. That includes not just the catalogs per se, but
+ * also their indexes, and TOAST tables and indexes if any.
*
- * Check IsCatalogRelation() for details.
+ * This function does not perform any catalog accesses.
+ * Some callers rely on that!
*/
bool
-IsCatalogClass(Oid relid, Form_pg_class reltuple)
+IsCatalogRelationOid(Oid relid)
{
- Oid relnamespace = reltuple->relnamespace;
-
/*
- * Never consider relations outside pg_catalog/pg_toast to be catalog
- * relations.
- */
- if (!IsSystemNamespace(relnamespace) && !IsToastNamespace(relnamespace))
- return false;
-
- /* ----
- * Check whether the oid was assigned during initdb, when creating the
- * initial template database. Minus the relations in information_schema
- * excluded above, these are integral part of the system.
- * We could instead check whether the relation is pinned in pg_depend, but
- * this is noticeably cheaper and doesn't require catalog access.
+ * We consider a relation to be a system catalog if it has an OID that was
+ * manually assigned or assigned by genbki.pl. This includes all the
+ * defined catalogs, their indexes, and their TOAST tables and indexes.
*
- * This test is safe since even an oid wraparound will preserve this
- * property (cf. GetNewObjectId()) and it has the advantage that it works
- * correctly even if a user decides to create a relation in the pg_catalog
- * namespace.
- * ----
+ * This rule excludes the relations in information_schema, which are not
+ * integral to the system and can be treated the same as user relations.
+ * (Since it's valid to drop and recreate information_schema, any rule
+ * that did not act this way would be wrong.)
+ *
+ * This test is reliable since an OID wraparound will skip this range of
+ * OIDs; see GetNewObjectId().
*/
- return relid < FirstNormalObjectId;
+ return (relid < (Oid) FirstBootstrapObjectId);
}
/*
* IsToastRelation
* True iff relation is a TOAST support relation (or index).
+ *
+ * Does not perform any catalog accesses.
*/
bool
IsToastRelation(Relation relation)
{
+ /*
+ * What we actually check is whether the relation belongs to a pg_toast
+ * namespace. This should be equivalent because of restrictions that are
+ * enforced elsewhere against creating user relations in, or moving
+ * relations into/out of, a pg_toast namespace. Notice also that this
+ * will not say "true" for toast tables belonging to other sessions' temp
+ * tables; we expect that other mechanisms will prevent access to those.
+ */
return IsToastNamespace(RelationGetNamespace(relation));
}
@@ -157,14 +167,16 @@ IsToastClass(Form_pg_class reltuple)
}
/*
- * IsSystemNamespace
+ * IsCatalogNamespace
* True iff namespace is pg_catalog.
*
+ * Does not perform any catalog accesses.
+ *
* NOTE: the reason this isn't a macro is to avoid having to include
* catalog/pg_namespace.h in a lot of places.
*/
bool
-IsSystemNamespace(Oid namespaceId)
+IsCatalogNamespace(Oid namespaceId)
{
return namespaceId == PG_CATALOG_NAMESPACE;
}
@@ -173,9 +185,13 @@ IsSystemNamespace(Oid namespaceId)
* IsToastNamespace
* True iff namespace is pg_toast or my temporary-toast-table namespace.
*
+ * Does not perform any catalog accesses.
+ *
* Note: this will return false for temporary-toast-table namespaces belonging
* to other backends. Those are treated the same as other backends' regular
* temp table namespaces, and access is prevented where appropriate.
+ * If you need to check for those, you may be able to use isAnyTempNamespace,
+ * but beware that that does involve a catalog access.
*/
bool
IsToastNamespace(Oid namespaceId)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index ee6b72e550a..6cffe550b31 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -324,7 +324,7 @@ heap_create(const char *relname,
* user defined relation, not a system one.
*/
if (!allow_system_table_mods &&
- ((IsSystemNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
+ ((IsCatalogNamespace(relnamespace) && relkind != RELKIND_INDEX) ||
IsToastNamespace(relnamespace)) &&
IsNormalProcessingMode())
ereport(ERROR,
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index bda7a3e92b0..be0a7e7390a 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -93,14 +93,16 @@ check_publication_add_relation(Relation targetrel)
*
* Note this also excludes all tables with relid < FirstNormalObjectId,
* ie all tables created during initdb. This mainly affects the preinstalled
- * information_schema. (IsCatalogClass() only checks for these inside
- * pg_catalog and toast schemas.)
+ * information_schema. (IsCatalogRelationOid() only excludes tables with
+ * relid < FirstBootstrapObjectId, making that test rather redundant, but
+ * really we should get rid of the FirstNormalObjectId test not
+ * IsCatalogRelationOid.)
*/
static bool
is_publishable_class(Oid relid, Form_pg_class reltuple)
{
return reltuple->relkind == RELKIND_RELATION &&
- !IsCatalogClass(relid, reltuple) &&
+ !IsCatalogRelationOid(relid) &&
reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
relid >= FirstNormalObjectId;
}
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 1db10d23606..dab06e20a83 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2590,15 +2590,11 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
continue;
/*
- * Skip system tables that index_create() would reject to index
- * concurrently. XXX We need the additional check for
- * FirstNormalObjectId to skip information_schema tables, because
- * IsCatalogClass() here does not cover information_schema, but the
- * check in index_create() will error on the TOAST tables of
- * information_schema tables.
+ * Skip system tables, since index_create() would reject indexing them
+ * concurrently (and it would likely fail if we tried).
*/
if (concurrent &&
- (IsCatalogClass(relid, classtuple) || relid < FirstNormalObjectId))
+ IsCatalogRelationOid(relid))
{
if (!concurrent_warning)
ereport(WARNING,
@@ -2842,7 +2838,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
errmsg("concurrent reindex is not supported for shared relations")));
/* A system catalog cannot be reindexed concurrently */
- if (IsSystemNamespace(get_rel_namespace(heapId)))
+ if (IsCatalogRelationOid(heapId))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("concurrent reindex is not supported for catalog relations")));
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 03daa252817..baeb13e6a0c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -12453,9 +12453,10 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
* Also, explicitly avoid any shared tables, temp tables, or TOAST
* (TOAST will be moved with the main table).
*/
- if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
+ if (IsCatalogNamespace(relForm->relnamespace) ||
+ relForm->relisshared ||
isAnyTempNamespace(relForm->relnamespace) ||
- relForm->relnamespace == PG_TOAST_NAMESPACE)
+ IsToastNamespace(relForm->relnamespace))
continue;
/* Only move the object type requested */
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index eaf2b18820e..d0f6f715e6f 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3316,8 +3316,8 @@ RelationBuildLocalRelation(const char *relname,
else
rel->rd_rel->relispopulated = true;
- /* system relations and non-table objects don't have one */
- if (!IsSystemNamespace(relnamespace) &&
+ /* set replica identity -- system catalogs and non-tables don't have one */
+ if (!IsCatalogNamespace(relnamespace) &&
(relkind == RELKIND_RELATION ||
relkind == RELKIND_MATVIEW ||
relkind == RELKIND_PARTITIONED_TABLE))
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index a58d09d6c71..adeba658730 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.h
@@ -24,9 +24,10 @@ extern bool IsCatalogRelation(Relation relation);
extern bool IsSystemClass(Oid relid, Form_pg_class reltuple);
extern bool IsToastClass(Form_pg_class reltuple);
-extern bool IsCatalogClass(Oid relid, Form_pg_class reltuple);
-extern bool IsSystemNamespace(Oid namespaceId);
+extern bool IsCatalogRelationOid(Oid relid);
+
+extern bool IsCatalogNamespace(Oid namespaceId);
extern bool IsToastNamespace(Oid namespaceId);
extern bool IsReservedName(const char *name);