Skip to content

Fix batch mode ignoring naming_convention for reflected constraints - #1840

Open
Karthick-dev-cart wants to merge 1 commit into
sqlalchemy:mainfrom
Karthick-dev-cart:bugfix/1834-batch-naming-convention-reflected-constraints
Open

Fix batch mode ignoring naming_convention for reflected constraints#1840
Karthick-dev-cart wants to merge 1 commit into
sqlalchemy:mainfrom
Karthick-dev-cart:bugfix/1834-batch-naming-convention-reflected-constraints

Conversation

@Karthick-dev-cart

Copy link
Copy Markdown

Fixes: #1834

Description

batch_alter_table(..., naming_convention=...) reflects the existing table into a MetaData(naming_convention=...), clearly intending for the convention to govern the recreated table's constraint names. But reflection always returns constraints with an explicit .name (whatever is actually stored in the database), and SQLAlchemy naming conventions only fill in names for constraints that don't already have one — so the convention silently had no effect on any reflected constraint.

This was most visible after rename_table(): batch mode would faithfully carry over reflected constraint names that still embed the old table name (e.g. pk_OldTableName after renaming to TableName), even though a naming_convention was explicitly passed to make names track the current table.

Fix

In ApplyBatchImpl._grab_table_elements(), a reflected constraint whose type has an entry in the supplied naming_convention (pk/fk/uq/ck) now has its name reset to None and is re-attached to self.table — which already carries the correct, final table name and the convention — so SQLAlchemy's own naming-convention event recomputes the name against the right target immediately, before the constraint gets copied onto the temp-named table used internally during the "move and copy". (An earlier version of this fix deferred the regeneration to copy time instead, which "fixed" the stale-old-name bug but introduced a different one — baking _alembic_tmp_<name> into the constraint name. Caught via a test that isolates the no-rename case and fixed by regenerating against self.table up front.)

Constraint types the convention doesn't mention are left untouched, so this can't turn some other constraint into an unnamed one it wasn't asked to govern.

_transfer_elements_to_new_table() now also carries naming_convention onto the new table's MetaData (previously always plain MetaData()), which the reset-name mechanism above relies on.

Checklist

  • A short code fix
  • Issue: Batch mode ignores naming_convention for reflected constraints (regression surfaced by SQLAlchemy 2.0.45) #1834 (includes a complete reproduction and root-cause diagnosis)
  • Fixes: #1834 included above
  • Tests: tests/test_batch.py::BatchRoundTripTest::test_naming_convention_applies_to_reflected_constraints — reproduces the issue's exact scenario (rename + batch recreate with a naming_convention covering pk/fk), asserts the recreated table's PK and FK names track the new table name. Verified this test fails against unpatched main with the exact bug signature (pk_oldtablename != pk_tablename).

Test plan

  • New regression test passes; fails on unpatched main with the issue's exact symptom.
  • Full suite: pytest tests/ → 1799 passed, 132 skipped (pre-existing, dialect-specific), 0 failed.
  • black --check / flake8 clean on both changed files.
  • Changelog fragment added at docs/build/unreleased/1834.rst.

Fixes: sqlalchemy#1834

A reflected constraint always comes back from reflection with an
explicit name -- the one stored in the database -- so a
naming_convention passed to batch_alter_table() previously had no
effect on it: naming conventions only fill in names for *unnamed*
constraints. Most visible after rename_table(): a recreated table's
constraints carried over names embedding the *old* table name instead
of following the convention against the new one.

Reflected constraints whose type has an entry in the supplied
naming_convention now have their name reset and are re-attached to the
(correctly, finally-named) existing table, re-firing SQLAlchemy's
naming-convention machinery against the real target name -- not the
"_alembic_tmp_*" name used internally during the copy, which an earlier
version of this fix incorrectly baked in instead.

Constraint types the naming_convention doesn't mention are left alone,
so this can't turn an unrelated constraint into an unnamed one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Batch mode ignores naming_convention for reflected constraints (regression surfaced by SQLAlchemy 2.0.45)

1 participant