@ -3037,6 +3037,113 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass)
table_close ( relationRelation , RowExclusiveLock ) ;
}
/*
* CheckRelationTableSpaceMove
* Check if relation can be moved to new tablespace .
*
* NOTE : Caller must be holding an appropriate lock on the relation .
* ShareUpdateExclusiveLock is sufficient .
*
* Returns true if the relation can be moved to the new tablespace ;
* false otherwise .
*/
bool
CheckRelationTableSpaceMove ( Relation rel , Oid newTableSpaceId )
{
Oid oldTableSpaceId ;
/*
* No work if no change in tablespace . Note that MyDatabaseTableSpace is
* stored as 0.
*/
oldTableSpaceId = rel - > rd_rel - > reltablespace ;
if ( newTableSpaceId = = oldTableSpaceId | |
( newTableSpaceId = = MyDatabaseTableSpace & & oldTableSpaceId = = 0 ) )
return false ;
/*
* We cannot support moving mapped relations into different tablespaces .
* ( In particular this eliminates all shared catalogs . )
*/
if ( RelationIsMapped ( rel ) )
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " cannot move system relation \" %s \" " ,
RelationGetRelationName ( rel ) ) ) ) ;
/* Cannot move a non-shared relation into pg_global */
if ( newTableSpaceId = = GLOBALTABLESPACE_OID )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " only shared relations can be placed in pg_global tablespace " ) ) ) ;
/*
* Do not allow moving temp tables of other backends . . . their local
* buffer manager is not going to cope .
*/
if ( RELATION_IS_OTHER_TEMP ( rel ) )
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " cannot move temporary tables of other sessions " ) ) ) ;
return true ;
}
/*
* SetRelationTableSpace
* Set new reltablespace and relfilenode in pg_class entry .
*
* newTableSpaceId is the new tablespace for the relation , and
* newRelFileNode its new filenode . If newrelfilenode is InvalidOid ,
* this field is not updated .
*
* NOTE : Caller must be holding an appropriate lock on the relation .
* ShareUpdateExclusiveLock is sufficient .
*
* The caller of this routine had better check if a relation can be
* moved to this new tablespace by calling CheckRelationTableSpaceMove ( )
* first , and is responsible for making the change visible with
* CommandCounterIncrement ( ) .
*/
void
SetRelationTableSpace ( Relation rel ,
Oid newTableSpaceId ,
Oid newRelFileNode )
{
Relation pg_class ;
HeapTuple tuple ;
Form_pg_class rd_rel ;
Oid reloid = RelationGetRelid ( rel ) ;
Assert ( CheckRelationTableSpaceMove ( rel , newTableSpaceId ) ) ;
/* Get a modifiable copy of the relation's pg_class row. */
pg_class = table_open ( RelationRelationId , RowExclusiveLock ) ;
tuple = SearchSysCacheCopy1 ( RELOID , ObjectIdGetDatum ( reloid ) ) ;
if ( ! HeapTupleIsValid ( tuple ) )
elog ( ERROR , " cache lookup failed for relation %u " , reloid ) ;
rd_rel = ( Form_pg_class ) GETSTRUCT ( tuple ) ;
/* Update the pg_class row. */
rd_rel - > reltablespace = ( newTableSpaceId = = MyDatabaseTableSpace ) ?
InvalidOid : newTableSpaceId ;
if ( OidIsValid ( newRelFileNode ) )
rd_rel - > relfilenode = newRelFileNode ;
CatalogTupleUpdate ( pg_class , & tuple - > t_self , tuple ) ;
/*
* Record dependency on tablespace . This is only required for relations
* that have no physical storage .
*/
if ( ! RELKIND_HAS_STORAGE ( rel - > rd_rel - > relkind ) )
changeDependencyOnTablespace ( RelationRelationId , reloid ,
rd_rel - > reltablespace ) ;
heap_freetuple ( tuple ) ;
table_close ( pg_class , RowExclusiveLock ) ;
}
/*
* renameatt_check - basic sanity checks before attribute rename
*/
@ -13160,13 +13267,9 @@ static void
ATExecSetTableSpace ( Oid tableOid , Oid newTableSpace , LOCKMODE lockmode )
{
Relation rel ;
Oid oldTableSpace ;
Oid reltoastrelid ;
Oid newrelfilenode ;
RelFileNode newrnode ;
Relation pg_class ;
HeapTuple tuple ;
Form_pg_class rd_rel ;
List * reltoastidxids = NIL ;
ListCell * lc ;
@ -13175,45 +13278,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
*/
rel = relation_open ( tableOid , lockmode ) ;
/*
* No work if no change in tablespace .
*/
oldTableSpace = rel - > rd_rel - > reltablespace ;
if ( newTableSpace = = oldTableSpace | |
( newTableSpace = = MyDatabaseTableSpace & & oldTableSpace = = 0 ) )
/* Check first if relation can be moved to new tablespace */
if ( ! CheckRelationTableSpaceMove ( rel , newTableSpace ) )
{
InvokeObjectPostAlterHook ( RelationRelationId ,
RelationGetRelid ( rel ) , 0 ) ;
relation_close ( rel , NoLock ) ;
return ;
}
/*
* We cannot support moving mapped relations into different tablespaces .
* ( In particular this eliminates all shared catalogs . )
*/
if ( RelationIsMapped ( rel ) )
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " cannot move system relation \" %s \" " ,
RelationGetRelationName ( rel ) ) ) ) ;
/* Can't move a non-shared relation into pg_global */
if ( newTableSpace = = GLOBALTABLESPACE_OID )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " only shared relations can be placed in pg_global tablespace " ) ) ) ;
/*
* Don ' t allow moving temp tables of other backends . . . their local buffer
* manager is not going to cope .
*/
if ( RELATION_IS_OTHER_TEMP ( rel ) )
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
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 ) )
@ -13224,14 +13297,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
relation_close ( toastRel , lockmode ) ;
}
/* Get a modifiable copy of the relation's pg_class row */
pg_class = table_open ( RelationRelationId , RowExclusiveLock ) ;
tuple = SearchSysCacheCopy1 ( RELOID , ObjectIdGetDatum ( tableOid ) ) ;
if ( ! HeapTupleIsValid ( tuple ) )
elog ( ERROR , " cache lookup failed for relation %u " , tableOid ) ;
rd_rel = ( Form_pg_class ) GETSTRUCT ( tuple ) ;
/*
* Relfilenodes are not unique in databases across tablespaces , so we need
* to allocate a new one in the new tablespace .
@ -13262,18 +13327,13 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
*
* NB : This wouldn ' t work if ATExecSetTableSpace ( ) were allowed to be
* executed on pg_class or its indexes ( the above copy wouldn ' t contain
* the updated pg_class entry ) , but that ' s forbidden above .
* the updated pg_class entry ) , but that ' s forbidden with
* CheckRelationTableSpaceMove ( ) .
*/
rd_rel - > reltablespace = ( newTableSpace = = MyDatabaseTableSpace ) ? InvalidOid : newTableSpace ;
rd_rel - > relfilenode = newrelfilenode ;
CatalogTupleUpdate ( pg_class , & tuple - > t_self , tuple ) ;
SetRelationTableSpace ( rel , newTableSpace , newrelfilenode ) ;
InvokeObjectPostAlterHook ( RelationRelationId , RelationGetRelid ( rel ) , 0 ) ;
heap_freetuple ( tuple ) ;
table_close ( pg_class , RowExclusiveLock ) ;
RelationAssumeNewRelfilenode ( rel ) ;
relation_close ( rel , NoLock ) ;
@ -13301,56 +13361,25 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
static void
ATExecSetTableSpaceNoStorage ( Relation rel , Oid newTableSpace )
{
HeapTuple tuple ;
Oid oldTableSpace ;
Relation pg_class ;
Form_pg_class rd_rel ;
Oid reloid = RelationGetRelid ( rel ) ;
/*
* Shouldn ' t be called on relations having storage ; these are processed in
* phase 3.
*/
Assert ( ! RELKIND_HAS_STORAGE ( rel - > rd_rel - > relkind ) ) ;
/* Can't allow a non-shared relation in pg_global */
if ( newTableSpace = = GLOBALTABLESPACE_OID )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " only shared relations can be placed in pg_global tablespace " ) ) ) ;
/*
* No work if no change in tablespace .
*/
oldTableSpace = rel - > rd_rel - > reltablespace ;
if ( newTableSpace = = oldTableSpace | |
( newTableSpace = = MyDatabaseTableSpace & & oldTableSpace = = 0 ) )
/* check if relation can be moved to its new tablespace */
if ( ! CheckRelationTableSpaceMove ( rel , newTableSpace ) )
{
InvokeObjectPostAlterHook ( RelationRelationId , reloid , 0 ) ;
InvokeObjectPostAlterHook ( RelationRelationId ,
RelationGetRelid ( rel ) ,
0 ) ;
return ;
}
/* Get a modifiable copy of the relation's pg_class row */
pg_class = table_open ( RelationRelationId , RowExclusiveLock ) ;
tuple = SearchSysCacheCopy1 ( RELOID , ObjectIdGetDatum ( reloid ) ) ;
if ( ! HeapTupleIsValid ( tuple ) )
elog ( ERROR , " cache lookup failed for relation %u " , reloid ) ;
rd_rel = ( Form_pg_class ) GETSTRUCT ( tuple ) ;
/* update the pg_class row */
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 ) ;
/* Update can be done, so change reltablespace */
SetRelationTableSpace ( rel , newTableSpace , InvalidOid ) ;
heap_freetuple ( tuple ) ;
table_close ( pg_class , RowExclusiveLock ) ;
InvokeObjectPostAlterHook ( RelationRelationId , RelationGetRelid ( rel ) , 0 ) ;
/* Make sure the reltablespace change is visible */
CommandCounterIncrement ( ) ;