From c11914a66bdac78d6e1a853b34b317c9ac9f2e47 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Sun, 5 Jul 2026 09:12:56 +0000 Subject: [PATCH] Fix schema init: use exec_driver_sql to avoid PL/pgSQL bind-param collision SQLAlchemy's text() treats $1/$2 in PL/pgSQL blocks as bindparams and raises InvalidRequestError. exec_driver_sql sends raw SQL directly to psycopg2, bypassing that processing. Without this all tables are missing on startup. Co-Authored-By: Claude Sonnet 4.6 --- backend/main.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/backend/main.py b/backend/main.py index 1d23bbc..d7bd28f 100644 --- a/backend/main.py +++ b/backend/main.py @@ -29,25 +29,21 @@ from scheduler import start_scheduler, shutdown_scheduler @asynccontextmanager async def lifespan(app: FastAPI): # Apply database schema (idempotent CREATE TABLE IF NOT EXISTS) + # Uses exec_driver_sql to bypass SQLAlchemy parameter parsing — schema.sql + # contains PL/pgSQL with $1/$2 syntax that text() misinterprets as bindparams. try: import os - from database import SyncSessionLocal + from database import sync_engine schema_path = os.path.join(os.path.dirname(__file__), 'schema.sql') if os.path.exists(schema_path): - db = SyncSessionLocal() - try: - with open(schema_path) as f: - sql = f.read() - db.execute(text(sql)) - db.commit() - logging.getLogger(__name__).info("Schema applied successfully") - except Exception as e: - logging.getLogger(__name__).warning(f"Schema init failed: {e}") - db.rollback() - finally: - db.close() + with open(schema_path) as f: + sql = f.read() + with sync_engine.connect() as conn: + conn.exec_driver_sql(sql) + conn.commit() + logging.getLogger(__name__).info("Schema applied successfully") except Exception as e: - logging.getLogger(__name__).warning(f"Schema load failed: {e}") + logging.getLogger(__name__).warning(f"Schema init failed: {e}") # Startup: clean up stale scrape batches try: