Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 97d8910

Browse files
committed
Fix pg_depend entry to AMs after ALTER TABLE .. SET ACCESS METHOD
ALTER TABLE .. SET ACCESS METHOD was not registering a dependency to the new access method with the relation altered in its rewrite phase, making possible the drop of an access method even if there are relations that depend on it. During the rewrite, a temporary relation is created to build the new relation files before swapping the new and old files, and, while the temporary relation was registering a correct dependency to the new AM, the old relation did not do that. A dependency on the access method is added when the relation files are swapped, which is the point where pg_class is updated. Materialized views and tables use the same code path, hence both were impacted. Backpatch down to 15, where this command has been introduced. Reported-by: Alexander Lakhin Reviewed-by: Nathan Bossart, Andres Freund Discussion: https://postgr.es/m/18000-9145c25b1af475ca@postgresql.org Backpatch-through: 15
1 parent 5f87a02 commit 97d8910

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

src/backend/commands/cluster.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
10701070
relfilenumber2;
10711071
RelFileNumber swaptemp;
10721072
char swptmpchr;
1073+
Oid relam1,
1074+
relam2;
10731075

10741076
/* We need writable copies of both pg_class tuples. */
10751077
relRelation = table_open(RelationRelationId, RowExclusiveLock);
@@ -1086,6 +1088,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
10861088

10871089
relfilenumber1 = relform1->relfilenode;
10881090
relfilenumber2 = relform2->relfilenode;
1091+
relam1 = relform1->relam;
1092+
relam2 = relform2->relam;
10891093

10901094
if (RelFileNumberIsValid(relfilenumber1) &&
10911095
RelFileNumberIsValid(relfilenumber2))
@@ -1257,6 +1261,31 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
12571261
CacheInvalidateRelcacheByTuple(reltup2);
12581262
}
12591263

1264+
/*
1265+
* Now that pg_class has been updated with its relevant information for
1266+
* the swap, update the dependency of the relations to point to their new
1267+
* table AM, if it has changed.
1268+
*/
1269+
if (relam1 != relam2)
1270+
{
1271+
if (changeDependencyFor(RelationRelationId,
1272+
r1,
1273+
AccessMethodRelationId,
1274+
relam1,
1275+
relam2) != 1)
1276+
elog(ERROR, "failed to change access method dependency for relation \"%s.%s\"",
1277+
get_namespace_name(get_rel_namespace(r1)),
1278+
get_rel_name(r1));
1279+
if (changeDependencyFor(RelationRelationId,
1280+
r2,
1281+
AccessMethodRelationId,
1282+
relam2,
1283+
relam1) != 1)
1284+
elog(ERROR, "failed to change access method dependency for relation \"%s.%s\"",
1285+
get_namespace_name(get_rel_namespace(r2)),
1286+
get_rel_name(r2));
1287+
}
1288+
12601289
/*
12611290
* Post alter hook for modified relations. The change to r2 is always
12621291
* internal, but r1 depends on the invocation context.

src/test/regress/expected/create_am.out

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,35 @@ SELECT amname FROM pg_class c, pg_am am
240240
heap
241241
(1 row)
242242

243+
-- Switching to heap2 adds new dependency entry to the AM.
244+
ALTER TABLE heaptable SET ACCESS METHOD heap2;
245+
SELECT pg_describe_object(classid, objid, objsubid) as obj,
246+
pg_describe_object(refclassid, refobjid, refobjsubid) as objref,
247+
deptype
248+
FROM pg_depend
249+
WHERE classid = 'pg_class'::regclass AND
250+
objid = 'heaptable'::regclass
251+
ORDER BY 1, 2;
252+
obj | objref | deptype
253+
-----------------+---------------------+---------
254+
table heaptable | access method heap2 | n
255+
table heaptable | schema public | n
256+
(2 rows)
257+
258+
-- Switching to heap should not have a dependency entry to the AM.
259+
ALTER TABLE heaptable SET ACCESS METHOD heap;
260+
SELECT pg_describe_object(classid, objid, objsubid) as obj,
261+
pg_describe_object(refclassid, refobjid, refobjsubid) as objref,
262+
deptype
263+
FROM pg_depend
264+
WHERE classid = 'pg_class'::regclass AND
265+
objid = 'heaptable'::regclass
266+
ORDER BY 1, 2;
267+
obj | objref | deptype
268+
-----------------+---------------+---------
269+
table heaptable | schema public | n
270+
(1 row)
271+
243272
ALTER TABLE heaptable SET ACCESS METHOD heap2;
244273
SELECT amname FROM pg_class c, pg_am am
245274
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass;

src/test/regress/sql/create_am.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,24 @@ CREATE TABLE heaptable USING heap AS
166166
SELECT a, repeat(a::text, 100) FROM generate_series(1,9) AS a;
167167
SELECT amname FROM pg_class c, pg_am am
168168
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass;
169+
-- Switching to heap2 adds new dependency entry to the AM.
170+
ALTER TABLE heaptable SET ACCESS METHOD heap2;
171+
SELECT pg_describe_object(classid, objid, objsubid) as obj,
172+
pg_describe_object(refclassid, refobjid, refobjsubid) as objref,
173+
deptype
174+
FROM pg_depend
175+
WHERE classid = 'pg_class'::regclass AND
176+
objid = 'heaptable'::regclass
177+
ORDER BY 1, 2;
178+
-- Switching to heap should not have a dependency entry to the AM.
179+
ALTER TABLE heaptable SET ACCESS METHOD heap;
180+
SELECT pg_describe_object(classid, objid, objsubid) as obj,
181+
pg_describe_object(refclassid, refobjid, refobjsubid) as objref,
182+
deptype
183+
FROM pg_depend
184+
WHERE classid = 'pg_class'::regclass AND
185+
objid = 'heaptable'::regclass
186+
ORDER BY 1, 2;
169187
ALTER TABLE heaptable SET ACCESS METHOD heap2;
170188
SELECT amname FROM pg_class c, pg_am am
171189
WHERE c.relam = am.oid AND c.oid = 'heaptable'::regclass;

0 commit comments

Comments
 (0)