• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define LOG_TAG "SqliteConnection"
17 #include "sqlite_connection.h"
18 
19 #include <dlfcn.h>
20 #include <sqlite3sym.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 
24 #include <cerrno>
25 #include <memory>
26 #include <sstream>
27 #include <string>
28 
29 #include "logger.h"
30 #include "raw_data_parser.h"
31 #include "rdb_errno.h"
32 #include "rdb_fault_hiview_reporter.h"
33 #include "rdb_local_db_observer.h"
34 #include "rdb_security_manager.h"
35 #include "rdb_sql_statistic.h"
36 #include "rdb_store_config.h"
37 #include "relational_store_client.h"
38 #include "sqlite3.h"
39 #include "sqlite_default_function.h"
40 #include "sqlite_errno.h"
41 #include "sqlite_global_config.h"
42 #include "sqlite_utils.h"
43 #include "value_object.h"
44 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
45 #include "rdb_manager_impl.h"
46 #include "relational/relational_store_sqlite_ext.h"
47 #endif
48 #include "task_executor.h"
49 
50 namespace OHOS {
51 namespace NativeRdb {
52 using namespace OHOS::Rdb;
53 using namespace std::chrono;
54 using RdbKeyFile = RdbSecurityManager::KeyFileType;
55 using Reportor = RdbFaultHiViewReporter;
56 constexpr const char *INTEGRITIES[] = { nullptr, "PRAGMA quick_check", "PRAGMA integrity_check" };
57 constexpr SqliteConnection::Suffix SqliteConnection::FILE_SUFFIXES[];
58 constexpr int SqliteConnection::DEFAULT_BUSY_TIMEOUT_MS;
59 constexpr int SqliteConnection::BACKUP_PAGES_PRE_STEP; // 1024 * 4 * 12800 == 50m
60 constexpr int SqliteConnection::BACKUP_PRE_WAIT_TIME;
61 constexpr ssize_t SqliteConnection::SLAVE_WAL_SIZE_LIMIT;
62 constexpr ssize_t SqliteConnection::SLAVE_INTEGRITY_CHECK_LIMIT;
63 constexpr uint32_t SqliteConnection::NO_ITER;
64 constexpr uint32_t SqliteConnection::DB_INDEX;
65 constexpr uint32_t SqliteConnection::WAL_INDEX;
66 constexpr uint32_t SqliteConnection::ITER_V1;
67 __attribute__((used))
68 const int32_t SqliteConnection::regCreator_ = Connection::RegisterCreator(DB_SQLITE, SqliteConnection::Create);
69 __attribute__((used))
70 const int32_t SqliteConnection::regRepairer_ = Connection::RegisterRepairer(DB_SQLITE, SqliteConnection::Repair);
71 __attribute__((used))
72 const int32_t SqliteConnection::regDeleter_ = Connection::RegisterDeleter(DB_SQLITE, SqliteConnection::Delete);
73 __attribute__((used))
74 const int32_t SqliteConnection::regCollector_ = Connection::RegisterCollector(DB_SQLITE, SqliteConnection::Collect);
75 __attribute__((used))
76 const int32_t SqliteConnection::regRestorer_ = Connection::RegisterRestorer(DB_SQLITE, SqliteConnection::Restore);
77 
Create(const RdbStoreConfig & config,bool isWrite)78 std::pair<int32_t, std::shared_ptr<Connection>> SqliteConnection::Create(const RdbStoreConfig &config, bool isWrite)
79 {
80     std::pair<int32_t, std::shared_ptr<Connection>> result = { E_ERROR, nullptr };
81     auto &[errCode, conn] = result;
82     std::tie(errCode, conn) = InnerCreate(config, isWrite);
83     return result;
84 }
85 
Delete(const RdbStoreConfig & config)86 int32_t SqliteConnection::Delete(const RdbStoreConfig &config)
87 {
88     auto path = config.GetPath();
89     auto slavePath = SqliteUtils::GetSlavePath(path);
90     Delete(path);
91     Delete(slavePath);
92     return E_OK;
93 }
94 
Delete(const std::string & path)95 int32_t SqliteConnection::Delete(const std::string &path)
96 {
97     for (const auto &suffix : FILE_SUFFIXES) {
98         SqliteUtils::DeleteFile(path + suffix.suffix_);
99     }
100     return E_OK;
101 }
102 
Collect(const RdbStoreConfig & config)103 std::map<std::string, Connection::Info> SqliteConnection::Collect(const RdbStoreConfig &config)
104 {
105     std::map<std::string, Connection::Info> collection;
106     if (config.IsMemoryRdb()) {
107         return collection;
108     }
109     std::string path;
110     SqliteGlobalConfig::GetDbPath(config, path);
111     for (auto &suffix : FILE_SUFFIXES) {
112         if (suffix.debug_ == nullptr) {
113             continue;
114         }
115         auto file = path + suffix.suffix_;
116         std::pair<int32_t, RdbDebugInfo> fileInfo = SqliteUtils::Stat(file);
117         if (fileInfo.first == E_OK) {
118             collection.insert(std::pair{ suffix.debug_, fileInfo.second });
119         }
120     }
121     RdbSecurityManager::KeyFiles keyFiles(path);
122     std::string keyPath =  keyFiles.GetKeyFile(RdbSecurityManager::PUB_KEY_FILE);
123     std::pair<int32_t, RdbDebugInfo> fileInfo = SqliteUtils::Stat(keyPath);
124     if (fileInfo.first == E_OK) {
125         collection.insert(std::pair{ "key", fileInfo.second });
126     }
127     std::string newKeyPath = keyFiles.GetKeyFile(RdbSecurityManager::PUB_KEY_FILE_NEW_KEY);
128     fileInfo = SqliteUtils::Stat(newKeyPath);
129     if (fileInfo.first == E_OK) {
130         collection.insert(std::pair{ "newKey", fileInfo.second });
131     }
132     return collection;
133 }
134 
SqliteConnection(const RdbStoreConfig & config,bool isWriteConnection)135 SqliteConnection::SqliteConnection(const RdbStoreConfig &config, bool isWriteConnection)
136     : dbHandle_(nullptr), isWriter_(isWriteConnection), isReadOnly_(false), maxVariableNumber_(0),
137       config_(config)
138 {
139     backupId_ = TaskExecutor::INVALID_TASK_ID;
140 }
141 
CreateSlaveConnection(const RdbStoreConfig & config,SlaveOpenPolicy slaveOpenPolicy)142 std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::CreateSlaveConnection(
143     const RdbStoreConfig &config, SlaveOpenPolicy slaveOpenPolicy)
144 {
145     std::pair<int32_t, std::shared_ptr<SqliteConnection>> result = { E_ERROR, nullptr };
146     auto &[errCode, conn] = result;
147     std::map<std::string, DebugInfo> bugInfo = Connection::Collect(config);
148     bool isSlaveExist = access(config.GetPath().c_str(), F_OK) == 0;
149     bool isSlaveLockExist = SqliteUtils::IsSlaveInterrupted(config_.GetPath());
150     bool hasFailure = SqliteUtils::IsSlaveInvalid(config_.GetPath());
151     bool walOverLimit = bugInfo.find(FILE_SUFFIXES[WAL_INDEX].debug_) != bugInfo.end() &&
152                         bugInfo[FILE_SUFFIXES[WAL_INDEX].debug_].size_ > SLAVE_WAL_SIZE_LIMIT;
153     LOG_INFO("slave cfg:[%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d]%{public}s "
154              "%{public}s,[%{public}d,%{public}d,%{public}d,%{public}d]",
155         config.GetDBType(), config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(),
156         config.GetRoleType(), config.IsReadOnly(),
157         SqliteUtils::FormatDebugInfoBrief(bugInfo, SqliteUtils::Anonymous(config.GetName())).c_str(),
158         SqliteUtils::FormatDebugInfoBrief(Connection::Collect(config_), "master").c_str(), isSlaveExist,
159         isSlaveLockExist, hasFailure, walOverLimit);
160     if (config.GetHaMode() == HAMode::MANUAL_TRIGGER && (slaveOpenPolicy == SlaveOpenPolicy::OPEN_IF_DB_VALID &&
161         (!isSlaveExist || isSlaveLockExist || hasFailure || walOverLimit))) {
162         if (walOverLimit) {
163             SqliteUtils::SetSlaveInvalid(config_.GetPath());
164             Reportor::ReportCorrupted(Reportor::Create(config, E_SQLITE_ERROR, "ErrorType: slaveWalOverLimit"));
165         }
166         return result;
167     }
168 
169     std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
170     errCode = connection->InnerOpen(config);
171     if (errCode != E_OK) {
172         SqliteUtils::SetSlaveInvalid(config_.GetPath());
173         if (errCode == E_SQLITE_CORRUPT) {
174             LOG_WARN("slave corrupt, rebuild:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
175             (void)Delete(config.GetPath());
176             // trigger mode does not require rebuild the slave
177             if (config.GetHaMode() == HAMode::MANUAL_TRIGGER) {
178                 return result;
179             }
180             errCode = connection->InnerOpen(config);
181             if (errCode != E_OK) {
182                 LOG_ERROR("reopen slave failed:%{public}d", errCode);
183                 return result;
184             }
185         } else {
186             LOG_WARN(
187                 "open slave failed:%{public}d, %{public}s", errCode, SqliteUtils::Anonymous(config.GetPath()).c_str());
188             return result;
189         }
190     }
191     conn = connection;
192     return result;
193 }
194 
GetSlaveRdbStoreConfig(const RdbStoreConfig & rdbConfig)195 RdbStoreConfig SqliteConnection::GetSlaveRdbStoreConfig(const RdbStoreConfig &rdbConfig)
196 {
197     RdbStoreConfig rdbStoreConfig(SqliteUtils::GetSlavePath(rdbConfig.GetPath()));
198     rdbStoreConfig.SetEncryptStatus(rdbConfig.IsEncrypt());
199     rdbStoreConfig.SetSearchable(rdbConfig.IsSearchable());
200     rdbStoreConfig.SetIsVector(rdbConfig.IsVector());
201     rdbStoreConfig.SetAutoClean(rdbConfig.GetAutoClean());
202     rdbStoreConfig.SetSecurityLevel(rdbConfig.GetSecurityLevel());
203     rdbStoreConfig.SetDataGroupId(rdbConfig.GetDataGroupId());
204     rdbStoreConfig.SetName(SqliteUtils::GetSlavePath(rdbConfig.GetName()));
205     rdbStoreConfig.SetCustomDir(rdbConfig.GetCustomDir());
206     rdbStoreConfig.SetAllowRebuild(rdbConfig.GetAllowRebuild());
207     rdbStoreConfig.SetReadOnly(rdbConfig.IsReadOnly());
208     rdbStoreConfig.SetAutoCheck(rdbConfig.IsAutoCheck());
209     rdbStoreConfig.SetCreateNecessary(rdbConfig.IsCreateNecessary());
210     rdbStoreConfig.SetJournalSize(rdbConfig.GetJournalSize());
211     rdbStoreConfig.SetPageSize(rdbConfig.GetPageSize());
212     rdbStoreConfig.SetReadConSize(rdbConfig.GetReadConSize());
213     rdbStoreConfig.SetReadTime(rdbConfig.GetReadTime());
214     rdbStoreConfig.SetDBType(rdbConfig.GetDBType());
215     rdbStoreConfig.SetVisitorDir(rdbConfig.GetVisitorDir());
216     rdbStoreConfig.SetScalarFunctions(rdbConfig.GetScalarFunctions());
217     rdbStoreConfig.SetJournalMode(rdbConfig.GetJournalMode());
218 
219     rdbStoreConfig.SetModuleName(rdbConfig.GetModuleName());
220     rdbStoreConfig.SetPluginLibs(rdbConfig.GetPluginLibs());
221     rdbStoreConfig.SetHaMode(rdbConfig.GetHaMode());
222 
223     rdbStoreConfig.SetCryptoParam(rdbConfig.GetCryptoParam());
224     return rdbStoreConfig;
225 }
226 
InnerOpen(const RdbStoreConfig & config)227 int SqliteConnection::InnerOpen(const RdbStoreConfig &config)
228 {
229     std::string dbPath;
230     auto errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
231     if (errCode != E_OK) {
232         return errCode;
233     }
234     SetTokenizer(config);
235 
236 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
237     bool isDbFileExist = access(dbPath.c_str(), F_OK) == 0;
238     if (!isDbFileExist && (!config.IsCreateNecessary())) {
239         Reportor::ReportFault(RdbFaultDbFileEvent(FT_EX_FILE, E_DB_NOT_EXIST, config, "db not exist"));
240         LOG_ERROR("db not exist errno is %{public}d", errno);
241         return E_DB_NOT_EXIST;
242     }
243 #endif
244     isReadOnly_ = !isWriter_ || config.IsReadOnly();
245     uint32_t openFileFlags = config.IsReadOnly() ? (SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX)
246                                             : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
247     if (config.IsMemoryRdb()) {
248         openFileFlags |= SQLITE_OPEN_URI;
249     }
250     errCode = OpenDatabase(dbPath, static_cast<int>(openFileFlags));
251     if (errCode != E_OK) {
252         Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, errCode, config, "", true));
253         return errCode;
254     }
255 
256     maxVariableNumber_ = sqlite3_limit(dbHandle_, SQLITE_LIMIT_VARIABLE_NUMBER, -1);
257     errCode = Configure(config, dbPath);
258     isConfigured_ = true;
259     if (errCode != E_OK) {
260         return errCode;
261     }
262 
263     if (isWriter_) {
264         ValueObject checkResult{"ok"};
265         auto index = static_cast<uint32_t>(config.GetIntegrityCheck());
266         if (index < static_cast<uint32_t>(sizeof(INTEGRITIES) / sizeof(INTEGRITIES[0]))) {
267             auto sql = INTEGRITIES[index];
268             if (sql != nullptr) {
269                 LOG_INFO("%{public}s : %{public}s, ", sql, SqliteUtils::Anonymous(config.GetName()).c_str());
270                 std::tie(errCode, checkResult) = ExecuteForValue(sql);
271             }
272             if (errCode == E_OK && static_cast<std::string>(checkResult) != "ok") {
273                 LOG_ERROR("%{public}s integrity check result is %{public}s, sql:%{public}s",
274                     SqliteUtils::Anonymous(config.GetName()).c_str(), static_cast<std::string>(checkResult).c_str(),
275                     sql);
276                 Reportor::ReportCorruptedOnce(Reportor::Create(config, errCode, static_cast<std::string>(checkResult)));
277             }
278         }
279     }
280     return E_OK;
281 }
282 
OpenDatabase(const std::string & dbPath,int openFileFlags)283 int32_t SqliteConnection::OpenDatabase(const std::string &dbPath, int openFileFlags)
284 {
285     int errCode = sqlite3_open_v2(dbPath.c_str(), &dbHandle_, openFileFlags, nullptr);
286     if (errCode != SQLITE_OK) {
287         LOG_ERROR("fail to open database errCode=%{public}d, dbPath=%{public}s, flags=%{public}d, errno=%{public}d",
288             errCode, SqliteUtils::Anonymous(dbPath).c_str(), openFileFlags, errno);
289 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
290         auto const pos = dbPath.find_last_of("\\/");
291         if (pos != std::string::npos) {
292             std::string filepath = dbPath.substr(0, pos);
293             if (access(filepath.c_str(), F_OK | W_OK) != 0) {
294                 LOG_ERROR("The path to the database file to be created is not valid, err = %{public}d", errno);
295                 return E_INVALID_FILE_PATH;
296             }
297         }
298 #endif
299         if (errCode == SQLITE_NOTADB) {
300             Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_SQLITE_NOT_DB, config_, "", true));
301         }
302         return SQLiteError::ErrNo(errCode);
303     }
304     return E_OK;
305 }
306 
SetCustomFunctions(const RdbStoreConfig & config)307 int SqliteConnection::SetCustomFunctions(const RdbStoreConfig &config)
308 {
309     customScalarFunctions_ = config.GetScalarFunctions();
310     for (auto &it : customScalarFunctions_) {
311         int errCode = SetCustomScalarFunction(it.first, it.second.argc_, &it.second.function_);
312         if (errCode != E_OK) {
313             return errCode;
314         }
315     }
316     return E_OK;
317 }
318 
CustomScalarFunctionCallback(sqlite3_context * ctx,int argc,sqlite3_value ** argv)319 static void CustomScalarFunctionCallback(sqlite3_context *ctx, int argc, sqlite3_value **argv)
320 {
321     if (ctx == nullptr || argv == nullptr) {
322         LOG_ERROR("ctx or argv is nullptr.");
323         return;
324     }
325     auto function = static_cast<ScalarFunction *>(sqlite3_user_data(ctx));
326     if (function == nullptr) {
327         LOG_ERROR("function is nullptr.");
328         return;
329     }
330 
331     std::vector<std::string> argsVector;
332     for (int i = 0; i < argc; ++i) {
333         auto arg = reinterpret_cast<const char *>(sqlite3_value_text(argv[i]));
334         if (arg == nullptr) {
335             LOG_ERROR("arg is nullptr, index is %{public}d, errno is %{public}d", i, errno);
336             sqlite3_result_null(ctx);
337             return;
338         }
339         argsVector.emplace_back(std::string(arg));
340     }
341 
342     std::string result = (*function)(argsVector);
343     if (result.empty()) {
344         sqlite3_result_null(ctx);
345         return;
346     }
347     sqlite3_result_text(ctx, result.c_str(), -1, SQLITE_TRANSIENT);
348 }
349 
SetCustomScalarFunction(const std::string & functionName,int argc,ScalarFunction * function)350 int SqliteConnection::SetCustomScalarFunction(const std::string &functionName, int argc, ScalarFunction *function)
351 {
352     int err = sqlite3_create_function_v2(dbHandle_, functionName.c_str(), argc, SQLITE_UTF8, function,
353         &CustomScalarFunctionCallback, nullptr, nullptr, nullptr);
354     if (err != SQLITE_OK) {
355         LOG_ERROR("SetCustomScalarFunction errCode is %{public}d, errno is %{public}d.", err, errno);
356     }
357     return err;
358 }
359 
Configure(const RdbStoreConfig & config,std::string & dbPath)360 int SqliteConnection::Configure(const RdbStoreConfig &config, std::string &dbPath)
361 {
362     if (config.GetRoleType() == VISITOR) {
363         return E_OK;
364     }
365 
366     auto errCode = RegDefaultFunctions(dbHandle_);
367     if (errCode != E_OK) {
368         return errCode;
369     }
370 
371     SetBusyTimeout(DEFAULT_BUSY_TIMEOUT_MS);
372 
373     LimitPermission(config, dbPath);
374 
375     errCode = SetPersistWal(config);
376     if (errCode != E_OK) {
377         return errCode;
378     }
379 
380     errCode = SetPageSize(config);
381     if (errCode != E_OK) {
382         return errCode;
383     }
384 
385     errCode = SetEncrypt(config);
386     if (errCode != E_OK) {
387         return errCode;
388     }
389 
390     errCode = SetJournalMode(config);
391     if (errCode != E_OK) {
392         return errCode;
393     }
394 
395     // set the user version to the wal file;
396     SetWalFile(config);
397 
398     errCode = SetAutoCheckpoint(config);
399     if (errCode != E_OK) {
400         return errCode;
401     }
402 
403     errCode = SetCustomFunctions(config);
404     if (errCode != E_OK) {
405         return errCode;
406     }
407     RegisterHookIfNecessary();
408     return LoadExtension(config, dbHandle_);
409 }
410 
~SqliteConnection()411 SqliteConnection::~SqliteConnection()
412 {
413     if (backupId_ != TaskExecutor::INVALID_TASK_ID) {
414         auto pool = TaskExecutor::GetInstance().GetExecutor();
415         if (pool != nullptr) {
416             pool->Remove(backupId_, true);
417         }
418     }
419     if (dbHandle_ != nullptr) {
420         int errCode = sqlite3_close_v2(dbHandle_);
421         if (errCode != SQLITE_OK) {
422             LOG_ERROR("could not close database err = %{public}d, errno = %{public}d", errCode, errno);
423         }
424     }
425 }
426 
VerifyAndRegisterHook(const RdbStoreConfig & config)427 int32_t SqliteConnection::VerifyAndRegisterHook(const RdbStoreConfig &config)
428 {
429     if (!isWriter_  || config_.IsEqualRegisterInfo(config)) {
430         return E_OK;
431     }
432     for (auto &eventInfo : onEventHandlers_) {
433         if (config.GetRegisterInfo(eventInfo.Type) && !config_.GetRegisterInfo(eventInfo.Type)) {
434             config_.SetRegisterInfo(eventInfo.Type, true);
435             (this->*(eventInfo.handle))();
436         }
437     }
438     return E_OK;
439 }
440 
RegisterHookIfNecessary()441 int32_t SqliteConnection::RegisterHookIfNecessary()
442 {
443     if (!isWriter_) {
444         return E_OK;
445     }
446     for (auto &eventInfo : onEventHandlers_) {
447         if (config_.GetRegisterInfo(eventInfo.Type)) {
448             (this->*(eventInfo.handle))();
449         }
450     }
451     return E_OK;
452 }
453 
RegisterStoreObs()454 int SqliteConnection::RegisterStoreObs()
455 {
456     RegisterDbHook(dbHandle_);
457     auto status = CreateDataChangeTempTrigger(dbHandle_);
458     if (status != E_OK) {
459         LOG_ERROR("CreateDataChangeTempTrigger failed. status %{public}d", status);
460         return status;
461     }
462     return E_OK;
463 }
464 
RegisterClientObs()465 int SqliteConnection::RegisterClientObs()
466 {
467     RegisterDbHook(dbHandle_);
468     return E_OK;
469 }
470 
CreateStatement(const std::string & sql,std::shared_ptr<Connection> conn)471 std::pair<int, std::shared_ptr<Statement>> SqliteConnection::CreateStatement(
472     const std::string &sql, std::shared_ptr<Connection> conn)
473 {
474     std::shared_ptr<SqliteStatement> statement = std::make_shared<SqliteStatement>();
475     // When memory is not cleared, quick_check reads memory pages and detects damage but does not report it
476     if (sql == INTEGRITIES[1] && dbHandle_ != nullptr && mode_ == JournalMode::MODE_WAL) {
477         sqlite3_db_release_memory(dbHandle_);
478     }
479     statement->config_ = &config_;
480     int errCode = statement->Prepare(dbHandle_, sql);
481     if (errCode != E_OK) {
482         return { errCode, nullptr };
483     }
484     statement->conn_ = conn;
485     if (slaveConnection_ && IsWriter()) {
486         auto slaveStmt = std::make_shared<SqliteStatement>();
487         if (sql == INTEGRITIES[1] && dbHandle_ != nullptr && mode_ == JournalMode::MODE_WAL) {
488             sqlite3_db_release_memory(dbHandle_);
489         }
490         slaveStmt->config_ = &slaveConnection_->config_;
491         errCode = slaveStmt->Prepare(slaveConnection_->dbHandle_, sql);
492         if (errCode != E_OK) {
493             LOG_WARN("prepare slave stmt failed:%{public}d, app self can check the SQL", errCode);
494             SqliteUtils::SetSlaveInvalid(config_.GetPath());
495             return { E_OK, statement };
496         }
497         statement->slave_ = slaveStmt;
498     }
499     return { E_OK, statement };
500 }
501 
IsWriter() const502 bool SqliteConnection::IsWriter() const
503 {
504     return isWriter_;
505 }
506 
SubscribeTableChanges(const Connection::Notifier & notifier)507 int SqliteConnection::SubscribeTableChanges(const Connection::Notifier &notifier)
508 {
509 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
510     if (!isWriter_ || notifier == nullptr) {
511         return E_OK;
512     }
513 
514     int32_t status = RegisterClientObserver(dbHandle_, [notifier](const ClientChangedData &clientData) {
515         DistributedRdb::RdbChangedData rdbChangedData;
516         for (auto &[key, val] : clientData.tableData) {
517             if (val.isTrackedDataChange || val.isP2pSyncDataChange) {
518                 rdbChangedData.tableData[key].isTrackedDataChange = val.isTrackedDataChange;
519                 rdbChangedData.tableData[key].isP2pSyncDataChange = val.isP2pSyncDataChange;
520             }
521         }
522         notifier(rdbChangedData);
523     });
524     if (status != E_OK) {
525         LOG_ERROR("RegisterClientObserver error, status:%{public}d", status);
526     }
527     RegisterDbHook(dbHandle_);
528     config_.SetRegisterInfo(RegisterType::CLIENT_OBSERVER, true);
529     return status;
530 #endif
531     return E_OK;
532 }
533 
GetMaxVariable() const534 int SqliteConnection::GetMaxVariable() const
535 {
536     return maxVariableNumber_;
537 }
538 
GetJournalMode()539 int32_t SqliteConnection::GetJournalMode()
540 {
541     return (int32_t)mode_;
542 }
543 
GetDBType() const544 int32_t SqliteConnection::GetDBType() const
545 {
546     return DB_SQLITE;
547 }
548 
SetPageSize(const RdbStoreConfig & config)549 int SqliteConnection::SetPageSize(const RdbStoreConfig &config)
550 {
551     if (isReadOnly_ || config.GetPageSize() == GlobalExpr::DB_PAGE_SIZE) {
552         return E_OK;
553     }
554 
555     int targetValue = config.GetPageSize();
556     auto [errCode, object] = ExecuteForValue("PRAGMA page_size");
557     if (errCode != E_OK) {
558         LOG_ERROR("SetPageSize fail to get page size : %{public}d", errCode);
559         return errCode;
560     }
561 
562     if (static_cast<int64_t>(object) == targetValue) {
563         return E_OK;
564     }
565 
566     errCode = ExecuteSql("PRAGMA page_size=" + std::to_string(targetValue));
567     if (errCode != E_OK) {
568         LOG_ERROR("SetPageSize fail to set page size : %{public}d", errCode);
569     }
570     return errCode;
571 }
572 
SetEncryptAgo(const RdbStoreConfig & config)573 int SqliteConnection::SetEncryptAgo(const RdbStoreConfig &config)
574 {
575     if (!config.GetCryptoParam().IsValid()) {
576         LOG_ERROR("Invalid crypto param: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}u",
577             SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetCryptoParam().iterNum,
578             config.GetCryptoParam().encryptAlgo, config.GetCryptoParam().hmacAlgo, config.GetCryptoParam().kdfAlgo,
579             config.GetCryptoParam().cryptoPageSize);
580         return E_INVALID_ARGS;
581     }
582 
583     if (config.GetIter() != NO_ITER) {
584         auto errCode = ExecuteSql(std::string(GlobalExpr::CIPHER_ALGO_PREFIX) +
585                                   SqliteUtils::EncryptAlgoDescription(config.GetEncryptAlgo()) +
586                                   std::string(GlobalExpr::ALGO_SUFFIX));
587         if (errCode != E_OK) {
588             LOG_ERROR("set cipher algo failed, err = %{public}d", errCode);
589             return errCode;
590         }
591 
592         errCode = ExecuteSql(std::string(GlobalExpr::CIPHER_KDF_ITER) + std::to_string(config.GetIter()));
593         if (errCode != E_OK) {
594             LOG_ERROR("set kdf iter number V1 failed, err = %{public}d", errCode);
595             return errCode;
596         }
597     }
598 
599     auto errCode = ExecuteSql(std::string(GlobalExpr::CODEC_HMAC_ALGO_PREFIX) +
600                               SqliteUtils::HmacAlgoDescription(config.GetCryptoParam().hmacAlgo) +
601                               std::string(GlobalExpr::ALGO_SUFFIX));
602     if (errCode != E_OK) {
603         LOG_ERROR("set codec hmac algo failed, err = %{public}d", errCode);
604         return errCode;
605     }
606 
607     errCode = ExecuteSql(std::string(GlobalExpr::CODEC_KDF_ALGO_PREFIX) +
608                          SqliteUtils::KdfAlgoDescription(config.GetCryptoParam().kdfAlgo) +
609                          std::string(GlobalExpr::ALGO_SUFFIX));
610     if (errCode != E_OK) {
611         LOG_ERROR("set codec kdf algo failed, err = %{public}d", errCode);
612         return errCode;
613     }
614 
615     errCode = ExecuteSql(
616         std::string(GlobalExpr::CODEC_PAGE_SIZE_PREFIX) + std::to_string(config.GetCryptoParam().cryptoPageSize));
617     if (errCode != E_OK) {
618         LOG_ERROR("set codec page size failed, err = %{public}d", errCode);
619         return errCode;
620     }
621 
622     errCode = ExecuteSql(GlobalExpr::CODEC_REKEY_HMAC_ALGO);
623     if (errCode != E_OK) {
624         LOG_ERROR("set rekey sha algo failed, err = %{public}d", errCode);
625         return errCode;
626     }
627     return E_OK;
628 }
629 
ReSetKey(const RdbStoreConfig & config)630 int SqliteConnection::ReSetKey(const RdbStoreConfig &config)
631 {
632     if (!IsWriter()) {
633         return E_OK;
634     }
635     LOG_INFO(
636         "name = %{public}s, iter = %{public}d", SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetIter());
637     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
638     int errCode = sqlite3_rekey(dbHandle_, static_cast<const void *>(newKey.data()), static_cast<int>(newKey.size()));
639     newKey.assign(newKey.size(), 0);
640     if (errCode != SQLITE_OK) {
641         LOG_ERROR("ReKey failed, err = %{public}d, errno = %{public}d", errCode, errno);
642         RdbSecurityManager::GetInstance().DelKeyFile(config.GetPath(), RdbKeyFile::PUB_KEY_FILE_NEW_KEY);
643         return E_OK;
644     }
645     config.ChangeEncryptKey();
646     return E_OK;
647 }
648 
SetEncrypt(const RdbStoreConfig & config)649 int SqliteConnection::SetEncrypt(const RdbStoreConfig &config)
650 {
651     if (!config.IsEncrypt()) {
652         return E_OK;
653     }
654     if (config.IsMemoryRdb()) {
655         return E_NOT_SUPPORT;
656     }
657 
658     std::vector<uint8_t> key = config.GetEncryptKey();
659     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
660     auto errCode = SetEncryptKey(key, config);
661     key.assign(key.size(), 0);
662     if (errCode != E_OK) {
663         Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_SET_ENCRYPT_FAIL, config, "LOG:SetEncryptKey errcode=" +
664             std::to_string(errCode) + ",iter=" + std::to_string(config.GetIter()), true));
665         if (!newKey.empty()) {
666             LOG_INFO("use new key, iter=%{public}d err=%{public}d errno=%{public}d name=%{public}s", config.GetIter(),
667                 errCode, errno, SqliteUtils::Anonymous(config.GetName()).c_str());
668             errCode = SetEncryptKey(newKey, config);
669             if (errCode != E_OK) {
670                 Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_SET_NEW_ENCRYPT_FAIL, config,
671                     "LOG:new key SetEncryptKey errcode= "+ std::to_string(errCode) +
672                     ",iter=" + std::to_string(config.GetIter()), true));
673             }
674         }
675         newKey.assign(newKey.size(), 0);
676         if (errCode != E_OK) {
677             errCode = SetServiceKey(config, errCode);
678             LOG_ERROR("fail, iter=%{public}d err=%{public}d errno=%{public}d name=%{public}s", config.GetIter(),
679                 errCode, errno, SqliteUtils::Anonymous(config.GetName()).c_str());
680             if (errCode != E_OK) {
681                 bool sameKey = (key == config.GetEncryptKey()) || (newKey == config.GetEncryptKey());
682                 Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_SET_SERVICE_ENCRYPT_FAIL, config,
683                     "LOG:service key SetEncryptKey errcode=" + std::to_string(errCode) +
684                     ",iter=" + std::to_string(config.GetIter()) + ",samekey=" + std::to_string(sameKey), true));
685             }
686             return errCode;
687         }
688         config.ChangeEncryptKey();
689         newKey = {};
690     }
691 
692     if (!newKey.empty()) {
693         ReSetKey(config);
694     }
695     newKey.assign(newKey.size(), 0);
696     return E_OK;
697 }
698 
SetEncryptKey(const std::vector<uint8_t> & key,const RdbStoreConfig & config)699 int SqliteConnection::SetEncryptKey(const std::vector<uint8_t> &key, const RdbStoreConfig &config)
700 {
701     if (key.empty()) {
702         return E_INVALID_SECRET_KEY;
703     }
704 
705     auto errCode = sqlite3_key(dbHandle_, static_cast<const void *>(key.data()), static_cast<int>(key.size()));
706     if (errCode != SQLITE_OK) {
707         return SQLiteError::ErrNo(errCode);
708     }
709 
710     errCode = SetEncryptAgo(config);
711     if (errCode != E_OK) {
712         return errCode;
713     }
714 
715     if (IsWriter()) {
716         ValueObject version;
717         std::tie(errCode, version) = ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
718         if (errCode != E_OK || version.GetType() == ValueObject::TYPE_NULL) {
719             return errCode;
720         }
721         return E_OK;
722     }
723     return errCode;
724 }
725 
SetPersistWal(const RdbStoreConfig & config)726 int SqliteConnection::SetPersistWal(const RdbStoreConfig &config)
727 {
728     if (config.IsMemoryRdb()) {
729         return E_OK;
730     }
731     int opcode = 1;
732     int errCode = sqlite3_file_control(dbHandle_, "main", SQLITE_FCNTL_PERSIST_WAL, &opcode);
733     if (errCode != SQLITE_OK) {
734         LOG_ERROR("failed.");
735         return E_SET_PERSIST_WAL;
736     }
737     return E_OK;
738 }
739 
SetBusyTimeout(int timeout)740 int SqliteConnection::SetBusyTimeout(int timeout)
741 {
742     auto errCode = sqlite3_busy_timeout(dbHandle_, timeout);
743     if (errCode != SQLITE_OK) {
744         LOG_ERROR("set buys timeout failed, errCode=%{public}d, errno=%{public}d", errCode, errno);
745         return errCode;
746     }
747     return E_OK;
748 }
749 
RegDefaultFunctions(sqlite3 * dbHandle)750 int SqliteConnection::RegDefaultFunctions(sqlite3 *dbHandle)
751 {
752     if (dbHandle == nullptr) {
753         return SQLITE_OK;
754     }
755 
756     auto [funcs, funcCount] = SqliteFunctionRegistry::GetFunctions();
757 
758     for (size_t i = 0; i < funcCount; i++) {
759         const SqliteFunction& func = funcs[i];
760         int errCode = sqlite3_create_function_v2(dbHandle, func.name, func.numArgs,
761             SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, func.function, nullptr, nullptr, nullptr);
762         if (errCode != SQLITE_OK) {
763             LOG_ERROR("register function %{public}s failed, errCode=0x%{public}x, errno=%{public}d", func.name,
764                 errCode, errno);
765             return SQLiteError::ErrNo(errCode);
766         }
767     }
768     return E_OK;
769 }
770 
SetJournalMode(const RdbStoreConfig & config)771 int SqliteConnection::SetJournalMode(const RdbStoreConfig &config)
772 {
773     if (isReadOnly_ || config.IsMemoryRdb()) {
774         return E_OK;
775     }
776 
777     auto [errCode, object] = ExecuteForValue("PRAGMA journal_mode");
778     if (errCode != E_OK) {
779         LOG_ERROR("SetJournalMode fail to get journal mode : %{public}d, errno %{public}d", errCode, errno);
780         Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_DFX_GET_JOURNAL_FAIL, config_.GetBundleName(),
781             "PRAGMA journal_mode get fail: " +  std::to_string(errCode) + "," + std::to_string(errno)));
782         // errno: 28 No space left on device
783         return (errCode == E_SQLITE_IOERR && sqlite3_system_errno(dbHandle_) == 28) ? E_SQLITE_IOERR_FULL : errCode;
784     }
785 
786     if (config.GetJournalMode().compare(static_cast<std::string>(object)) == 0) {
787         return E_OK;
788     }
789 
790     std::string currentMode = SqliteUtils::StrToUpper(static_cast<std::string>(object));
791     if (currentMode != config.GetJournalMode()) {
792         auto [errorCode, journalMode] = ExecuteForValue("PRAGMA journal_mode=" + config.GetJournalMode());
793         if (errorCode != E_OK) {
794             LOG_ERROR("SqliteConnection SetJournalMode: fail to set journal mode err=%{public}d", errorCode);
795             Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_DFX_SET_JOURNAL_FAIL, config_.GetBundleName(),
796                 "PRAGMA journal_mode set fail: " +  std::to_string(errCode) + "," + std::to_string(errno) + "," +
797                 config.GetJournalMode()));
798             return errorCode;
799         }
800 
801         if (SqliteUtils::StrToUpper(static_cast<std::string>(journalMode)) != config.GetJournalMode()) {
802             LOG_ERROR("SqliteConnection SetJournalMode: result incorrect.");
803             return E_EXECUTE_RESULT_INCORRECT;
804         }
805     }
806 
807     if (config.GetJournalMode() == "WAL") {
808         errCode = SetWalSyncMode(config.GetSyncMode());
809     }
810     if (config.GetJournalMode() == "TRUNCATE") {
811         mode_ = JournalMode::MODE_TRUNCATE;
812     }
813     return errCode;
814 }
815 
SetAutoCheckpoint(const RdbStoreConfig & config)816 int SqliteConnection::SetAutoCheckpoint(const RdbStoreConfig &config)
817 {
818     if (isReadOnly_ || config.IsMemoryRdb()) {
819         return E_OK;
820     }
821 
822     int targetValue = SqliteGlobalConfig::GetWalAutoCheckpoint();
823     auto [errCode, value] = ExecuteForValue("PRAGMA wal_autocheckpoint");
824     if (errCode != E_OK) {
825         LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to get wal_autocheckpoint : %{public}d", errCode);
826         return errCode;
827     }
828 
829     if (static_cast<int64_t>(value) == targetValue) {
830         return E_OK;
831     }
832 
833     std::tie(errCode, value) = ExecuteForValue("PRAGMA wal_autocheckpoint=" + std::to_string(targetValue));
834     if (errCode != E_OK) {
835         LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to set wal_autocheckpoint : %{public}d", errCode);
836     }
837     return errCode;
838 }
839 
SetTokenizer(const RdbStoreConfig & config)840 int SqliteConnection::SetTokenizer(const RdbStoreConfig &config)
841 {
842     auto tokenizer = config.GetTokenizer();
843     if (tokenizer == NONE_TOKENIZER || tokenizer == CUSTOM_TOKENIZER) {
844         return E_OK;
845     }
846     if (tokenizer == ICU_TOKENIZER) {
847         sqlite3_config(SQLITE_CONFIG_ENABLE_ICU, 1);
848         return E_OK;
849     }
850     LOG_ERROR("fail to set Tokenizer: %{public}d", tokenizer);
851     return E_INVALID_ARGS;
852 }
853 
SetWalFile(const RdbStoreConfig & config)854 int SqliteConnection::SetWalFile(const RdbStoreConfig &config)
855 {
856     if (!IsWriter()) {
857         return E_OK;
858     }
859     auto [errCode, version] = ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
860     if (errCode != E_OK) {
861         return errCode;
862     }
863     return ExecuteSql(std::string(GlobalExpr::PRAGMA_VERSION) + "=?", { std::move(version) });
864 }
865 
SetWalSyncMode(const std::string & syncMode)866 int SqliteConnection::SetWalSyncMode(const std::string &syncMode)
867 {
868     std::string targetValue = SqliteGlobalConfig::GetSyncMode();
869     if (syncMode.length() != 0) {
870         targetValue = syncMode;
871     }
872 
873     auto [errCode, object] = ExecuteForValue("PRAGMA synchronous");
874     if (errCode != E_OK) {
875         LOG_ERROR("get wal sync mode fail, errCode:%{public}d", errCode);
876         return errCode;
877     }
878 
879     std::string walSyncMode = SqliteUtils::StrToUpper(static_cast<std::string>(object));
880     if (walSyncMode == targetValue) {
881         return E_OK;
882     }
883 
884     errCode = ExecuteSql("PRAGMA synchronous=" + targetValue);
885     if (errCode != E_OK) {
886         LOG_ERROR("set wal sync mode fail, errCode:%{public}d", errCode);
887     }
888     return errCode;
889 }
890 
ExecuteSql(const std::string & sql,const std::vector<ValueObject> & bindArgs)891 int SqliteConnection::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
892 {
893     auto [errCode, statement] = CreateStatement(sql, nullptr);
894     if (statement == nullptr || errCode != E_OK) {
895         return errCode;
896     }
897     return statement->Execute(bindArgs);
898 }
899 
ExecuteForValue(const std::string & sql,const std::vector<ValueObject> & bindArgs)900 std::pair<int32_t, ValueObject> SqliteConnection::ExecuteForValue(
901     const std::string &sql, const std::vector<ValueObject> &bindArgs)
902 {
903     auto [errCode, statement] = CreateStatement(sql, nullptr);
904     if (statement == nullptr || errCode != E_OK) {
905         return { static_cast<int32_t>(errCode), ValueObject() };
906     }
907 
908     ValueObject object;
909     std::tie(errCode, object) = statement->ExecuteForValue(bindArgs);
910     if (errCode != E_OK) {
911         LOG_ERROR("execute sql failed, errCode:%{public}d, app self can check the SQL, args size:%{public}zu",
912             SQLiteError::ErrNo(errCode), bindArgs.size());
913     }
914     return { errCode, object };
915 }
916 
ClearCache()917 int SqliteConnection::ClearCache()
918 {
919     if (dbHandle_ != nullptr && mode_ == JournalMode::MODE_WAL) {
920         int usedBytes = 0;
921         int nEnyry = 0;
922         int errCode = sqlite3_db_status(dbHandle_, SQLITE_DBSTATUS_CACHE_USED, &usedBytes, &nEnyry, 0);
923         if (errCode == SQLITE_OK && usedBytes > config_.GetClearMemorySize()) {
924             sqlite3_db_release_memory(dbHandle_);
925         }
926     }
927     if (slaveConnection_) {
928         int errCode = slaveConnection_->ClearCache();
929         if (errCode != E_OK) {
930             LOG_ERROR("slaveConnection clearCache failed:%{public}d", errCode);
931         }
932     }
933     return E_OK;
934 }
935 
LimitPermission(const RdbStoreConfig & config,const std::string & dbPath) const936 void SqliteConnection::LimitPermission(const RdbStoreConfig &config, const std::string &dbPath) const
937 {
938     if (config.IsMemoryRdb()) {
939         return;
940     }
941     struct stat st = { 0 };
942     if (stat(dbPath.c_str(), &st) == 0) {
943         if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) {
944             int ret = chmod(dbPath.c_str(), st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
945             if (ret != 0) {
946                 LOG_DEBUG("SqliteConnection LimitPermission chmod fail, err = %{public}d", errno);
947             }
948         }
949     } else {
950         LOG_ERROR("SqliteConnection LimitPermission stat fail, err = %{public}d", errno);
951     }
952 }
953 
ConfigLocale(const std::string & localeStr)954 int SqliteConnection::ConfigLocale(const std::string &localeStr)
955 {
956     static void *handle = dlopen("librelational_store_icu.z.so", RTLD_LAZY);
957     if (handle == nullptr) {
958         LOG_ERROR("dlopen(librelational_store_icu) failed(%{public}d)!", errno);
959         return E_NOT_SUPPORT;
960     }
961     auto func = reinterpret_cast<int32_t (*)(sqlite3 *, const std::string &str)>(dlsym(handle, "ConfigICULocal"));
962     if (func == nullptr) {
963         LOG_ERROR("dlsym(librelational_store_icu) failed(%{public}d)!", errno);
964         return E_ERROR;
965     }
966     func(dbHandle_, localeStr);
967     return E_OK;
968 }
969 
CleanDirtyData(const std::string & table,uint64_t cursor)970 int SqliteConnection::CleanDirtyData(const std::string &table, uint64_t cursor)
971 {
972     if (table.empty()) {
973         LOG_ERROR("table is empty");
974         return E_INVALID_ARGS;
975     }
976     uint64_t tmpCursor = cursor == UINT64_MAX ? 0 : cursor;
977     auto status = DropLogicDeletedData(dbHandle_, table, tmpCursor);
978     LOG_INFO("status:%{public}d, table:%{public}s, cursor:%{public}" PRIu64 "", status,
979         SqliteUtils::Anonymous(table).c_str(), cursor);
980     return status == DistributedDB::DBStatus::OK ? E_OK : E_ERROR;
981 }
982 
TryCheckPoint(bool timeout)983 int SqliteConnection::TryCheckPoint(bool timeout)
984 {
985     if (!isWriter_ || config_.IsMemoryRdb()) {
986         return E_NOT_SUPPORT;
987     }
988 
989     std::shared_ptr<Connection> autoCheck(slaveConnection_.get(), [this, timeout](Connection *conn) {
990         if (conn != nullptr && backupId_ == TaskExecutor::INVALID_TASK_ID) {
991             conn->TryCheckPoint(timeout);
992         }
993     });
994     std::string walName = sqlite3_filename_wal(sqlite3_db_filename(dbHandle_, "main"));
995     ssize_t size = SqliteUtils::GetFileSize(walName);
996     if (size < 0) {
997         LOG_ERROR("Invalid size for WAL:%{public}s size:%{public}zd", SqliteUtils::Anonymous(walName).c_str(), size);
998         return E_ERROR;
999     }
1000 
1001     if (size <= config_.GetStartCheckpointSize()) {
1002         return E_OK;
1003     }
1004 
1005     if (!timeout && size < config_.GetCheckpointSize()) {
1006         return E_INNER_WARNING;
1007     }
1008 
1009     (void)sqlite3_busy_timeout(dbHandle_, CHECKPOINT_TIME);
1010     int errCode = sqlite3_wal_checkpoint_v2(dbHandle_, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr);
1011     (void)sqlite3_busy_timeout(dbHandle_, DEFAULT_BUSY_TIMEOUT_MS);
1012     if (errCode != SQLITE_OK) {
1013         Reportor::ReportFault(RdbFaultDbFileEvent(FT_CP, E_CHECK_POINT_FAIL, config_,
1014             "LOG:cp fail, errcode=" + std::to_string(errCode), true));
1015         LOG_WARN("sqlite3_wal_checkpoint_v2 failed err:%{public}d,size:%{public}zd,wal:%{public}s.", errCode, size,
1016             SqliteUtils::Anonymous(walName).c_str());
1017         return SQLiteError::ErrNo(errCode);
1018     }
1019     return E_OK;
1020 }
1021 
LimitWalSize()1022 int SqliteConnection::LimitWalSize()
1023 {
1024     if (!isConfigured_ || !isWriter_ || config_.IsMemoryRdb()) {
1025         return E_OK;
1026     }
1027 
1028     std::string walName = sqlite3_filename_wal(sqlite3_db_filename(dbHandle_, "main"));
1029     ssize_t fileSize = SqliteUtils::GetFileSize(walName);
1030     if (fileSize < 0 || fileSize > config_.GetWalLimitSize()) {
1031         std::stringstream ss;
1032         ss << "The WAL file size exceeds the limit,name=" << SqliteUtils::Anonymous(walName).c_str()
1033             << ",file size=" << fileSize
1034             << ",limit size=" << config_.GetWalLimitSize();
1035         LOG_ERROR("%{public}s", ss.str().c_str());
1036         Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_WAL_SIZE_OVER_LIMIT, config_, ss.str()));
1037         return E_WAL_SIZE_OVER_LIMIT;
1038     }
1039     return E_OK;
1040 }
1041 
Subscribe(const std::shared_ptr<DistributedDB::StoreObserver> & observer)1042 int32_t SqliteConnection::Subscribe(const std::shared_ptr<DistributedDB::StoreObserver> &observer)
1043 {
1044     if (!isWriter_ || observer == nullptr) {
1045         return E_OK;
1046     }
1047     int32_t errCode = RegisterStoreObserver(dbHandle_, observer);
1048     if (errCode != E_OK) {
1049         return errCode;
1050     }
1051     RegisterDbHook(dbHandle_);
1052     config_.SetRegisterInfo(RegisterType::STORE_OBSERVER, true);
1053     return E_OK;
1054 }
1055 
Unsubscribe(const std::shared_ptr<DistributedDB::StoreObserver> & observer)1056 int32_t SqliteConnection::Unsubscribe(const std::shared_ptr<DistributedDB::StoreObserver> &observer)
1057 {
1058     if (!isWriter_ || observer == nullptr) {
1059         return E_OK;
1060     }
1061     int32_t errCode = UnregisterStoreObserver(dbHandle_, observer);
1062     if (errCode != 0) {
1063         return errCode;
1064     }
1065     return E_OK;
1066 }
1067 
Backup(const std::string & databasePath,const std::vector<uint8_t> & destEncryptKey,bool isAsync,SlaveStatus & slaveStatus)1068 int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
1069     bool isAsync, SlaveStatus &slaveStatus)
1070 {
1071     if (slaveStatus == SlaveStatus::BACKING_UP) {
1072         LOG_INFO("backing up, return:%{public}s", config_.GetName().c_str());
1073         return E_OK;
1074     }
1075     LOG_INFO(
1076         "begin backup to slave:%{public}s, isAsync:%{public}d", SqliteUtils::Anonymous(databasePath).c_str(), isAsync);
1077     if (!isAsync) {
1078         if (slaveConnection_ == nullptr) {
1079             RdbStoreConfig rdbSlaveStoreConfig = GetSlaveRdbStoreConfig(config_);
1080             auto [errCode, conn] = CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::FORCE_OPEN);
1081             if (errCode != E_OK) {
1082                 return errCode;
1083             }
1084             slaveConnection_ = conn;
1085         }
1086         return ExchangeSlaverToMaster(false, true, slaveStatus);
1087     }
1088 
1089     if (backupId_ == TaskExecutor::INVALID_TASK_ID) {
1090         auto pool = TaskExecutor::GetInstance().GetExecutor();
1091         if (pool == nullptr) {
1092             LOG_WARN("task pool err when restore");
1093             return E_OK;
1094         }
1095         backupId_ = pool->Execute([this, &slaveStatus]() {
1096             auto [err, conn] = InnerCreate(config_, true);
1097             if (err != E_OK) {
1098                 return;
1099             }
1100             err = conn->ExchangeSlaverToMaster(false, true, slaveStatus);
1101             if (err != E_OK) {
1102                 LOG_WARN("master backup to slave failed:%{public}d", err);
1103             }
1104             backupId_ = TaskExecutor::INVALID_TASK_ID;
1105         });
1106     }
1107     return E_OK;
1108 }
1109 
Restore(const std::string & databasePath,const std::vector<uint8_t> & destEncryptKey,SlaveStatus & slaveStatus)1110 int32_t SqliteConnection::Restore(
1111     const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey, SlaveStatus &slaveStatus)
1112 {
1113     return ExchangeSlaverToMaster(true, true, slaveStatus);
1114 };
1115 
LoadExtension(const RdbStoreConfig & config,sqlite3 * dbHandle)1116 int SqliteConnection::LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle)
1117 {
1118     auto pluginLibs = config.GetPluginLibs();
1119     if (config.GetTokenizer() == CUSTOM_TOKENIZER) {
1120         pluginLibs.push_back("libcustomtokenizer.z.so");
1121     }
1122     if (pluginLibs.empty() || dbHandle == nullptr) {
1123         return E_OK;
1124     }
1125     if (pluginLibs.size() >
1126         SqliteUtils::MAX_LOAD_EXTENSION_COUNT + (config.GetTokenizer() == CUSTOM_TOKENIZER ? 1 : 0)) {
1127         LOG_ERROR("failed, size %{public}zu is too large", pluginLibs.size());
1128         return E_INVALID_ARGS;
1129     }
1130     int err = sqlite3_db_config(
1131         dbHandle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SqliteUtils::ENABLE_LOAD_EXTENSION, nullptr);
1132     if (err != SQLITE_OK) {
1133         LOG_ERROR("enable failed, err=%{public}d, errno=%{public}d", err, errno);
1134         return SQLiteError::ErrNo(err);
1135     }
1136     for (auto &path : pluginLibs) {
1137         if (path.empty()) {
1138             continue;
1139         }
1140         err = sqlite3_load_extension(dbHandle, path.c_str(), nullptr, nullptr);
1141         if (err != SQLITE_OK) {
1142             LOG_ERROR("load error. err=%{public}d, errno=%{public}d, errmsg:%{public}s, lib=%{public}s", err, errno,
1143                 sqlite3_errmsg(dbHandle), SqliteUtils::Anonymous(path).c_str());
1144             if (access(path.c_str(), F_OK) != 0) {
1145                 return E_INVALID_FILE_PATH;
1146             }
1147             break;
1148         }
1149     }
1150     int ret = sqlite3_db_config(
1151         dbHandle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SqliteUtils::DISABLE_LOAD_EXTENSION, nullptr);
1152     if (ret != SQLITE_OK) {
1153         LOG_ERROR("disable failed, err=%{public}d, errno=%{public}d", err, errno);
1154     }
1155     return SQLiteError::ErrNo(err == SQLITE_OK ? ret : err);
1156 }
1157 
SetServiceKey(const RdbStoreConfig & config,int32_t errCode)1158 int SqliteConnection::SetServiceKey(const RdbStoreConfig &config, int32_t errCode)
1159 {
1160     DistributedRdb::RdbSyncerParam param;
1161     param.bundleName_ = config.GetBundleName();
1162     param.hapName_ = config.GetModuleName();
1163     param.storeName_ = config.GetName();
1164     param.customDir_ = config.GetCustomDir();
1165     param.area_ = config.GetArea();
1166     param.level_ = static_cast<int32_t>(config.GetSecurityLevel());
1167     param.type_ = config.GetDistributedType();
1168     param.isEncrypt_ = config.IsEncrypt();
1169     param.isAutoClean_ = config.GetAutoClean();
1170     param.isSearchable_ = config.IsSearchable();
1171     param.haMode_ = config.GetHaMode();
1172     param.password_ = {};
1173     param.subUser_ = config.GetSubUser();
1174     std::vector<std::vector<uint8_t>> keys;
1175 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
1176     auto [svcErr, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
1177     if (svcErr != E_OK) {
1178         return errCode;
1179     }
1180     svcErr = service->GetPassword(param, keys);
1181     if (svcErr != RDB_OK) {
1182         return errCode;
1183     }
1184 #endif
1185 
1186     for (const auto &key : keys) {
1187         errCode = SetEncryptKey(key, config);
1188         if (errCode == E_OK) {
1189             config.RestoreEncryptKey(key);
1190             break;
1191         }
1192     }
1193     for (auto &key : keys) {
1194         key.assign(key.size(), 0);
1195     }
1196     return errCode;
1197 }
1198 
ExchangeSlaverToMaster(bool isRestore,bool verifyDb,SlaveStatus & curStatus)1199 int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, bool verifyDb, SlaveStatus &curStatus)
1200 {
1201     curStatus = SlaveStatus::BACKING_UP;
1202     int err = verifyDb ? ExchangeVerify(isRestore) : E_OK;
1203     if (err != E_OK) {
1204         curStatus = SlaveStatus::UNDEFINED;
1205         return err;
1206     }
1207     return SqliteNativeBackup(isRestore, curStatus);
1208 }
1209 
SqliteNativeBackup(bool isRestore,SlaveStatus & curStatus)1210 int SqliteConnection::SqliteNativeBackup(bool isRestore, SlaveStatus &curStatus)
1211 {
1212     sqlite3 *dbFrom = isRestore ? dbHandle_ : slaveConnection_->dbHandle_;
1213     sqlite3 *dbTo = isRestore ? slaveConnection_->dbHandle_ : dbHandle_;
1214     sqlite3_backup *pBackup = sqlite3_backup_init(dbFrom, "main", dbTo, "main");
1215     if (pBackup == nullptr) {
1216         LOG_WARN("slave backup init failed");
1217         curStatus = SlaveStatus::UNDEFINED;
1218         return E_OK;
1219     }
1220     int rc = SQLITE_OK;
1221     do {
1222         if (!isRestore && curStatus == SlaveStatus::BACKUP_INTERRUPT) {
1223             rc = E_CANCEL;
1224             break;
1225         }
1226         rc = sqlite3_backup_step(pBackup, BACKUP_PAGES_PRE_STEP);
1227         LOG_INFO("backup slave process cur/total:%{public}d/%{public}d, rs:%{public}d, isRestore:%{public}d",
1228             sqlite3_backup_pagecount(pBackup) - sqlite3_backup_remaining(pBackup), sqlite3_backup_pagecount(pBackup),
1229             rc, isRestore);
1230         if (!isRestore) {
1231             sqlite3_sleep(BACKUP_PRE_WAIT_TIME);
1232         }
1233     } while (sqlite3_backup_pagecount(pBackup) != 0 && (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED));
1234     (void)sqlite3_backup_finish(pBackup);
1235     if (rc != SQLITE_DONE) {
1236         LOG_ERROR("backup slave err:%{public}d, isRestore:%{public}d", rc, isRestore);
1237         if (!isRestore) {
1238             RdbStoreConfig slaveConfig(slaveConnection_->config_.GetPath());
1239             if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED) {
1240                 slaveConnection_ = nullptr;
1241                 (void)SqliteConnection::Delete(slaveConfig.GetPath());
1242             }
1243             curStatus = SlaveStatus::BACKUP_INTERRUPT;
1244             Reportor::ReportCorrupted(Reportor::Create(slaveConfig, SQLiteError::ErrNo(rc), "ErrorType: slaveBackup"));
1245         }
1246         return rc == E_CANCEL ? E_CANCEL : SQLiteError::ErrNo(rc);
1247     }
1248     rc = isRestore ? TryCheckPoint(true) : slaveConnection_->TryCheckPoint(true);
1249     if (rc != E_OK && config_.GetHaMode() == HAMode::MANUAL_TRIGGER) {
1250         if (!isRestore) {
1251             curStatus = SlaveStatus::BACKUP_INTERRUPT;
1252         }
1253         LOG_WARN("CheckPoint failed err:%{public}d, isRestore:%{public}d", rc, isRestore);
1254         return E_OK;
1255     }
1256     curStatus = SlaveStatus::BACKUP_FINISHED;
1257     SqliteUtils::SetSlaveValid(config_.GetPath());
1258     LOG_INFO("backup slave success, isRestore:%{public}d", isRestore);
1259     return E_OK;
1260 }
1261 
GenerateExchangeStrategy(const SlaveStatus & status)1262 ExchangeStrategy SqliteConnection::GenerateExchangeStrategy(const SlaveStatus &status)
1263 {
1264     if (dbHandle_ == nullptr || slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr ||
1265         config_.GetHaMode() == HAMode::SINGLE || status == SlaveStatus::BACKING_UP) {
1266         return ExchangeStrategy::NOT_HANDLE;
1267     }
1268     static const std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
1269     auto [mRet, mObj] = ExecuteForValue(querySql);
1270     if (mRet == E_SQLITE_CORRUPT) {
1271         LOG_WARN("main abnormal, err:%{public}d", mRet);
1272         return ExchangeStrategy::RESTORE;
1273     }
1274     int64_t mCount = static_cast<int64_t>(mObj);
1275     // trigger mode only does restore, not backup
1276     if (config_.GetHaMode() == HAMode::MANUAL_TRIGGER) {
1277         return mCount == 0 ? ExchangeStrategy::RESTORE : ExchangeStrategy::NOT_HANDLE;
1278     }
1279     auto [sRet, sObj] = slaveConnection_->ExecuteForValue(querySql);
1280     if (sRet == E_SQLITE_CORRUPT) {
1281         LOG_WARN("slave db abnormal, need backup, err:%{public}d", sRet);
1282         return ExchangeStrategy::BACKUP;
1283     }
1284     if (status == SlaveStatus::DB_NOT_EXITS || status == SlaveStatus::BACKUP_INTERRUPT) {
1285         return ExchangeStrategy::BACKUP;
1286     }
1287     int64_t sCount = static_cast<int64_t>(sObj);
1288     if ((mCount == sCount) && !SqliteUtils::IsSlaveInvalid(config_.GetPath())) {
1289         LOG_INFO("equal, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
1290         return ExchangeStrategy::NOT_HANDLE;
1291     }
1292     if (mCount == 0) {
1293         LOG_INFO("main empty, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
1294         return ExchangeStrategy::RESTORE;
1295     }
1296     LOG_INFO("backup, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
1297     return ExchangeStrategy::BACKUP;
1298 }
1299 
Repair(const RdbStoreConfig & config)1300 int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
1301 {
1302     if (config.GetHaMode() == HAMode::MANUAL_TRIGGER) {
1303         return SqliteConnection::Restore(config, SqliteUtils::GetSlavePath(config.GetPath()), config.GetPath());
1304     }
1305     std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
1306     if (connection == nullptr) {
1307         return E_ERROR;
1308     }
1309     RdbStoreConfig rdbSlaveStoreConfig = connection->GetSlaveRdbStoreConfig(config);
1310     if (access(rdbSlaveStoreConfig.GetPath().c_str(), F_OK) != 0) {
1311         return E_NOT_SUPPORT;
1312     }
1313     auto [ret, conn] = connection->CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::FORCE_OPEN);
1314     if (ret != E_OK) {
1315         return ret;
1316     }
1317     connection->slaveConnection_ = conn;
1318     ret = connection->VeritySlaveIntegrity();
1319     if (ret != E_OK) {
1320         return ret;
1321     }
1322     (void)SqliteConnection::Delete(config.GetPath());
1323     ret = connection->InnerOpen(config);
1324     if (ret != E_OK) {
1325         LOG_ERROR("reopen db failed, err:%{public}d", ret);
1326         return ret;
1327     }
1328     connection->TryCheckPoint(true);
1329     SlaveStatus curStatus;
1330     ret = connection->ExchangeSlaverToMaster(true, false, curStatus);
1331     if (ret != E_OK) {
1332         LOG_ERROR("repair failed, [%{public}s]->[%{public}s], err:%{public}d", rdbSlaveStoreConfig.GetName().c_str(),
1333             SqliteUtils::Anonymous(config.GetName()).c_str(), ret);
1334     } else {
1335         LOG_INFO("repair main success:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
1336     }
1337     return ret;
1338 }
1339 
ExchangeVerify(bool isRestore)1340 int SqliteConnection::ExchangeVerify(bool isRestore)
1341 {
1342     if (isRestore) {
1343         int err = VeritySlaveIntegrity();
1344         if (err != E_OK) {
1345             return err;
1346         }
1347         if (IsDbVersionBelowSlave()) {
1348             return E_OK;
1349         }
1350         if (SqliteUtils::IsSlaveInvalid(config_.GetPath())) {
1351             LOG_ERROR("incomplete slave, %{public}s", config_.GetName().c_str());
1352             return E_SQLITE_CORRUPT;
1353         }
1354         return E_OK;
1355     }
1356     if (slaveConnection_ == nullptr) {
1357         return E_ALREADY_CLOSED;
1358     }
1359     if (access(config_.GetPath().c_str(), F_OK) != 0) {
1360         LOG_WARN("main no exist, isR:%{public}d, %{public}s", isRestore, config_.GetName().c_str());
1361         return E_DB_NOT_EXIST;
1362     }
1363     auto [cRet, cObj] = ExecuteForValue(INTEGRITIES[1]); // 1 is quick_check
1364     if (cRet == E_OK && (static_cast<std::string>(cObj) != "ok")) {
1365         LOG_ERROR("main corrupt, cancel, %{public}s, ret:%{public}s, qRet:%{public}d",
1366             SqliteUtils::Anonymous(config_.GetName()).c_str(), static_cast<std::string>(cObj).c_str(), cRet);
1367         return E_SQLITE_CORRUPT;
1368     }
1369     SqliteUtils::SetSlaveInterrupted(config_.GetPath());
1370     return E_OK;
1371 }
1372 
InnerCreate(const RdbStoreConfig & config,bool isWrite)1373 std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::InnerCreate(
1374     const RdbStoreConfig &config, bool isWrite)
1375 {
1376     std::pair<int32_t, std::shared_ptr<SqliteConnection>> result = { E_ERROR, nullptr };
1377     auto &[errCode, conn] = result;
1378     std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, isWrite);
1379     if (connection == nullptr) {
1380         LOG_ERROR("connection is nullptr.");
1381         return result;
1382     }
1383 
1384     errCode = connection->InnerOpen(config);
1385     if (errCode != E_OK) {
1386         return result;
1387     }
1388     conn = connection;
1389     if (isWrite && config.GetHaMode() != HAMode::SINGLE) {
1390         RdbStoreConfig slaveCfg = connection->GetSlaveRdbStoreConfig(config);
1391         auto [err, slaveConn] = connection->CreateSlaveConnection(slaveCfg, SlaveOpenPolicy::OPEN_IF_DB_VALID);
1392         if (err == E_OK) {
1393             conn->slaveConnection_ = slaveConn;
1394         }
1395     }
1396     return result;
1397 }
1398 
VeritySlaveIntegrity()1399 int SqliteConnection::VeritySlaveIntegrity()
1400 {
1401     if (slaveConnection_ == nullptr) {
1402         return E_ALREADY_CLOSED;
1403     }
1404 
1405     RdbStoreConfig slaveCfg = GetSlaveRdbStoreConfig(config_);
1406     std::map<std::string, DebugInfo> bugInfo = Connection::Collect(slaveCfg);
1407     LOG_INFO("%{public}s", SqliteUtils::FormatDebugInfoBrief(bugInfo,
1408         SqliteUtils::Anonymous(slaveCfg.GetName())).c_str());
1409 
1410     if (SqliteUtils::IsSlaveInterrupted(config_.GetPath())) {
1411         return E_SQLITE_CORRUPT;
1412     }
1413 
1414     std::string sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
1415     auto [err, obj] = slaveConnection_->ExecuteForValue(sql);
1416     auto val = std::get_if<int64_t>(&obj.value);
1417     if (err == E_SQLITE_CORRUPT || (val != nullptr && static_cast<int64_t>(*val) == 0L)) {
1418         LOG_ERROR("slave %{public}d", err);
1419         return E_SQLITE_CORRUPT;
1420     }
1421 
1422     int64_t mCount = 0L;
1423     if (dbHandle_ != nullptr) {
1424         std::tie(err, obj) = ExecuteForValue(sql);
1425         val = std::get_if<int64_t>(&obj.value);
1426         if (val != nullptr) {
1427             mCount = static_cast<int64_t>(*val);
1428         }
1429     }
1430     bool isSlaveDbOverLimit = bugInfo.find(FILE_SUFFIXES[DB_INDEX].debug_) != bugInfo.end() &&
1431                               bugInfo[FILE_SUFFIXES[DB_INDEX].debug_].size_ > SLAVE_INTEGRITY_CHECK_LIMIT;
1432     if (isSlaveDbOverLimit && mCount == 0L) {
1433         return SqliteUtils::IsSlaveInvalid(config_.GetPath()) ? E_SQLITE_CORRUPT : E_OK;
1434     }
1435 
1436     std::tie(err, obj) = slaveConnection_->ExecuteForValue(INTEGRITIES[2]); // 2 is integrity_check
1437     if (err == E_OK && (static_cast<std::string>(obj) != "ok")) {
1438         LOG_ERROR("slave corrupt, ret:%{public}s, cRet:%{public}d, %{public}d", static_cast<std::string>(obj).c_str(),
1439             err, errno);
1440         SqliteUtils::SetSlaveInvalid(config_.GetPath());
1441         return E_SQLITE_CORRUPT;
1442     }
1443     return E_OK;
1444 }
1445 
IsDbVersionBelowSlave()1446 bool SqliteConnection::IsDbVersionBelowSlave()
1447 {
1448     if (slaveConnection_ == nullptr) {
1449         return false;
1450     }
1451 
1452     auto [cRet, cObj] = ExecuteForValue("SELECT COUNT(*) FROM sqlite_master WHERE type='table';");
1453     auto cVal = std::get_if<int64_t>(&cObj.value);
1454     if (cRet == E_SQLITE_CORRUPT || (cVal != nullptr && (static_cast<int64_t>(*cVal) == 0L))) {
1455         LOG_INFO("main empty, %{public}d, %{public}s", cRet, config_.GetName().c_str());
1456         return true;
1457     }
1458 
1459     std::tie(cRet, cObj) = ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
1460     if (cVal == nullptr || (cVal != nullptr && static_cast<int64_t>(*cVal) == 0L)) {
1461         std::tie(cRet, cObj) = slaveConnection_->ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
1462         cVal = std::get_if<int64_t>(&cObj.value);
1463         if (cVal != nullptr && static_cast<int64_t>(*cVal) > 0L) {
1464             LOG_INFO("version, %{public}" PRId64, static_cast<int64_t>(*cVal));
1465             return true;
1466         }
1467     }
1468     return false;
1469 }
1470 
CopyDb(const RdbStoreConfig & config,const std::string & srcPath,const std::string & destPath)1471 int SqliteConnection::CopyDb(const RdbStoreConfig &config, const std::string &srcPath, const std::string &destPath)
1472 {
1473     RdbStoreConfig srcConfig(config);
1474     srcConfig.SetPath(srcPath);
1475     srcConfig.SetIntegrityCheck(IntegrityCheck::FULL);
1476     srcConfig.SetHaMode(HAMode::SINGLE);
1477     auto [ret, conn] = Connection::Create(srcConfig, true);
1478     if (ret == E_SQLITE_CORRUPT && srcConfig.IsEncrypt() && srcConfig.GetIter() != ITER_V1) {
1479         srcConfig.SetIter(ITER_V1);
1480         std::tie(ret, conn) = Connection::Create(srcConfig, true);
1481     }
1482     if (ret != E_OK) {
1483         LOG_ERROR("backup file is corrupted, %{public}s", SqliteUtils::Anonymous(srcPath).c_str());
1484         return E_SQLITE_CORRUPT;
1485     }
1486     conn = nullptr;
1487 
1488     auto walFile = srcPath + "-wal";
1489     if (SqliteUtils::GetFileSize(walFile) != 0) {
1490         LOG_ERROR("Wal file exist.");
1491         return E_SQLITE_CORRUPT;
1492     }
1493     SqliteUtils::DeleteFile(srcPath + "-shm");
1494     SqliteUtils::DeleteFile(srcPath + "-wal");
1495     Connection::Delete(config);
1496 
1497     if (config.GetPath() != destPath) {
1498         RdbStoreConfig dstConfig(destPath);
1499         Connection::Delete(dstConfig);
1500     }
1501 
1502     if (!SqliteUtils::CopyFile(srcPath, destPath)) {
1503         return E_ERROR;
1504     }
1505     return E_OK;
1506 }
1507 
Restore(const RdbStoreConfig & config,const std::string & srcPath,const std::string & destPath)1508 int32_t SqliteConnection::Restore(const RdbStoreConfig &config, const std::string &srcPath, const std::string &destPath)
1509 {
1510     if (config.GetHaMode() == HAMode::SINGLE || !SqliteUtils::IsSlaveDbName(srcPath)) {
1511         return SqliteConnection::CopyDb(config, srcPath, destPath);
1512     }
1513     std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
1514     if (connection == nullptr) {
1515         return E_ERROR;
1516     }
1517     RdbStoreConfig slaveConfig = connection->GetSlaveRdbStoreConfig(config);
1518     if (access(slaveConfig.GetPath().c_str(), F_OK) != 0) {
1519         return E_NOT_SUPPORT;
1520     }
1521     auto [ret, conn] = connection->CreateSlaveConnection(slaveConfig, SlaveOpenPolicy::FORCE_OPEN);
1522     if (ret != E_OK) {
1523         return ret;
1524     }
1525     connection->slaveConnection_ = conn;
1526 
1527     int openMainRes = connection->InnerOpen(config);
1528     ret = connection->VeritySlaveIntegrity();
1529     if (ret != E_OK) {
1530         return ret;
1531     }
1532     if (openMainRes == E_OK && SqliteUtils::IsSlaveInvalid(config.GetPath()) && !connection->IsDbVersionBelowSlave()) {
1533         return E_SQLITE_CORRUPT;
1534     }
1535 
1536     ret = SQLiteError::ErrNo(sqlite3_wal_checkpoint_v2(connection->slaveConnection_->dbHandle_, nullptr,
1537         SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr));
1538     if (ret != E_OK) {
1539         LOG_ERROR("chk %{public}d %{public}d %{public}s", ret, errno, SqliteUtils::Anonymous(config.GetName()).c_str());
1540         return ret;
1541     }
1542     connection->slaveConnection_ = nullptr;
1543     connection = nullptr;
1544 
1545     if (!SqliteUtils::RenameFile(slaveConfig.GetPath(), config.GetPath())) {
1546         LOG_ERROR("rename %{public}d %{public}s", errno, SqliteUtils::Anonymous(config.GetName()).c_str());
1547         return E_ERROR;
1548     }
1549     for (auto &suffix : FILE_SUFFIXES) {
1550         if (suffix.suffix_ != nullptr && !std::string(suffix.suffix_).empty()) {
1551             SqliteUtils::DeleteFile(config.GetPath() + suffix.suffix_);
1552         }
1553     }
1554     Connection::Delete(slaveConfig.GetPath());
1555     return E_OK;
1556 }
1557 } // namespace NativeRdb
1558 } // namespace OHOS