Skip to content

Commit 3e40cb9

Browse files
authored
fix(core): remove runtime ALTER TABLE from vector init (#728)
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 8c81d3c commit 3e40cb9

File tree

2 files changed

+42
-41
lines changed

2 files changed

+42
-41
lines changed

src/basic_memory/repository/postgres_search_repository.py

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ async def _ensure_vector_tables(self) -> None:
292292
) from exc
293293

294294
# --- Chunks table (dimension-independent, may already exist via migration) ---
295+
# Trigger: fresh Postgres projects may not have vector chunk tables yet.
296+
# Why: runtime can bootstrap missing tables, but schema evolution must stay
297+
# in Alembic to avoid concurrent ALTER TABLE deadlocks during indexing.
298+
# Outcome: new installs create the current schema; upgrades rely on migration.
295299
await session.execute(
296300
text(
297301
"""
@@ -318,47 +322,6 @@ async def _ensure_vector_tables(self) -> None:
318322
"""
319323
)
320324
)
321-
await session.execute(
322-
text(
323-
"""
324-
ALTER TABLE search_vector_chunks
325-
ADD COLUMN IF NOT EXISTS entity_fingerprint TEXT
326-
"""
327-
)
328-
)
329-
await session.execute(
330-
text(
331-
"""
332-
ALTER TABLE search_vector_chunks
333-
ADD COLUMN IF NOT EXISTS embedding_model TEXT
334-
"""
335-
)
336-
)
337-
await session.execute(
338-
text(
339-
"""
340-
UPDATE search_vector_chunks
341-
SET entity_fingerprint = COALESCE(entity_fingerprint, ''),
342-
embedding_model = COALESCE(embedding_model, '')
343-
"""
344-
)
345-
)
346-
await session.execute(
347-
text(
348-
"""
349-
ALTER TABLE search_vector_chunks
350-
ALTER COLUMN entity_fingerprint SET NOT NULL
351-
"""
352-
)
353-
)
354-
await session.execute(
355-
text(
356-
"""
357-
ALTER TABLE search_vector_chunks
358-
ALTER COLUMN embedding_model SET NOT NULL
359-
"""
360-
)
361-
)
362325

363326
# --- Embeddings table (dimension-dependent, created at runtime) ---
364327
# Trigger: provider dimensions may differ from what was previously deployed.

tests/repository/test_postgres_search_repository_unit.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import asyncio
9+
from contextlib import asynccontextmanager
910
from unittest.mock import AsyncMock, MagicMock, patch
1011

1112
import pytest
@@ -169,6 +170,43 @@ async def test_skips_when_already_initialized(self):
169170
assert repo._vector_tables_initialized is True
170171

171172

173+
class TestEnsureVectorTablesSchemaBootstrapping:
174+
"""Guard the runtime setup path against inline schema migration drift."""
175+
176+
@pytest.mark.asyncio
177+
async def test_initialization_never_alters_chunk_table_schema(self, monkeypatch):
178+
repo = _make_repo(
179+
semantic_enabled=True,
180+
embedding_provider=StubEmbeddingProvider(),
181+
)
182+
session = AsyncMock()
183+
184+
@asynccontextmanager
185+
async def fake_scoped_session(session_maker):
186+
yield session
187+
188+
monkeypatch.setattr(
189+
"basic_memory.repository.postgres_search_repository.db.scoped_session",
190+
fake_scoped_session,
191+
)
192+
monkeypatch.setattr(repo, "_get_existing_embedding_dims", AsyncMock(return_value=None))
193+
194+
await repo._ensure_vector_tables()
195+
196+
executed_sql = [str(call.args[0]) for call in session.execute.await_args_list]
197+
198+
assert any(
199+
"CREATE TABLE IF NOT EXISTS search_vector_chunks" in sql for sql in executed_sql
200+
)
201+
assert any(
202+
"CREATE TABLE IF NOT EXISTS search_vector_embeddings" in sql
203+
for sql in executed_sql
204+
)
205+
assert not any("ALTER TABLE search_vector_chunks" in sql for sql in executed_sql)
206+
session.commit.assert_awaited_once()
207+
assert repo._vector_tables_initialized is True
208+
209+
172210
# --- _run_vector_query empty embedding (line 395-396) ----------------------
173211

174212

0 commit comments

Comments
 (0)