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