Re: bug, ALTER TABLE call ATPostAlterTypeCleanup twice for the same relation - Mailing list pgsql-hackers

From Chao Li
Subject Re: bug, ALTER TABLE call ATPostAlterTypeCleanup twice for the same relation
Date
Msg-id 173872F1-0EE6-45C5-BB1B-D8DF2E9930F2@gmail.com
Whole thread Raw
In response to Re: bug, ALTER TABLE call ATPostAlterTypeCleanup twice for the same relation  (jian he <jian.universality@gmail.com>)
List pgsql-hackers

> On Oct 13, 2025, at 16:08, jian he <jian.universality@gmail.com> wrote:
>
> On Wed, Oct 1, 2025 at 11:04 AM jian he <jian.universality@gmail.com> wrote:
>>
>> we can simply change from
>>
>>            if (pass == AT_PASS_ALTER_TYPE || pass == AT_PASS_SET_EXPRESSION)
>>                ATPostAlterTypeCleanup(wqueue, tab, lockmode);
>>
>> to
>>            if (pass == AT_PASS_SET_EXPRESSION)
>>                ATPostAlterTypeCleanup(wqueue, tab, lockmode);
>>            else if (pass == AT_PASS_ALTER_TYPE &&
>>                     tab->subcmds[AT_PASS_SET_EXPRESSION] == NIL)
>>                ATPostAlterTypeCleanup(wqueue, tab, lockmode);
>
> That will not work if AT_PASS_ALTER_TYPE triggers the creation of a new
> AT_PASS_SET_EXPRESSION entry.
> For example, consider:
> CREATE TABLE gtest25 (a int, b int GENERATED ALWAYS AS (a * 2) STORED);
>
> If we alter the type of column "a", the column b’s generation
> expression would need
> to be rebuilt (which is currently not supported).  In that case, the current
> logic would not be able to handle it.
>
> I think the correct fix is within ATPostAlterTypeCleanup.
> at the end of ATPostAlterTypeCleanup, we already delete these changed
> objects via
> ``performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL);``
>
> we can just list_free these (the below) objects too:
>    tab->changedConstraintOids
>    tab->changedConstraintDefs
>    tab->changedIndexOids
>    tab->changedIndexDefs
>    tab->changedStatisticsOids
>    tab->changedStatisticsDefs
>
> since this information would become stale if those objects have
> already been dropped.
> <v5-0001-avoid-call-ATPostAlterTypeCleanup-twice.patch>

I think the correct solution should be my proposed v4 that has a fundamental difference from your current change is
that:

* The current implementation as well as your current change, they do ATPostAlterTypeCleanup() in either ALTER_TYPE pass
orSET_EXPRESSION pass. Say a table has columns a and b, and a constraint (a+b>5), then I alter both columns types in a
singlecommand, then it will alter a’s type, then rebuild the constant, and alter b’s type, then rebuild the constraint
again.For the first rebuild, because c’s type has not been updated, the rebuild may potentially fail. 

*  My v4 defers ATPostAlterTypeCleanup() to a later pass, which allows all "set data type” and “set expression” to
finish,then start to rebuild constraints. My v4 does the cleanup in next pass of SET_EXPRESSION, which might not be the
bestsolution, instead, it’s just a quick PoC to demo my idea. Perhaps, we may add a new pass. 

But to handle the complicated case that I described above, v4 is still not enough. All “changedXXXXX” stuffs should be
movedto an upper level of tab. Still using the same example, the constrain depends on both columns an and b, so we
shouldremember the constraint only once. 

WDYT?

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/







pgsql-hackers by date:

Previous
From: torikoshia
Date:
Subject: Re: [Proposal] Expose internal MultiXact member count function for efficient monitoring
Next
From: Chao Li
Date:
Subject: Why cannot alter a column's type when it's used by a generated column