@@ -574,7 +574,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
574574 heap_close (OldHeap , NoLock );
575575
576576 /* 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 ,
578579 AccessExclusiveLock );
579580
580581 /* Copy the heap data into the new table in the desired order */
@@ -595,13 +596,14 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose)
595596 * Create the transient table that will be filled with new data during
596597 * CLUSTER, ALTER TABLE, and similar operations. The transient table
597598 * 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.
599601 *
600602 * After this, the caller should load the new heap with transferred/modified
601603 * data, then call finish_heap_swap to complete the operation.
602604 */
603605Oid
604- make_new_heap (Oid OIDOldHeap , Oid NewTableSpace , bool forcetemp ,
606+ make_new_heap (Oid OIDOldHeap , Oid NewTableSpace , char relpersistence ,
605607 LOCKMODE lockmode )
606608{
607609 TupleDesc OldHeapDesc ;
@@ -613,7 +615,6 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
613615 Datum reloptions ;
614616 bool isNull ;
615617 Oid namespaceid ;
616- char relpersistence ;
617618
618619 OldHeap = heap_open (OIDOldHeap , lockmode );
619620 OldHeapDesc = RelationGetDescr (OldHeap );
@@ -636,16 +637,10 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, bool forcetemp,
636637 if (isNull )
637638 reloptions = (Datum ) 0 ;
638639
639- if (forcetemp )
640- {
640+ if (relpersistence == RELPERSISTENCE_TEMP )
641641 namespaceid = LookupCreationNamespace ("pg_temp" );
642- relpersistence = RELPERSISTENCE_TEMP ;
643- }
644642 else
645- {
646643 namespaceid = RelationGetNamespace (OldHeap );
647- relpersistence = OldHeap -> rd_rel -> relpersistence ;
648- }
649644
650645 /*
651646 * 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,
11091104/*
11101105 * Swap the physical files of two given relations.
11111106 *
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.
11141111 *
11151112 * We can swap associated TOAST data in either of two ways: recursively swap
11161113 * 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,
11461143 Oid relfilenode1 ,
11471144 relfilenode2 ;
11481145 Oid swaptemp ;
1146+ char swptmpchr ;
11491147 CatalogIndexState indstate ;
11501148
11511149 /* 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,
11661164
11671165 if (OidIsValid (relfilenode1 ) && OidIsValid (relfilenode2 ))
11681166 {
1169- /* Normal non-mapped relations: swap relfilenodes and reltablespaces */
1167+ /*
1168+ * Normal non-mapped relations: swap relfilenodes, reltablespaces,
1169+ * relpersistence
1170+ */
11701171 Assert (!target_is_pg_class );
11711172
11721173 swaptemp = relform1 -> relfilenode ;
@@ -1177,6 +1178,10 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
11771178 relform1 -> reltablespace = relform2 -> reltablespace ;
11781179 relform2 -> reltablespace = swaptemp ;
11791180
1181+ swptmpchr = relform1 -> relpersistence ;
1182+ relform1 -> relpersistence = relform2 -> relpersistence ;
1183+ relform2 -> relpersistence = swptmpchr ;
1184+
11801185 /* Also swap toast links, if we're swapping by links */
11811186 if (!swap_toast_by_content )
11821187 {
@@ -1196,15 +1201,18 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
11961201 NameStr (relform1 -> relname ));
11971202
11981203 /*
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.
12041209 */
12051210 if (relform1 -> reltablespace != relform2 -> reltablespace )
12061211 elog (ERROR , "cannot change tablespace of mapped relation \"%s\"" ,
12071212 NameStr (relform1 -> relname ));
1213+ if (relform1 -> relpersistence != relform2 -> relpersistence )
1214+ elog (ERROR , "cannot change persistence of mapped relation \"%s\"" ,
1215+ NameStr (relform1 -> relname ));
12081216 if (!swap_toast_by_content &&
12091217 (relform1 -> reltoastrelid || relform2 -> reltoastrelid ))
12101218 elog (ERROR , "cannot swap toast by links for mapped relation \"%s\"" ,
0 commit comments