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