diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b3ed69457fc..7612e9a3f86 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -20797,13 +20797,14 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, Relation partRel; ObjectAddress address; Oid defaultPartOid; + PartitionDesc partdesc; /* * We must lock the default partition, because detaching this partition * will change its partition constraint. */ - defaultPartOid = - get_default_oid_from_partdesc(RelationGetPartitionDesc(rel, true)); + partdesc = RelationGetPartitionDesc(rel, true); + defaultPartOid = get_default_oid_from_partdesc(partdesc); if (OidIsValid(defaultPartOid)) { /* @@ -20872,8 +20873,19 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, /* * Add a new constraint to the partition being detached, which * supplants the partition constraint (unless there is one already). + * + * In stable branches, we currently skip adding this constraint + * for hash partitions. The reason is to avoid leaving behind + * OID-dependent check constraints referencing the parent table's OID, + * which could lead to unexpected errors(e.g. Could not open relation + * with OID xxxx). + * + * For other partitioning strategies, we keep the previous behavior + * to prevent breaking existing workloads that might rely on the + * absence of such constraints. */ - DetachAddConstraintIfNeeded(wqueue, partRel); + if (partdesc->boundinfo->strategy != PARTITION_STRATEGY_HASH) + DetachAddConstraintIfNeeded(wqueue, partRel); /* * We're almost done now; the only traces that remain are the diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 476266e3f4b..fd5b1b35bda 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4487,6 +4487,30 @@ Check constraints: "part_rp100_a_check" CHECK (a >= 123 AND a < 133 AND a IS NOT NULL) DROP TABLE range_parted2; +CREATE TABLE hash_parted2 ( + a int +) PARTITION BY HASH(a); +CREATE TABLE part_hp PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 2, REMAINDER 0); +ALTER TABLE hash_parted2 DETACH PARTITION part_hp CONCURRENTLY; +\d+ hash_parted2 + Partitioned table "public.hash_parted2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------+---------+-----------+----------+---------+---------+--------------+------------- + a | integer | | | | plain | | +Partition key: HASH (a) +Number of partitions: 0 + +-- constraint should not be created +\d part_hp + Table "public.part_hp" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + +DROP TABLE hash_parted2; +-- work fine +INSERT INTO part_hp VALUES (1); +DROP TABLE part_hp; -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent ALTER TABLE ONLY list_parted2 ADD COLUMN c int; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 5ce9d1e429f..06d4a8be60f 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2832,6 +2832,19 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY; \d part_rp100 DROP TABLE range_parted2; +CREATE TABLE hash_parted2 ( + a int +) PARTITION BY HASH(a); +CREATE TABLE part_hp PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 2, REMAINDER 0); +ALTER TABLE hash_parted2 DETACH PARTITION part_hp CONCURRENTLY; +\d+ hash_parted2 +-- constraint should not be created +\d part_hp +DROP TABLE hash_parted2; +-- work fine +INSERT INTO part_hp VALUES (1); +DROP TABLE part_hp; + -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent