Fix PostgreSQL init_db: rollback after benign schema migration errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-01 08:13:14 +08:00
parent 1b276b5897
commit bc79ad308c
2 changed files with 28 additions and 5 deletions
+5 -3
View File
@@ -56,7 +56,7 @@ from kline_store import ensure_kline_tables
from kline_stream import kline_hub, sse_format from kline_stream import kline_hub, sse_format
from kline_chart import generate_review_kline_chart, fetch_market_klines, MARKET_PERIODS from kline_chart import generate_review_kline_chart, fetch_market_klines, MARKET_PERIODS
from market import get_price as market_get_price, set_ths_refresh_token, get_quote_source_label from market import get_price as market_get_price, set_ths_refresh_token, get_quote_source_label
from db_conn import OperationalError, connect_db, database_label, is_benign_migration_error, is_db_contention_error from db_conn import OperationalError, connect_db, database_label, is_benign_migration_error, is_db_contention_error, is_schema_migration_error, rollback_if_postgres
from admin_settings import save_admin_credentials from admin_settings import save_admin_credentials
from db_backup import ( from db_backup import (
backup_dir, backup_dir,
@@ -373,8 +373,9 @@ def init_db():
try: try:
c.execute(sql) c.execute(sql)
except Exception as exc: except Exception as exc:
if not is_benign_migration_error(exc): if not is_schema_migration_error(exc):
raise raise
rollback_if_postgres(conn)
c.execute('''CREATE TABLE IF NOT EXISTS review_records c.execute('''CREATE TABLE IF NOT EXISTS review_records
(id INTEGER PRIMARY KEY AUTOINCREMENT, (id INTEGER PRIMARY KEY AUTOINCREMENT,
open_time TEXT, close_time TEXT, open_time TEXT, close_time TEXT,
@@ -427,8 +428,9 @@ def init_db():
try: try:
c.execute(sql) c.execute(sql)
except Exception as exc: except Exception as exc:
if not is_benign_migration_error(exc): if not is_schema_migration_error(exc):
raise raise
rollback_if_postgres(conn)
ensure_kline_tables(conn) ensure_kline_tables(conn)
init_strategy_tables(conn) init_strategy_tables(conn)
from risk.account_risk_lib import ensure_account_risk_schema from risk.account_risk_lib import ensure_account_risk_schema
+23 -2
View File
@@ -92,6 +92,13 @@ def adapt_sql(sql: str) -> str:
def is_benign_migration_error(exc: BaseException) -> bool: def is_benign_migration_error(exc: BaseException) -> bool:
"""ALTER TABLE 重复列等初始化迁移可忽略的错误。""" """ALTER TABLE 重复列等初始化迁移可忽略的错误。"""
if is_schema_migration_error(exc):
return True
return False
def is_schema_migration_error(exc: BaseException) -> bool:
"""init_db 增量迁移:缺表/缺列/重复列均可忽略。"""
msg = str(exc).lower() msg = str(exc).lower()
if any( if any(
x in msg x in msg
@@ -99,18 +106,32 @@ def is_benign_migration_error(exc: BaseException) -> bool:
"duplicate column", "duplicate column",
"already exists", "already exists",
"duplicate key", "duplicate key",
"no such table",
"does not exist",
"undefined table",
"undefined column",
) )
): ):
return True return True
if isinstance(exc, sqlite3.OperationalError) and "duplicate column" in msg: if isinstance(exc, sqlite3.OperationalError) and (
"duplicate column" in msg or "no such table" in msg
):
return True return True
if _PSYCOPG_OK and isinstance(exc, PgOperationalError): if _PSYCOPG_OK and isinstance(exc, PgOperationalError):
code = getattr(exc, "sqlstate", "") or "" code = getattr(exc, "sqlstate", "") or ""
if code in ("42701", "42P07"): # duplicate_column, duplicate_table if code in ("42701", "42P07", "42P01", "42703"):
return True return True
return False return False
def rollback_if_postgres(conn: "DbConnection") -> None:
if is_postgres():
try:
conn.rollback()
except Exception:
pass
class DbCursor: class DbCursor:
"""统一 cursor:兼容 sqlite3 的 execute / fetchone / lastrowid。""" """统一 cursor:兼容 sqlite3 的 execute / fetchone / lastrowid。"""