| 3844 | } |
| 3845 | |
| 3846 | bool CWallet::MigrateToSQLite(bilingual_str& error) |
| 3847 | { |
| 3848 | AssertLockHeld(cs_wallet); |
| 3849 | |
| 3850 | WalletLogPrintf("Migrating wallet storage database from BerkeleyDB to SQLite.\n"); |
| 3851 | |
| 3852 | if (m_database->Format() == "sqlite") { |
| 3853 | error = _("Error: This wallet already uses SQLite"); |
| 3854 | return false; |
| 3855 | } |
| 3856 | |
| 3857 | // Get all of the records for DB type migration |
| 3858 | std::unique_ptr<DatabaseBatch> batch = m_database->MakeBatch(); |
| 3859 | std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor(); |
| 3860 | std::vector<std::pair<SerializeData, SerializeData>> records; |
| 3861 | if (!cursor) { |
| 3862 | error = _("Error: Unable to begin reading all records in the database"); |
| 3863 | return false; |
| 3864 | } |
| 3865 | DatabaseCursor::Status status = DatabaseCursor::Status::FAIL; |
| 3866 | while (true) { |
| 3867 | DataStream ss_key{}; |
| 3868 | DataStream ss_value{}; |
| 3869 | status = cursor->Next(ss_key, ss_value); |
| 3870 | if (status != DatabaseCursor::Status::MORE) { |
| 3871 | break; |
| 3872 | } |
| 3873 | SerializeData key(ss_key.begin(), ss_key.end()); |
| 3874 | SerializeData value(ss_value.begin(), ss_value.end()); |
| 3875 | records.emplace_back(key, value); |
| 3876 | } |
| 3877 | cursor.reset(); |
| 3878 | batch.reset(); |
| 3879 | if (status != DatabaseCursor::Status::DONE) { |
| 3880 | error = _("Error: Unable to read all records in the database"); |
| 3881 | return false; |
| 3882 | } |
| 3883 | |
| 3884 | // Close this database and delete the file |
| 3885 | fs::path db_path = fs::PathFromString(m_database->Filename()); |
| 3886 | m_database->Close(); |
| 3887 | fs::remove(db_path); |
| 3888 | |
| 3889 | // Generate the path for the location of the migrated wallet |
| 3890 | // Wallets that are plain files rather than wallet directories will be migrated to be wallet directories. |
| 3891 | const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(m_name)); |
| 3892 | |
| 3893 | // Make new DB |
| 3894 | DatabaseOptions opts; |
| 3895 | opts.require_create = true; |
| 3896 | opts.require_format = DatabaseFormat::SQLITE; |
| 3897 | DatabaseStatus db_status; |
| 3898 | std::unique_ptr<WalletDatabase> new_db = MakeDatabase(wallet_path, opts, db_status, error); |
| 3899 | assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists. |
| 3900 | m_database.reset(); |
| 3901 | m_database = std::move(new_db); |
| 3902 | |
| 3903 | // Write existing records into the new DB |
no test coverage detected