Skip to content

Commit 771ac10

Browse files
committed
fix(checkpointer): clear stale cubepi_schema_version rows on upgrade
INSERT ... ON CONFLICT DO NOTHING leaves prior version rows behind because version is the primary key. _verify_schema does SELECT version ... LIMIT 1 and could read the stale row, triggering a spurious CubepiSchemaMismatch on upgrade. DELETE any non-current row before INSERT — still idempotent.
1 parent 34b83cc commit 771ac10

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

cubepi/checkpointer/postgres/alembic_helpers.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,19 @@ def create_message_partitions_op() -> str:
2121

2222

2323
def write_schema_version_op() -> str:
24-
"""Return SQL inserting the current schema version.
24+
"""Return SQL setting cubepi_schema_version to the current version.
2525
2626
Call inside alembic upgrade() after CREATE TABLE cubepi_schema_version.
27-
Idempotent via ON CONFLICT DO NOTHING.
27+
28+
Atomically clears any stale rows (from prior cubepi versions) and writes
29+
the current version. ``version`` is the primary key, so a plain INSERT
30+
would leave older rows in place and ``_verify_schema`` (which does
31+
``SELECT version ... LIMIT 1``) could read a stale value and falsely
32+
report CubepiSchemaMismatch. Idempotent under repeated execution.
2833
"""
2934
return (
35+
f"DELETE FROM cubepi_schema_version "
36+
f"WHERE version <> {EXPECTED_SCHEMA_VERSION}; "
3037
f"INSERT INTO cubepi_schema_version (version) "
3138
f"VALUES ({EXPECTED_SCHEMA_VERSION}) ON CONFLICT DO NOTHING;"
3239
)

tests/checkpointer/test_postgres.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ def test_write_schema_version_op_includes_expected_version() -> None:
7979
assert "ON CONFLICT" in sql
8080

8181

82+
def test_write_schema_version_op_clears_stale_rows() -> None:
83+
"""A prior version's row must be removed so _verify_schema sees the new one."""
84+
from cubepi.checkpointer.postgres.alembic_helpers import write_schema_version_op
85+
86+
sql = write_schema_version_op()
87+
# Must DELETE rows whose version is not the expected one before INSERT.
88+
assert "DELETE FROM cubepi_schema_version" in sql
89+
assert "WHERE version <> 1" in sql
90+
# And the DELETE must come before the INSERT in the statement order.
91+
assert sql.index("DELETE") < sql.index("INSERT")
92+
93+
8294
def test_schema_uninitialized_is_schema_error() -> None:
8395
from cubepi.checkpointer.postgres.exceptions import (
8496
CubepiSchemaError,

0 commit comments

Comments
 (0)