Skip to content

Swift-数据迁移有BUG #1545

@xiaofeng886

Description

@xiaofeng886

在一个未做加密的数据库上,需要进行数据迁移,迁移到一个加密的数据库上,代码如下:

let oldDBPath = MyDBDataPath.basePath + userId + ".db"
     let newDBPath = MyDBDataPath.basePath + userId + "_encryption.db"

     let oldDataBase = Database(at: oldDBPath)
     self.createTable(dataBase: oldDataBase, tableSubString: "")

     self.myDatabase = Database(at: newDBPath)
     let password = userId.data(using: .ascii)
     self.myDatabase?.setCipher(key: password)
     self.myDatabase?.setAutoMigration(enable: true)
//        self.myDatabase?.tag = 10599
     self.myDatabase?.addMigration(sourcePath: oldDBPath,{ info in
         info.sourceTable = info.table + "_encryption"; //配置数据迁移的源表格名
     })
     self.createTable(dataBase: self.myDatabase, tableSubString: "_encryption")

在迁移的过程中报错: "未能完成操作。(WCDBSwift.WCDBError错误1。)"

使用AI进行分析如下:

根本原因分析
通过深入分析 WCDB 源码,我找到了确切的 bug 原因:
SQLCipher ATTACH 机制问题
从 MigrationInfo.cpp 可以看到:

MigrationDatabaseInfo::MigrationDatabaseInfo(...) {
    m_statementForAttachingSchema = StatementAttach().attach(m_sourcePath).as(m_schema);
    if (!cipher.empty()) {
        m_statementForAttachingSchema.key(BindParameter(1)); // 只有cipher非空才添加KEY
    }
}

再看 MigratingHandleDecorator.cpp 的 attach 逻辑:

bool MigratingHandleDecorator::attachDatabase(...) {
    const Data& cipher = attachInfo->getSourceCipher();
    if (!cipher.empty()) {
        handleStatement.bindBLOB(cipher); // 只有cipher非空才绑定key
    }
    succeed = handleStatement.step();
}

而 UnsafeData::empty() 判断逻辑是 m_size == 0。问题链条:
1、你传 sourceCipher: nil → C++ 层 cipher 为空 (size=0)
2、ATTACH 语句变成:ATTACH DATABASE '/old.db' AS 'schema'(没有 KEY 子句)
3、SQLCipher 规则:ATTACH 不指定 KEY 时,使用主数据库的 key 来打开附加数据库
4、你的主数据库(target)是加密的,SQLCipher 用这个密钥去解密未加密的源数据库 → 失败!

正确的 SQL 应该是:

ATTACH DATABASE '/old.db' AS 'schema' KEY ''; -- 空key表示明文

这是 WCDB 2.1.15 版本在"加密目标 + 未加密源"跨库迁移场景下的 bug。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions