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 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-05 09:12:56 +00:00
parent aeb99650bd
commit c11914a66b

View file

@ -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()
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 init failed: {e}")
db.rollback()
finally:
db.close()
except Exception as e:
logging.getLogger(__name__).warning(f"Schema load failed: {e}")
# Startup: clean up stale scrape batches
try: