@@ -574,7 +574,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
574
574
heap_close (OldHeap , NoLock );
575
575
576
576
/* Create the transient table that will receive the re-ordered data */
577
- OIDNewHeap = make_new_heap (tableOid , tableSpace , false,
577
+ OIDNewHeap = make_new_heap (tableOid , tableSpace ,
578
+ OldHeap -> rd_rel -> relpersistence ,
578
579
AccessExclusiveLock );
579
580
580
581
/* Copy the heap data into the new table in the desired order */
@@ -595,13 +596,14 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
595
596
* Create the transient table that will be filled with new data during
596
597
* CLUSTER, ALTER TABLE, and similar operations. The transient table
597
598
* duplicates the logical structure of the OldHeap, but is placed in
598
- * NewTableSpace which might be different from OldHeap's.
599
+ * NewTableSpace which might be different from OldHeap's. Also, it's built
600
+ * with the specified persistence, which might differ from the original's.
599
601
*
600
602
* After this, the caller should load the new heap with transferred/modified
601
603
* data, then call finish_heap_swap to complete the operation.
602
604
*/
603
605
Oid
604
- make_new_heap (Oid OIDOldHeap , Oid NewTableSpace , bool forcetemp ,
606
+ make_new_heap (Oid OIDOldHeap , Oid NewTableSpace , char relpersistence ,
605
607
LOCKMODE lockmode )
606
608
{
607
609
TupleDesc OldHeapDesc ;
@@ -613,7 +615,6 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
613
615
Datum reloptions ;
614
616
bool isNull ;
615
617
Oid namespaceid ;
616
- char relpersistence ;
617
618
618
619
OldHeap = heap_open (OIDOldHeap , lockmode );
619
620
OldHeapDesc = RelationGetDescr (OldHeap );
@@ -636,16 +637,10 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
636
637
if (isNull )
637
638
reloptions = (Datum ) 0 ;
638
639
639
- if (forcetemp )
640
- {
640
+ if (relpersistence == RELPERSISTENCE_TEMP )
641
641
namespaceid = LookupCreationNamespace ("pg_temp" );
642
- relpersistence = RELPERSISTENCE_TEMP ;
643
- }
644
642
else
645
- {
646
643
namespaceid = RelationGetNamespace (OldHeap );
647
- relpersistence = OldHeap -> rd_rel -> relpersistence ;
648
- }
649
644
650
645
/*
651
646
* Create the new heap, using a temporary name in the same namespace as
@@ -1109,8 +1104,10 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
1109
1104
/*
1110
1105
* Swap the physical files of two given relations.
1111
1106
*
1112
- * We swap the physical identity (reltablespace and relfilenode) while
1113
- * keeping the same logical identities of the two relations.
1107
+ * We swap the physical identity (reltablespace, relfilenode) while keeping the
1108
+ * same logical identities of the two relations. relpersistence is also
1109
+ * swapped, which is critical since it determines where buffers live for each
1110
+ * relation.
1114
1111
*
1115
1112
* We can swap associated TOAST data in either of two ways: recursively swap
1116
1113
* the physical content of the toast tables (and their indexes), or swap the
@@ -1146,6 +1143,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
1146
1143
Oid relfilenode1 ,
1147
1144
relfilenode2 ;
1148
1145
Oid swaptemp ;
1146
+ char swptmpchr ;
1149
1147
CatalogIndexState indstate ;
1150
1148
1151
1149
/* We need writable copies of both pg_class tuples. */
@@ -1166,7 +1164,10 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
1166
1164
1167
1165
if (OidIsValid (relfilenode1 ) && OidIsValid (relfilenode2 ))
1168
1166
{
1169
- /* Normal non-mapped relations: swap relfilenodes and reltablespaces */
1167
+ /*
1168
+ * Normal non-mapped relations: swap relfilenodes, reltablespaces,
1169
+ * relpersistence
1170
+ */
1170
1171
Assert (!target_is_pg_class );
1171
1172
1172
1173
swaptemp = relform1 -> relfilenode ;
@@ -1177,6 +1178,10 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
1177
1178
relform1 -> reltablespace = relform2 -> reltablespace ;
1178
1179
relform2 -> reltablespace = swaptemp ;
1179
1180
1181
+ swptmpchr = relform1 -> relpersistence ;
1182
+ relform1 -> relpersistence = relform2 -> relpersistence ;
1183
+ relform2 -> relpersistence = swptmpchr ;
1184
+
1180
1185
/* Also swap toast links, if we're swapping by links */
1181
1186
if (!swap_toast_by_content )
1182
1187
{
@@ -1196,15 +1201,18 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
1196
1201
NameStr (relform1 -> relname ));
1197
1202
1198
1203
/*
1199
- * We can't change the tablespace of a mapped rel, and we can't handle
1200
- * toast link swapping for one either, because we must not apply any
1201
- * critical changes to its pg_class row. These cases should be
1202
- * prevented by upstream permissions tests, so this check is a
1203
- * non-user-facing emergency backstop.
1204
+ * We can't change the tablespace nor persistence of a mapped rel, and
1205
+ * we can't handle toast link swapping for one either, because we must
1206
+ * not apply any critical changes to its pg_class row. These cases
1207
+ * should be prevented by upstream permissions tests, so these checks
1208
+ * are non-user-facing emergency backstop.
1204
1209
*/
1205
1210
if (relform1 -> reltablespace != relform2 -> reltablespace )
1206
1211
elog (ERROR , "cannot change tablespace of mapped relation \"%s\"" ,
1207
1212
NameStr (relform1 -> relname ));
1213
+ if (relform1 -> relpersistence != relform2 -> relpersistence )
1214
+ elog (ERROR , "cannot change persistence of mapped relation \"%s\"" ,
1215
+ NameStr (relform1 -> relname ));
1208
1216
if (!swap_toast_by_content &&
1209
1217
(relform1 -> reltoastrelid || relform2 -> reltoastrelid ))
1210
1218
elog (ERROR , "cannot swap toast by links for mapped relation \"%s\"" ,
0 commit comments