ALTER TABLE ONLY .. DROP CONSTRAINT on partitioned tables

From: Alvaro Herrera <alvherre(at)alvh(dot)no-ip(dot)org>
To: Pg Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Cc: Amit Langote <amitlangote09(at)gmail(dot)com>, jian he <jian(dot)universality(at)gmail(dot)com>
Subject: ALTER TABLE ONLY .. DROP CONSTRAINT on partitioned tables
Date: 2024-09-26 17:52:03
Message-ID: 202409261752.nbvlawkxsttf@alvherre.pgsql
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello

While studying a review note from Jian He on not-null constraints, I
came across some behavior introduced by commit 9139aa19423b[1] that I
think is mistaken. Consider the following example:

CREATE TABLE parted (a int CONSTRAINT the_check CHECK (a > 0)) PARTITION BY LIST (a);
CREATE TABLE parted_1 PARTITION OF parted FOR VALUES IN (1);
ALTER TABLE ONLY parted DROP CONSTRAINT the_check;

The ALTER TABLE fails with the following message:

ERROR: cannot remove constraint from only the partitioned table when partitions exist
HINT: Do not specify the ONLY keyword.

and the relevant code in ATExecDropConstraint is:

/*
* For a partitioned table, if partitions exist and we are told not to
* recurse, it's a user error. It doesn't make sense to have a constraint
* be defined only on the parent, especially if it's a partitioned table.
*/
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
children != NIL && !recurse)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
errhint("Do not specify the ONLY keyword.")));

Note that the comment here is confused: it talks about a constraint that
would "be defined only on the parent", but that's bogus: the end result
would be that the constraint no longer exist on the parent but would
continue to exist on the children. Indeed it's not entirely
unimaginable that you start with a partitioned table with a bunch of
constraints which are enforced on all partitions, then you later decide
that you want this constraint to apply only to some of the partitions,
not the whole partitioned table. To implement that, you would drop the
constraint on the parent using ONLY, then drop it on a few of the
partitions, but still keep it on the other partitions. This would work
just fine if not for this ereport(ERROR).

Also, you can achieve the same end result by creating the constraint on
only some of the partitions and not on the partitioned table to start
with.

This also applies to ALTER TABLE ONLY ... DROP NOT NULL.

Of course, *adding* a constraint in this fashion is also forbidden, but
that makes perfect sense. Both restrictions were added as part of the
same commit, so I suppose we thought they were symmetrical behaviors and
failed to notice they weren't.

The DROP of such constraints can already be done on a table with legacy
inheritance children; it's just partitioned tables that have this
weirdness.

It doesn't surprise me that nobody has reported this inconsistency,
because it seems an unusual enough situation. For the same reason, I
wouldn't propose to backpatch this change. But I put forward the
attached patch, which removes the ereport(ERROR)s.

[1] Discussion: https://postgr.es/m/7682253a-6f79-6a92-00aa-267c4c412870@lab.ntt.co.jp

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"Here's a general engineering tip: if the non-fun part is too complex for you
to figure out, that might indicate the fun part is too ambitious." (John Naylor)
https://postgr.es/m/CAFBsxsG4OWHBbSDM%3DsSeXrQGOtkPiOEOuME4yD7Ce41NtaAD9g%40mail.gmail.com

Attachment Content-Type Size
0001-Don-t-disallow-DROP-of-constraints-ONLY-on-partition.patch text/x-diff 6.6 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message diPhantxm 2024-09-26 18:30:08 Truncate logs by max_log_size
Previous Message Shayon Mukherjee 2024-09-26 17:39:23 Re: Proposal to Enable/Disable Index using ALTER INDEX