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