From 047c2d3fc090bdaeff4560045c587855b0f575f8 Mon Sep 17 00:00:00 2001 From: Suchethan021 <150219759+Suchethan021@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:44:31 +0530 Subject: [PATCH] Fix offline --sql mode incorrectly emitting DROP TABLE for alembic_version Running 'stamp base --sql' or 'downgrade :base --sql' would emit a DROP TABLE alembic_version statement. Online mode never drops the version table (it only deletes rows), so this was an inconsistency introduced in the very early commits of the project. Remove the block from MigrationContext.run_migrations() that emitted the table drop exclusively in --sql mode when all heads were removed. Add an explanatory comment and an additional test covering 'stamp base --sql'. Fixes: #1822 --- alembic/runtime/migration.py | 8 +++++--- docs/build/unreleased/1822.rst | 10 ++++++++++ tests/test_command.py | 9 ++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 docs/build/unreleased/1822.rst diff --git a/alembic/runtime/migration.py b/alembic/runtime/migration.py index 3fccf22a6..31e03d0cb 100644 --- a/alembic/runtime/migration.py +++ b/alembic/runtime/migration.py @@ -639,9 +639,11 @@ def run_migrations(self, **kw: Any) -> None: run_args=kw, ) - if self.as_sql and not head_maintainer.heads: - assert self.connection is not None - self._version.drop(self.connection) + # NOTE: offline ("--sql") mode intentionally does not emit a DROP + # of the version table when ending at base. Online mode never drops + # the version table (e.g. ``downgrade base`` only deletes its rows), + # so dropping it in offline mode only was an inconsistency present + # since the version table was first introduced. See #1822. def _in_connection_transaction(self) -> bool: try: diff --git a/docs/build/unreleased/1822.rst b/docs/build/unreleased/1822.rst new file mode 100644 index 000000000..f0f598b00 --- /dev/null +++ b/docs/build/unreleased/1822.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, commands + :tickets: 1822 + + Fixed inconsistency where running ``stamp`` or ``downgrade`` to ``base`` + in offline (``--sql``) mode would emit a ``DROP TABLE alembic_version`` + statement, while the same operations in online mode never drop the version + table. Offline mode no longer emits this ``DROP``, matching online + behavior. The version table continues to be created when it does not + exist; only the spurious offline-only drop has been removed. diff --git a/tests/test_command.py b/tests/test_command.py index 391a19d00..96427b5c4 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -988,7 +988,7 @@ def test_version_to_none(self): command.downgrade(self.cfg, "%s:base" % self.c, sql=True) assert "CREATE TABLE alembic_version" not in buf.getvalue() assert "INSERT INTO alembic_version" not in buf.getvalue() - assert "DROP TABLE alembic_version" in buf.getvalue() + assert "DROP TABLE alembic_version" not in buf.getvalue() assert "DROP STEP 3" in buf.getvalue() assert "DROP STEP 2" in buf.getvalue() assert "DROP STEP 1" in buf.getvalue() @@ -1047,6 +1047,13 @@ def test_sql_stamp_revision_as_kw(self): in buf.getvalue() ) + def test_sql_stamp_to_base_no_drop(self): + # stamping to "base" in offline mode must not emit a DROP of the + # version table; online mode never drops it. See #1822. + with capture_context_buffer() as buf: + command.stamp(self.cfg, "base", sql=True) + assert "DROP TABLE alembic_version" not in buf.getvalue() + def test_stamp_argparser_single_rev(self): cmd = config.CommandLine() options = cmd.parser.parse_args(["stamp", self.c, "--sql"])