[FIX] lift_constraints: drop constraints individually, not in one statement - #462
Draft
quoc-pn wants to merge 1 commit into
Draft
[FIX] lift_constraints: drop constraints individually, not in one statement#462quoc-pn wants to merge 1 commit into
quoc-pn wants to merge 1 commit into
Conversation
legalsylvain
marked this pull request as draft
August 5, 2026 09:33
quoc-pn
marked this pull request as ready for review
August 5, 2026 10:59
quoc-pn
force-pushed
the
fix-lift_constraints-pg17-ordering
branch
from
August 5, 2026 11:11
28ec79d to
532b340
Compare
legalsylvain
marked this pull request as draft
August 5, 2026 12:00
…tement
On PostgreSQL 17+, NOT NULL is catalogued as a named constraint
(<table>_<column>_not_null) instead of an implicit pg_attribute flag.
lift_constraints() dropped all constraints on a column in a single
ALTER TABLE statement (`DROP CONSTRAINT a, DROP CONSTRAINT b, ...`).
PostgreSQL validates each DROP CONSTRAINT subcommand against the
catalog state as it existed before the statement started, not against
the pending effects of earlier subcommands in the same statement. So
when a column has both a not-null constraint and a primary key, and
the not-null constraint is listed before the primary key, PostgreSQL
rejects the statement with:
ERROR: column "id" is in a primary key
even though the very next clause in the same statement would have
dropped that primary key.
Fix by dropping each constraint in its own ALTER TABLE statement
instead of combining them, so there is no cross-clause catalog
dependency for PostgreSQL to complain about.
This alone is not enough: even as separate statements, dropping the
not-null constraint before the primary key still fails with the same
error, since the primary key hasn't been dropped yet at that point.
Order the constraints so the primary key (if any) is dropped first;
dropping it with CASCADE takes the dependent not-null constraint (and
anything else referencing it) down with it, so the remaining
DROP CONSTRAINT IF EXISTS calls become no-ops.
quoc-pn
force-pushed
the
fix-lift_constraints-pg17-ordering
branch
from
August 18, 2026 09:15
532b340 to
19ff019
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
lift_constraints()drops all constraints found on a column in a singleALTER TABLE ... DROP CONSTRAINT a, DROP CONSTRAINT b, ...statement.On PostgreSQL 17+,
NOT NULLis catalogued as a named constraint (<table>_<column>_not_null) instead of an implicitpg_attributeflag. PostgreSQL validates eachDROP CONSTRAINTsubcommand against the catalog state as it existed before the statement started, not against the pending effects of earlier subcommands within the same statement.So when a column has both a not-null constraint and a primary key, and the not-null constraint happens to be listed before the primary key in the generated statement, PostgreSQL rejects the whole statement:
even though the very next clause in that same statement would have dropped the primary key.
This surfaced concretely in an OCA/OpenUpgrade migration script (
hr_recruitment/19.0.1.1/pre-migration.py) callinglift_constraints(cr, legacy_table, "id", cascade=True)on a table whoseidcolumn has both a not-null constraint and a primary key, running against PostgreSQL 18.Fix
Drop each constraint in its own separate
ALTER TABLE ... DROP CONSTRAINT IF EXISTS ...statement instead of combining them into one multi-clause statement. This removes any cross-clause catalog ordering dependency, regardless of how many constraints are found or what order they come back in.Test
The existing
test_lift_constraintstest (tests/test_openupgradelib.py) already exercisescascade=Trueonres_partner.id, which has both a primary key and (on PostgreSQL 17+) a not-null constraint — this test reproduces the failure before the fix and passes after it.