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_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 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 db_backup import (
backup_dir,
@@ -373,8 +373,9 @@ def init_db():
try:
c.execute(sql)
except Exception as exc:
if not is_benign_migration_error(exc):
if not is_schema_migration_error(exc):
raise
rollback_if_postgres(conn)
c.execute('''CREATE TABLE IF NOT EXISTS review_records
(id INTEGER PRIMARY KEY AUTOINCREMENT,
open_time TEXT, close_time TEXT,
@@ -427,8 +428,9 @@ def init_db():
try:
c.execute(sql)
except Exception as exc:
if not is_benign_migration_error(exc):
if not is_schema_migration_error(exc):
raise
rollback_if_postgres(conn)
ensure_kline_tables(conn)
init_strategy_tables(conn)
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:
"""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()
if any(
x in msg
@@ -99,18 +106,32 @@ def is_benign_migration_error(exc: BaseException) -> bool:
"duplicate column",
"already exists",
"duplicate key",
"no such table",
"does not exist",
"undefined table",
"undefined column",
)
):
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
if _PSYCOPG_OK and isinstance(exc, PgOperationalError):
code = getattr(exc, "sqlstate", "") or ""
if code in ("42701", "42P07"): # duplicate_column, duplicate_table
if code in ("42701", "42P07", "42P01", "42703"):
return True
return False
def rollback_if_postgres(conn: "DbConnection") -> None:
if is_postgres():
try:
conn.rollback()
except Exception:
pass
class DbCursor:
"""统一 cursor:兼容 sqlite3 的 execute / fetchone / lastrowid。"""