diff --git a/alembic/runtime/migration.py b/alembic/runtime/migration.py index 3fccf22a..9ef12211 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 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 index 00000000..edf34369 --- /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 391a19d0..9cd49f08 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -988,11 +988,20 @@ 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() + # 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)