A pg_depend entry between a partitioned table and its table access
method was missing when using CREATE TABLE .. USING with an unpinned
access method. DROP ACCESS METHOD could be used, while it should be
blocked if CASCADE is not specified, even if there was a partitioned
table that depends on the table access method. pg_class.relam would
then hold an orphaned OID value still pointing to the AM dropped.
The problem is fixed by adding a dependency between the partitioned
table and its table access method if set when the relation is created.
A test checking the contents of pg_depend in this case is added.
Issue introduced in
374c7a229042, that has added support for CREATE
TABLE .. USING for partitioned tables.
Reviewed-by: Alexander Lakhin
Discussion: https://postgr.es/m/18674-
1ef01eceec278fab@postgresql.org
Backpatch-through: 17
* access method is.
*
* No need to add an explicit dependency for the toast table, as the
- * main table depends on it.
+ * main table depends on it. Partitioned tables may not have an
+ * access method set.
*/
- if (RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE)
+ if ((RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE) ||
+ (relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)))
{
ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
add_exact_object_address(&referenced, addrs);
ERROR: cannot have multiple SET ACCESS METHOD subcommands
DROP MATERIALIZED VIEW heapmv;
DROP TABLE heaptable;
+-- Partitioned table with USING
+CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x) USING heap2;
+SELECT pg_describe_object(classid, objid, objsubid) AS obj,
+ pg_describe_object(refclassid, refobjid, refobjsubid) as refobj
+ FROM pg_depend, pg_am
+ WHERE pg_depend.refclassid = 'pg_am'::regclass
+ AND pg_am.oid = pg_depend.refobjid
+ AND pg_depend.objid = 'am_partitioned'::regclass;
+ obj | refobj
+----------------------+---------------------
+ table am_partitioned | access method heap2
+(1 row)
+
+DROP TABLE am_partitioned;
-- Partition hierarchies with access methods
BEGIN;
SET LOCAL default_table_access_method = 'heap';
DROP MATERIALIZED VIEW heapmv;
DROP TABLE heaptable;
+-- Partitioned table with USING
+CREATE TABLE am_partitioned(x INT, y INT) PARTITION BY hash (x) USING heap2;
+SELECT pg_describe_object(classid, objid, objsubid) AS obj,
+ pg_describe_object(refclassid, refobjid, refobjsubid) as refobj
+ FROM pg_depend, pg_am
+ WHERE pg_depend.refclassid = 'pg_am'::regclass
+ AND pg_am.oid = pg_depend.refobjid
+ AND pg_depend.objid = 'am_partitioned'::regclass;
+DROP TABLE am_partitioned;
+
-- Partition hierarchies with access methods
BEGIN;
SET LOCAL default_table_access_method = 'heap';