@@ -446,6 +446,7 @@ static bool ATPrepChangePersistence(Relation rel, bool toLogged);
446
446
static void ATPrepSetTableSpace (AlteredTableInfo * tab , Relation rel ,
447
447
const char * tablespacename , LOCKMODE lockmode );
448
448
static void ATExecSetTableSpace (Oid tableOid , Oid newTableSpace , LOCKMODE lockmode );
449
+ static void ATExecPartedIdxSetTableSpace (Relation rel , Oid newTableSpace );
449
450
static void ATExecSetRelOptions (Relation rel , List * defList ,
450
451
AlterTableType operation ,
451
452
LOCKMODE lockmode );
@@ -3845,7 +3846,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
3845
3846
pass = AT_PASS_DROP ;
3846
3847
break ;
3847
3848
case AT_SetTableSpace : /* SET TABLESPACE */
3848
- ATSimplePermissions (rel , ATT_TABLE | ATT_MATVIEW | ATT_INDEX );
3849
+ ATSimplePermissions (rel , ATT_TABLE | ATT_MATVIEW | ATT_INDEX |
3850
+ ATT_PARTITIONED_INDEX );
3849
3851
/* This command never recurses */
3850
3852
ATPrepSetTableSpace (tab , rel , cmd -> name , lockmode );
3851
3853
pass = AT_PASS_MISC ; /* doesn't actually matter */
@@ -4181,10 +4183,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
4181
4183
*/
4182
4184
break ;
4183
4185
case AT_SetTableSpace : /* SET TABLESPACE */
4184
-
4185
4186
/*
4186
- * Nothing to do here; Phase 3 does the work
4187
+ * Only do this for partitioned indexes, for which this is just
4188
+ * a catalog change. Other relation types are handled by Phase 3.
4187
4189
*/
4190
+ if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_INDEX )
4191
+ ATExecPartedIdxSetTableSpace (rel , tab -> newTableSpace );
4192
+
4188
4193
break ;
4189
4194
case AT_SetRelOptions : /* SET (...) */
4190
4195
case AT_ResetRelOptions : /* RESET (...) */
@@ -11049,6 +11054,55 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
11049
11054
list_free (reltoastidxids );
11050
11055
}
11051
11056
11057
+ /*
11058
+ * Special handling of ALTER TABLE SET TABLESPACE for partitioned indexes,
11059
+ * which have no storage (so not handled in Phase 3 like other relation types)
11060
+ */
11061
+ static void
11062
+ ATExecPartedIdxSetTableSpace (Relation rel , Oid newTableSpace )
11063
+ {
11064
+ HeapTuple tuple ;
11065
+ Oid oldTableSpace ;
11066
+ Relation pg_class ;
11067
+ Form_pg_class rd_rel ;
11068
+ Oid indexOid = RelationGetRelid (rel );
11069
+
11070
+ Assert (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_INDEX );
11071
+
11072
+ /*
11073
+ * No work if no change in tablespace.
11074
+ */
11075
+ oldTableSpace = rel -> rd_rel -> reltablespace ;
11076
+ if (newTableSpace == oldTableSpace ||
11077
+ (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0 ))
11078
+ {
11079
+ InvokeObjectPostAlterHook (RelationRelationId ,
11080
+ indexOid , 0 );
11081
+ return ;
11082
+ }
11083
+
11084
+ /* Get a modifiable copy of the relation's pg_class row */
11085
+ pg_class = heap_open (RelationRelationId , RowExclusiveLock );
11086
+
11087
+ tuple = SearchSysCacheCopy1 (RELOID , ObjectIdGetDatum (indexOid ));
11088
+ if (!HeapTupleIsValid (tuple ))
11089
+ elog (ERROR , "cache lookup failed for relation %u" , indexOid );
11090
+ rd_rel = (Form_pg_class ) GETSTRUCT (tuple );
11091
+
11092
+ /* update the pg_class row */
11093
+ rd_rel -> reltablespace = (newTableSpace == MyDatabaseTableSpace ) ? InvalidOid : newTableSpace ;
11094
+ CatalogTupleUpdate (pg_class , & tuple -> t_self , tuple );
11095
+
11096
+ InvokeObjectPostAlterHook (RelationRelationId , indexOid , 0 );
11097
+
11098
+ heap_freetuple (tuple );
11099
+
11100
+ heap_close (pg_class , RowExclusiveLock );
11101
+
11102
+ /* Make sure the reltablespace change is visible */
11103
+ CommandCounterIncrement ();
11104
+ }
11105
+
11052
11106
/*
11053
11107
* Alter Table ALL ... SET TABLESPACE
11054
11108
*
0 commit comments