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