From 38c489caec2dae0d300377b3aa514cd48e5ce479 Mon Sep 17 00:00:00 2001 From: zjk <1553836110@qq.com> Date: Wed, 2 Sep 2026 20:47:47 +0800 Subject: [PATCH] =?UTF-8?q?pPowerManger=20SQLite=20=E8=80=81=E5=BA=93?= =?UTF-8?q?=E7=BC=BA=E5=88=97=E8=87=AA=E5=8A=A8=E8=BF=81=E7=A7=BB=EF=BC=9A?= =?UTF-8?q?=E6=8C=89=E6=B3=A8=E5=86=8C=E8=A1=A8=E5=AF=B9=E6=AF=94=E7=8E=B0?= =?UTF-8?q?=E6=9C=89=E5=88=97=E9=80=90=E5=88=97=20ALTER=20TABLE=20ADD=20CO?= =?UTF-8?q?LUMN=EF=BC=88=E5=8D=8F=E8=AE=AE=E6=BC=94=E8=BF=9B=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=AD=97=E6=AE=B5=E5=90=8E=E6=97=A7=E8=A1=A8=E5=8F=AF?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E9=BD=90=EF=BC=89=EF=BC=8CSCHEMA=5F?= =?UTF-8?q?VERSION=20=E5=8D=87=E8=87=B3=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pPowerManger/sqlit3/SQLite.cpp | 51 +++++++++++++++++++++++++++++- src/pPowerManger/sqlit3/SQLite.h | 1 + 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/pPowerManger/sqlit3/SQLite.cpp b/src/pPowerManger/sqlit3/SQLite.cpp index f262f3b..e14fa13 100644 --- a/src/pPowerManger/sqlit3/SQLite.cpp +++ b/src/pPowerManger/sqlit3/SQLite.cpp @@ -7,7 +7,7 @@ #include "../logc/loguru.hpp" namespace { -const int SCHEMA_VERSION = 1; +const int SCHEMA_VERSION = 2; } //==================================================================== @@ -463,6 +463,10 @@ bool SQLite::migrate() if (!createAllTablesUnlocked()) return false; + // 老库缺列自动补齐(协议演进新增字段后,旧表由 CREATE TABLE IF NOT EXISTS + // 创建、不会带新列,导致 INSERT prepare 失败、该表数据无法落库) + if (!migrateColumnsUnlocked()) return false; + if (version < SCHEMA_VERSION) { std::string sql = "PRAGMA user_version = " + std::to_string(SCHEMA_VERSION) + ";"; sqlite3_exec(m_db, sql.c_str(), nullptr, nullptr, nullptr); @@ -470,6 +474,51 @@ bool SQLite::migrate() return true; } +//==================================================================== +// migrateColumnsUnlocked:按注册表逐一对比表现有列,缺哪列补哪列 +// (ALTER TABLE ADD COLUMN,新增列对旧行取默认值 0/NULL)。 +//==================================================================== +bool SQLite::migrateColumnsUnlocked() +{ + for (const TableDesc& t : allTables()) { + // 读取现有列(PRAGMA table_info 第 2 列为列名) + std::vector existing; + sqlite3_stmt* stmt = nullptr; + std::string pragma = std::string("PRAGMA table_info(") + t.name + ");"; + if (sqlite3_prepare_v2(m_db, pragma.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { + while (sqlite3_step(stmt) == SQLITE_ROW) { + const unsigned char* name = sqlite3_column_text(stmt, 1); + if (name) existing.push_back(reinterpret_cast(name)); + } + sqlite3_finalize(stmt); + } + if (existing.empty()) continue; // 表不存在(新库),建表时已含全部列 + + for (const Column& c : t.columns) { + bool found = false; + for (const std::string& e : existing) { + if (e == c.name) { found = true; break; } + } + if (found) continue; + + std::string sql = std::string("ALTER TABLE ") + t.name + + " ADD COLUMN " + c.name + " " + c.sqlType + ";"; + char* errMsg = nullptr; + int rc = sqlite3_exec(m_db, sql.c_str(), nullptr, nullptr, &errMsg); + if (rc == SQLITE_OK) { + LOG_F(INFO, "SQLite 迁移: 表 %s 新增列 %s", t.name, c.name); + } else { + // 记录失败但不中断打开:其余列/表继续尝试, + // 未补齐列的 insert 仍会按原样报 prepare 错误 + m_lastError = errMsg ? errMsg : "alter table failed"; + LOG_F(ERROR, "SQLite 迁移失败: %s (%s)", sql.c_str(), m_lastError.c_str()); + if (errMsg) sqlite3_free(errMsg); + } + } + } + return true; +} + bool SQLite::createTableInternal(const std::string& tableName, const std::string& columns) { std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + columns + ");"; diff --git a/src/pPowerManger/sqlit3/SQLite.h b/src/pPowerManger/sqlit3/SQLite.h index 784f328..4898177 100644 --- a/src/pPowerManger/sqlit3/SQLite.h +++ b/src/pPowerManger/sqlit3/SQLite.h @@ -65,6 +65,7 @@ private: bool migrate(); bool createTableInternal(const std::string& tableName, const std::string& columns); bool createAllTablesUnlocked(); + bool migrateColumnsUnlocked(); // 列描述:名称 + SQL 类型 + 绑定器(无捕获函数指针) struct Column {