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 {