diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/heap.c | 9 | ||||
-rw-r--r-- | src/backend/catalog/pg_shdepend.c | 68 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 4 | ||||
-rw-r--r-- | src/backend/commands/tablespace.c | 12 |
4 files changed, 84 insertions, 9 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 21f2240ade8..9abc4a1f556 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -440,6 +440,15 @@ heap_create(const char *relname, } } + /* + * If a tablespace is specified, removal of that tablespace is normally + * protected by the existence of a physical file; but for relations with + * no files, add a pg_shdepend entry to account for that. + */ + if (!create_storage && reltablespace != InvalidOid) + recordDependencyOnTablespace(RelationRelationId, relid, + reltablespace); + return rel; } diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 86c3be107ff..90b7a5de299 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -59,6 +59,7 @@ #include "commands/schemacmds.h" #include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" +#include "commands/tablespace.h" #include "commands/typecmds.h" #include "miscadmin.h" #include "storage/lmgr.h" @@ -186,11 +187,14 @@ recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner) * * There must be no more than one existing entry for the given dependent * object and dependency type! So in practice this can only be used for - * updating SHARED_DEPENDENCY_OWNER entries, which should have that property. + * updating SHARED_DEPENDENCY_OWNER and SHARED_DEPENDENCY_TABLESPACE + * entries, which should have that property. * * If there is no previous entry, we assume it was referencing a PINned * object, so we create a new entry. If the new referenced object is * PINned, we don't create an entry (and drop the old one, if any). + * (For tablespaces, we don't record dependencies in certain cases, so + * there are other possible reasons for entries to be missing.) * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. @@ -345,6 +349,58 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId) } /* + * recordDependencyOnTablespace + * + * A convenient wrapper of recordSharedDependencyOn -- register the specified + * tablespace as default for the given object. + * + * Note: it's the caller's responsibility to ensure that there isn't a + * tablespace entry for the object already. + */ +void +recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace) +{ + ObjectAddress myself, + referenced; + + ObjectAddressSet(myself, classId, objectId); + ObjectAddressSet(referenced, TableSpaceRelationId, tablespace); + + recordSharedDependencyOn(&myself, &referenced, + SHARED_DEPENDENCY_TABLESPACE); +} + +/* + * changeDependencyOnTablespace + * + * Update the shared dependencies to account for the new tablespace. + * + * Note: we don't need an objsubid argument because only whole objects + * have tablespaces. + */ +void +changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId) +{ + Relation sdepRel; + + sdepRel = table_open(SharedDependRelationId, RowExclusiveLock); + + if (newTablespaceId != DEFAULTTABLESPACE_OID && + newTablespaceId != InvalidOid) + shdepChangeDep(sdepRel, + classId, objectId, 0, + TableSpaceRelationId, newTablespaceId, + SHARED_DEPENDENCY_TABLESPACE); + else + shdepDropDependency(sdepRel, + classId, objectId, 0, true, + InvalidOid, InvalidOid, + SHARED_DEPENDENCY_INVALID); + + table_close(sdepRel, RowExclusiveLock); +} + +/* * getOidListDiff * Helper for updateAclDependencies. * @@ -1121,13 +1177,6 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) objectId))); break; - /* - * Currently, this routine need not support any other shared - * object types besides roles. If we wanted to record explicit - * dependencies on databases or tablespaces, we'd need code along - * these lines: - */ -#ifdef NOT_USED case TableSpaceRelationId: { /* For lack of a syscache on pg_tablespace, do this: */ @@ -1141,7 +1190,6 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) pfree(tablespace); break; } -#endif case DatabaseRelationId: { @@ -1201,6 +1249,8 @@ storeObjectDescription(StringInfo descs, appendStringInfo(descs, _("privileges for %s"), objdesc); else if (deptype == SHARED_DEPENDENCY_POLICY) appendStringInfo(descs, _("target of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_TABLESPACE) + appendStringInfo(descs, _("tablespace for %s"), objdesc); else elog(ERROR, "unrecognized dependency type: %d", (int) deptype); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 993da56d437..fd55bf4ac7d 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13340,6 +13340,10 @@ ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace) rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + /* Record dependency on tablespace */ + changeDependencyOnTablespace(RelationRelationId, + reloid, rd_rel->reltablespace); + InvokeObjectPostAlterHook(RelationRelationId, reloid, 0); heap_freetuple(tuple); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index a9a2db28345..69ea155d502 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -420,6 +420,8 @@ DropTableSpace(DropTableSpaceStmt *stmt) Form_pg_tablespace spcform; ScanKeyData entry[1]; Oid tablespaceoid; + char *detail; + char *detail_log; /* * Find the target tuple @@ -468,6 +470,16 @@ DropTableSpace(DropTableSpaceStmt *stmt) aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_TABLESPACE, tablespacename); + /* Check for pg_shdepend entries depending on this tablespace */ + if (checkSharedDependencies(TableSpaceRelationId, tablespaceoid, + &detail, &detail_log)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("tablespace \"%s\" cannot be dropped because some objects depend on it", + tablespacename), + errdetail_internal("%s", detail), + errdetail_log("%s", detail_log))); + /* DROP hook for the tablespace being removed */ InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0); |