Fix PostgreSQL init_db: rollback after benign schema migration errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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
@@ -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。"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user