pPowerManger SQLite 老库缺列自动迁移:按注册表对比现有列逐列 ALTER TABLE ADD COLUMN(协议演进新增字段后旧表可自动补齐),SCHEMA_VERSION 升至 2
build-test-deploy / ci (push) Successful in 30m10s
build-test-deploy / ci (push) Successful in 30m10s
This commit is contained in:
@@ -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<std::string> 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<const char*>(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 + ");";
|
||||
|
||||
Reference in New Issue
Block a user