]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Don't emit DROP of version table in offline mode at base (#1822)
authorMurod <murodlearns@gmail.com>
Fri, 24 Jul 2026 17:15:15 +0000 (13:15 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 24 Jul 2026 18:32:44 +0000 (14:32 -0400)
Fixes #1822.

As diagnosed by @zzzeek in the issue, offline (`--sql`) mode emitted a `DROP TABLE alembic_version` when running `stamp` or `downgrade` to `base`, while online mode never drops the version table — an inconsistency dating to the version table's introduction.

This removes the offline-only `DROP` so both modes behave the same. The version table is still created when it does not exist; only the spurious offline drop is gone.

**Tests**
- Updated `UpgradeDowngradeStampTest::test_version_to_none` to assert the version table is no longer dropped in offline downgrade-to-base.
- Added `UpgradeDowngradeStampTest::test_sql_stamp_to_base_no_drop` regressing the exact scenario from the issue (`stamp --sql base`).
- Added a changelog entry under `docs/build/unreleased/`.

Full local run: 1763 passed (the only failures are pre-existing `test_post_write.py` hook tests unrelated to this change). `black` + `flake8` clean.

Closes: #1823
Pull-request: https://github.com/sqlalchemy/alembic/pull/1823
Pull-request-sha: 8403c7083d9a1acbb9410ec0fd92331eace5ca8b

Change-Id: Ic5310b989f5217c4c74f88987c8d6a5459226b6b

alembic/runtime/migration.py
docs/build/unreleased/1822.rst [new file with mode: 0644]
tests/test_command.py

index a108539d18793596f01ae634b737f630381b1981..0035540a182326763635622cdfa89ee05c8c7f2b 100644 (file)
@@ -639,9 +639,11 @@ class MigrationContext:
                         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 row),
+        # 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 (file)
index 0000000..f156161
--- /dev/null
@@ -0,0 +1,11 @@
+.. 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.  Pull request
+    courtesy imurodl.
index 16e2b1cc0fd2ab42130b769a610996bad5c21373..67aabd18eee872aca051782fd148c7ad27b0fce5 100644 (file)
@@ -977,11 +977,20 @@ class UpgradeDowngradeStampTest(TestBase):
             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()
+        # offline mode no longer drops the version table, matching online
+        # mode which never drops it.  See #1822.
+        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()
 
+    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_version_to_middle(self):
         with capture_context_buffer() as buf:
             command.downgrade(self.cfg, "%s:%s" % (self.c, self.a), sql=True)